diff options
author | syn <isaqtm@gmail.com> | 2020-01-18 21:13:58 +0300 |
---|---|---|
committer | syn <isaqtm@gmail.com> | 2020-01-18 21:13:58 +0300 |
commit | c5c41582a258996f3637f6cb586e5eaea56c1bd5 (patch) | |
tree | 2bd6d99ce98c48a28ac773cd3ba8a420ed1261ad /src | |
parent | 396db96c2ce92adb34483b8c64bc3008c21604c9 (diff) | |
download | evr-c5c41582a258996f3637f6cb586e5eaea56c1bd5.tar.gz |
Support reporting signalled processes
Diffstat (limited to 'src')
-rw-r--r-- | src/backends/clang.rs | 48 | ||||
-rw-r--r-- | src/backends/mod.rs | 10 | ||||
-rw-r--r-- | src/backends/python.rs | 18 | ||||
-rw-r--r-- | src/conf.rs | 19 |
4 files changed, 71 insertions, 24 deletions
diff --git a/src/backends/clang.rs b/src/backends/clang.rs index a174af6..b732ed5 100644 --- a/src/backends/clang.rs +++ b/src/backends/clang.rs @@ -1,4 +1,5 @@ use serde_derive::{ Serialize, Deserialize }; +use crate::backends::{ Backend, mk_tmp_dir, RunStatus }; use std::path::{ Path, PathBuf }; use std::io::{ Result, Error, ErrorKind }; use std::process::Command; @@ -6,7 +7,6 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use log::trace; -type Result<T> = std::io::Result<T>; #[derive(Debug, Serialize, Deserialize, Default)] pub struct ClangBackend { @@ -75,14 +75,46 @@ impl Backend for ClangBackend { } } - fn run(&self, fname: &Path) -> std::io::Result<()> { + fn run(&self, fname: &Path) -> Result<RunStatus> { let binary_fname = self.build(fname)?; - Command::new(&binary_fname) - .status() - .map(|status| { - trace!("{:#?}", status); - () - }) + let binary_proc = Command::new(&binary_fname).spawn()?; + get_status(binary_proc) } } + +use nix::sys::wait; + +#[cfg(unix)] +fn get_status(proc: std::process::Child) -> Result<RunStatus> { + let id = proc.id() as i32; // for fuck sake, why this emits u32? + + loop { + let status_result = wait::waitpid(Some(nix::unistd::Pid::from_raw(id)), None) + .map_err(|err| Error::new(ErrorKind::Other, err)); + + let status = status_result?; + match status { + wait::WaitStatus::Exited(pid, code) => { + assert_eq!(pid.as_raw(), id); + + if code == 0 { + return Ok(RunStatus::Success); + } else { + return Ok(RunStatus::ErrorCode(code)); + } + }, + wait::WaitStatus::Signaled(pid, sig, coredump) => { + assert_eq!(pid.as_raw(), id); + + return Ok(RunStatus::Signal(sig, coredump)); + } + _ => continue, + } + } +} + +#[cfg(not(unix))] +fn get_status(proc: std::process::Child) -> Result<RunStatus> { + compile_error!("currently only unix supported"); +}
\ No newline at end of file diff --git a/src/backends/mod.rs b/src/backends/mod.rs index b91bde5..25ac164 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -2,6 +2,7 @@ use std::path::{ Path, PathBuf }; use std::env::temp_dir; use lazy_static::lazy_static; use std::io::{ Error, ErrorKind, Result }; +use nix::sys::signal::Signal as NixSignal; pub mod python; pub mod clang; @@ -13,10 +14,17 @@ lazy_static! { static ref EVR_TMP_DIR: PathBuf = temp_dir().join("evr-tmp"); } +pub enum RunStatus { + Success, + ErrorCode(i32), + TimedOut(std::time::Duration), + Signal(NixSignal, bool), +} + pub trait Backend { fn get_template(&self) -> Option<&str>; - fn run(&self, fname: &Path) -> Result<()>; + fn run(&self, fname: &Path) -> Result<RunStatus>; fn try_guess_test_file(&self, fname: &Path) -> Option<PathBuf> { let maybe_test = fname.with_extension("txt"); diff --git a/src/backends/python.rs b/src/backends/python.rs index 39827a7..2398997 100644 --- a/src/backends/python.rs +++ b/src/backends/python.rs @@ -1,10 +1,9 @@ use serde_derive::{ Serialize, Deserialize }; -use crate::backends::Backend; +use crate::backends::{ Backend, RunStatus }; use std::process::{ Command, Stdio }; use std::path::Path; -use std::io::{ Error, ErrorKind }; use std::fs::File; -use log::{ trace, warn, error }; +use log::{ warn, error }; use wait_timeout::ChildExt; #[derive(Debug, Serialize, Deserialize, Default)] @@ -35,7 +34,7 @@ impl Backend for PythonBackend { } } - fn run(&self, fname: &Path) -> std::io::Result<()> { + fn run(&self, fname: &Path) -> std::io::Result<RunStatus> { let stdio = match self.try_guess_test_file(fname) { Some(test_filename) => match File::open(test_filename) { Ok(test_content) => Stdio::from(test_content), @@ -58,19 +57,16 @@ impl Backend for PythonBackend { match child.wait_timeout(timeout) { Ok(maybe_status) => match maybe_status { Some(status) => { - trace!("elapsed: {:#?}", timer.elapsed()); if !status.success() { - return Err(Error::new(ErrorKind::Other, - "process exited with non-zero exit code")); + return Ok(RunStatus::ErrorCode(status.code().unwrap_or(0))); } - Ok(()) + Ok(RunStatus::Success) }, None => { - warn!("timed out: {:#?}", timer.elapsed()); + let elapsed = timer.elapsed().unwrap_or(Default::default()); child.kill()?; child.wait()?; - Err(Error::new(ErrorKind::TimedOut, - "process timed out")) + Ok(RunStatus::TimedOut(elapsed)) } }, Err(err) => { diff --git a/src/conf.rs b/src/conf.rs index e36a932..dec461f 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -7,7 +7,7 @@ use std::io::prelude::*; type Error = std::io::Error; use std::io::ErrorKind; -use crate::backends::{ Backend, PythonBackend, ClangBackend }; +use crate::backends::{ Backend, PythonBackend, ClangBackend, RunStatus }; #[derive(Debug, Serialize, Deserialize, Default)] @@ -43,9 +43,20 @@ impl Conf { } pub fn run(&self, fname: &Path) -> std::io::Result<()> { - self.get_backend(fname) - .and_then(|backend| Some(backend.run(fname))) - .unwrap_or(Err(Error::new(ErrorKind::InvalidData, "Backend not found"))) + match self.get_backend(fname) { + Some(backend) => backend.run(fname).map(|status| { + match status { + RunStatus::Success => {}, + RunStatus::ErrorCode(code) => + { error!("process exited with code: {}", code); }, + RunStatus::TimedOut(duration) => + { error!("process timed out at {:.3}s", duration.as_secs_f32()); } + RunStatus::Signal(sig, coredump) => + { error!("process killed by {} {}", sig, if coredump { "(core dumped)" } else { "" }); } + }; + }), + None => Err(Error::new(ErrorKind::InvalidData, "Backend not found")) + } } pub fn make(&self, fname: &Path) -> std::io::Result<()> { |