summaryrefslogtreecommitdiffstats
path: root/src/backends
diff options
context:
space:
mode:
Diffstat (limited to 'src/backends')
-rw-r--r--src/backends/clang.rs60
-rw-r--r--src/backends/mod.rs19
-rw-r--r--src/backends/python.rs34
-rw-r--r--src/backends/run_error.rs38
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