diff options
Diffstat (limited to 'src/backends')
-rw-r--r-- | src/backends/clang.rs | 60 | ||||
-rw-r--r-- | src/backends/mod.rs | 19 | ||||
-rw-r--r-- | src/backends/python.rs | 34 | ||||
-rw-r--r-- | src/backends/run_error.rs | 38 |
4 files changed, 68 insertions, 83 deletions
diff --git a/src/backends/clang.rs b/src/backends/clang.rs index dd566c7..0947b49 100644 --- a/src/backends/clang.rs +++ b/src/backends/clang.rs @@ -1,11 +1,12 @@ use serde_derive::{ Serialize, Deserialize }; -use crate::backends::{ Backend, mk_tmp_dir, RunStatus }; +use crate::backends::{ Backend, mk_tmp_dir, RunError }; use std::path::{ Path, PathBuf }; -use std::io::{ Result, Error, ErrorKind }; +use std::io::{ Result as IoResult, Error, ErrorKind }; use std::process::{ Command }; use std::collections::hash_map::DefaultHasher; use std::hash::{ Hash, Hasher }; -use nix::{ sys::wait, unistd::Pid }; +use crate::wait::{ WaitInfo, wait_child }; +use std::time::Duration; #[derive(Debug, Serialize, Deserialize, Default)] @@ -17,6 +18,9 @@ pub struct ClangBackend { #[serde(default = "default_cc")] cc: String, + + #[serde(default = "default_timeout")] + timeout: Duration } @@ -24,8 +28,12 @@ fn default_cc() -> String { "clang++".to_string() } +fn default_timeout() -> Duration { + Duration::from_secs(1) +} + -fn get_binary_by_filename(fname: &Path) -> Result<PathBuf> { +fn get_binary_by_filename(fname: &Path) -> IoResult<PathBuf> { let hashed_fname = { let mut hasher = DefaultHasher::new(); fname.hash(&mut hasher); @@ -37,7 +45,7 @@ fn get_binary_by_filename(fname: &Path) -> Result<PathBuf> { impl ClangBackend { - fn build(&self, fname: &Path) -> Result<PathBuf> { + fn build(&self, fname: &Path) -> IoResult<PathBuf> { let binary_fname = get_binary_by_filename(fname)?; let get_mtime = |file| { std::fs::metadata(file)? @@ -73,48 +81,12 @@ impl Backend for ClangBackend { } } - fn run(&self, fname: &Path) -> Result<RunStatus> { + fn run(&self, fname: &Path) -> Result<WaitInfo, RunError> { let binary_fname = self.build(fname)?; - let binary_proc = Command::new(&binary_fname) + let proc = Command::new(&binary_fname) .spawn()?; - get_status(binary_proc) + Ok(wait_child(proc, self.timeout, std::time::Instant::now())?) } } - - -#[cfg(unix)] -fn get_status(proc: std::process::Child) -> Result<RunStatus> { - let pid = Pid::from_raw(proc.id() as i32); - - loop { - let status_result = wait::waitpid(Some(pid), None) - .map_err(|err| Error::new(ErrorKind::Other, err)); - - let status = status_result?; - - match status { - wait::WaitStatus::Exited(ret_pid, code) => { - assert_eq!(ret_pid, pid); - - if code == 0 { - return Ok(RunStatus::Success); - } else { - return Ok(RunStatus::ErrorCode(code)); - } - }, - wait::WaitStatus::Signaled(ret_pid, sig, coredump) => { - assert_eq!(ret_pid, pid); - - 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 0af1bb1..3bf9fc7 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -1,8 +1,8 @@ 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; +use std::io::{ Error, ErrorKind }; +use crate::wait::{ WaitInfo }; pub mod python; pub mod clang; @@ -10,24 +10,21 @@ pub mod clang; pub use python::PythonBackend; pub use clang::ClangBackend; +pub mod run_error; +pub use run_error::RunError; + + 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<RunStatus>; + fn run(&self, fname: &Path) -> Result<WaitInfo, RunError>; } -fn mk_tmp_dir() -> Result<&'static std::path::PathBuf> { +fn mk_tmp_dir() -> std::io::Result<&'static std::path::PathBuf> { if !EVR_TMP_DIR.exists() { std::fs::create_dir(&*EVR_TMP_DIR)?; } else { diff --git a/src/backends/python.rs b/src/backends/python.rs index 66402b9..e3569b1 100644 --- a/src/backends/python.rs +++ b/src/backends/python.rs @@ -1,9 +1,8 @@ use serde_derive::{ Serialize, Deserialize }; -use crate::backends::{ Backend, RunStatus }; +use crate::backends::{ Backend, RunError }; use std::process::{ Command }; use std::path::Path; -use log::error; -use wait_timeout::ChildExt; +use crate::wait::{ wait_child, WaitInfo }; #[derive(Debug, Serialize, Deserialize, Default)] pub struct PythonBackend { @@ -33,35 +32,14 @@ impl Backend for PythonBackend { } } - fn run(&self, fname: &Path) -> std::io::Result<RunStatus> { - let timer = std::time::SystemTime::now(); + fn run(&self, fname: &Path) -> Result<WaitInfo, RunError> { + let timer = std::time::Instant::now(); - let mut child = Command::new(self.get_interpreter()) + let child = Command::new(self.get_interpreter()) .arg(fname.as_os_str()) .spawn()?; let timeout = std::time::Duration::from_secs_f32(self.timeout.unwrap_or(1.0)); - match child.wait_timeout(timeout) { - Ok(maybe_status) => match maybe_status { - Some(status) => { - if !status.success() { - return Ok(RunStatus::ErrorCode(status.code().unwrap_or(0))); - } - Ok(RunStatus::Success) - }, - None => { - let elapsed = timer.elapsed().unwrap_or(Default::default()); - child.kill()?; - child.wait()?; - Ok(RunStatus::TimedOut(elapsed)) - } - }, - Err(err) => { - error!("could not wait for child: {}", err); - child.kill()?; - child.wait()?; // Wait defunct - Err(err) - } - } + Ok(wait_child(child, timeout, timer)?) } }
\ No newline at end of file diff --git a/src/backends/run_error.rs b/src/backends/run_error.rs new file mode 100644 index 0000000..68f0495 --- /dev/null +++ b/src/backends/run_error.rs @@ -0,0 +1,38 @@ +use crate::wait::WaitError; +use std::io::Error as IoError; + +#[derive(Debug)] +pub enum RunError { + IoError(std::io::Error), + WaitError(WaitError) +} + +impl From<IoError> for RunError { + fn from(err: IoError) -> Self { + RunError::IoError(err) + } +} + +impl From<WaitError> for RunError { + fn from(err: WaitError) -> Self { + RunError::WaitError(err) + } +} + +impl std::fmt::Display for RunError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match &*self { + RunError::IoError(e) => e.fmt(f), + RunError::WaitError(e) => e.fmt(f) + } + } +} + +impl std::error::Error for RunError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + RunError::IoError(ref e) => Some(e), + RunError::WaitError(ref e) => Some(e) + } + } +}
\ No newline at end of file |