diff options
-rw-r--r-- | src/backends/clang.rs | 4 | ||||
-rw-r--r-- | src/backends/mod.rs | 4 | ||||
-rw-r--r-- | src/backends/python.rs | 4 | ||||
-rw-r--r-- | src/conf.rs | 51 | ||||
-rw-r--r-- | src/main.rs | 38 | ||||
-rw-r--r-- | src/wait/error.rs | 26 | ||||
-rw-r--r-- | src/wait/mod.rs | 31 |
7 files changed, 83 insertions, 75 deletions
diff --git a/src/backends/clang.rs b/src/backends/clang.rs index 0947b49..11c316a 100644 --- a/src/backends/clang.rs +++ b/src/backends/clang.rs @@ -5,7 +5,7 @@ use std::io::{ Result as IoResult, Error, ErrorKind }; use std::process::{ Command }; use std::collections::hash_map::DefaultHasher; use std::hash::{ Hash, Hasher }; -use crate::wait::{ WaitInfo, wait_child }; +use crate::wait::{ ChildExitStatus, wait_child }; use std::time::Duration; @@ -81,7 +81,7 @@ impl Backend for ClangBackend { } } - fn run(&self, fname: &Path) -> Result<WaitInfo, RunError> { + fn run(&self, fname: &Path) -> Result<ChildExitStatus, RunError> { let binary_fname = self.build(fname)?; let proc = Command::new(&binary_fname) diff --git a/src/backends/mod.rs b/src/backends/mod.rs index 3bf9fc7..a5d2d28 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -2,7 +2,7 @@ use std::path::{ Path, PathBuf }; use std::env::temp_dir; use lazy_static::lazy_static; use std::io::{ Error, ErrorKind }; -use crate::wait::{ WaitInfo }; +use crate::wait::ChildExitStatus; pub mod python; pub mod clang; @@ -21,7 +21,7 @@ lazy_static! { pub trait Backend { fn get_template(&self) -> Option<&str>; - fn run(&self, fname: &Path) -> Result<WaitInfo, RunError>; + fn run(&self, fname: &Path) -> Result<ChildExitStatus, RunError>; } fn mk_tmp_dir() -> std::io::Result<&'static std::path::PathBuf> { diff --git a/src/backends/python.rs b/src/backends/python.rs index e3569b1..3ee7b35 100644 --- a/src/backends/python.rs +++ b/src/backends/python.rs @@ -2,7 +2,7 @@ use serde_derive::{ Serialize, Deserialize }; use crate::backends::{ Backend, RunError }; use std::process::{ Command }; use std::path::Path; -use crate::wait::{ wait_child, WaitInfo }; +use crate::wait::{ wait_child, ChildExitStatus }; #[derive(Debug, Serialize, Deserialize, Default)] pub struct PythonBackend { @@ -32,7 +32,7 @@ impl Backend for PythonBackend { } } - fn run(&self, fname: &Path) -> Result<WaitInfo, RunError> { + fn run(&self, fname: &Path) -> Result<ChildExitStatus, RunError> { let timer = std::time::Instant::now(); let child = Command::new(self.get_interpreter()) diff --git a/src/conf.rs b/src/conf.rs index febfef5..cc281f0 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -1,14 +1,12 @@ use serde_derive::{ Serialize, Deserialize }; use std::path::{ PathBuf, Path }; use toml::de; -use log::{ error, trace }; -use std::io::prelude::*; -use nix::sys::wait::WaitStatus; +use log::{ error }; type Error = std::io::Error; use std::io::ErrorKind; -use crate::backends::{ Backend, PythonBackend, ClangBackend, RunError }; +use crate::backends::{ Backend, PythonBackend, ClangBackend }; #[derive(Debug, Serialize, Deserialize, Default)] @@ -42,51 +40,6 @@ impl Conf { _ => None } } - - pub fn run( - &self, - fname: &Path, - show_time: bool, - show_mem: bool - ) -> Result<(), RunError> { - match self.get_backend(fname) { - Some(backend) => backend.run(fname).map(|info| { - match info.status { - WaitStatus::Exited(_pid, ret) => match ret { - 0 => { - if show_time { - println!("wall time: {:?}", info.wall_time); - } - if show_mem { - println!("rss: {}K", info.usage.ru_maxrss); - } - }, - _ => error!("process exited with {}", ret) - }, - WaitStatus::Signaled(pid, sig, coredump) => { - error!( - "process killed by {} {}. was {}", - sig, - if coredump {"(core dumped)"} else {""}, - pid - ); - }, - _ => error!("process signaled, but not exited") - } - }), - None => Err(Error::new(ErrorKind::InvalidData, "Backend not found").into()) - } - } - - pub fn make(&self, fname: &Path) -> Result<(), RunError> { - trace!("Template: {:?}", self.get_template(&fname)); - - std::fs::File::create(fname)? - .write_all(self.get_template(fname).as_bytes())?; - - trace!("Written some bytes to {}", fname.to_string_lossy()); - Ok(()) - } } diff --git a/src/main.rs b/src/main.rs index 1621e1b..4eeb298 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ extern crate lazy_static; use clap::{ AppSettings, App, Arg }; use env_logger; use log::{ error }; +use std::io::prelude::*; mod conf; mod backends; @@ -41,19 +42,28 @@ fn main() { .into(); let config = conf::get_conf(); - let result = - if src_path.exists() { - config.run( - &src_path, - matches.is_present("time"), - matches.is_present("mem") - ) + if src_path.exists() { + if let Some(backend) = config.get_backend(&src_path) { + match backend.run(&src_path) { + Ok(status) => { + if matches.is_present("time") { + println!("wall time: {:?}", status.wall_time); + } + if matches.is_present("mem") { + println!("rss: {}K", status.usage.ru_maxrss); + } + }, + Err(err) => error!("{}", err) + }; } else { - config.make(&src_path) - }; - - match result { - Ok(_) => {}, - Err(err) => error!("{}", err) - } + error!("could not match backend"); + } + } else { + let template = config.get_template(&src_path).as_bytes(); + if let Err(err) = + std::fs::File::create(&src_path) + .and_then(|mut file| file.write_all(template)) { + error!("{}", err); + } + }; } diff --git a/src/wait/error.rs b/src/wait/error.rs index bb95e81..169097d 100644 --- a/src/wait/error.rs +++ b/src/wait/error.rs @@ -2,11 +2,22 @@ use nix; use std::time::Duration; #[derive(Debug)] +pub struct ProcessSignalInfo { + pub pid: nix::unistd::Pid, + pub signal: nix::sys::signal::Signal, + pub coredump: bool +} + +#[derive(Debug)] pub enum WaitError { TimedOut(Duration), - OsError(nix::Error) + ReturnNonZero(i32, nix::unistd::Pid), + Signaled(ProcessSignalInfo), + OsError(nix::Error), + NotExited } + impl From<nix::Error> for WaitError { fn from(err: nix::Error) -> Self { WaitError::OsError(err) @@ -17,7 +28,13 @@ impl std::fmt::Display for WaitError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { WaitError::TimedOut(dur) => write!(f, "process timed out in {:?}", dur), - WaitError::OsError(err) => err.fmt(f) + WaitError::ReturnNonZero(ret, pid) => + write!(f, "process exited with non-zero exit code ({}). was {}", ret, pid), + WaitError::Signaled(ref info) => + write!(f, "process killed by {} {}. was {}", + info.signal, if info.coredump {"(core dumped)"} else {""}, info.pid), + WaitError::OsError(err) => err.fmt(f), + WaitError::NotExited => write!(f, "process signaled, but not exited") } } } @@ -25,7 +42,10 @@ impl std::fmt::Display for WaitError { impl std::error::Error for WaitError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match *self { - WaitError::TimedOut(_) => None, + WaitError::TimedOut(_) | + WaitError::ReturnNonZero(_, _) | + WaitError::Signaled(_) | + WaitError::NotExited => None, WaitError::OsError(ref e) => Some(e) } } diff --git a/src/wait/mod.rs b/src/wait/mod.rs index 9761f08..c591bb1 100644 --- a/src/wait/mod.rs +++ b/src/wait/mod.rs @@ -8,20 +8,45 @@ use std::time::{ Instant, Duration }; use std::process::Child; use std::thread; use std::sync::mpsc; +use std::convert::{ TryFrom, TryInto }; mod error; mod rusage_ffi; pub use rusage_ffi::Rusage; pub use error::WaitError; +use error::ProcessSignalInfo; #[derive(Debug)] -pub struct WaitInfo { +struct WaitInfo { pub status: WaitStatus, pub usage: Rusage, pub wall_time: Duration } +#[derive(Debug)] +pub struct ChildExitStatus { + pub usage: Rusage, + pub wall_time: Duration +} + +impl TryFrom<WaitInfo> for ChildExitStatus { + type Error = WaitError; + + fn try_from(info: WaitInfo) -> Result<Self, Self::Error> { + match info.status { + WaitStatus::Exited(pid, ret) => + match ret { + 0 => Ok(ChildExitStatus { usage: info.usage, wall_time: info.wall_time }), + _ => Err(WaitError::ReturnNonZero(ret, pid)) + }, + WaitStatus::Signaled(pid, signal, coredump) => + Err(WaitError::Signaled(ProcessSignalInfo { pid, signal, coredump })), + _ => Err(WaitError::NotExited) + } + } +} + fn wait4_pid( pid: Pid, @@ -57,14 +82,14 @@ pub fn wait_child( mut child: Child, timeout: Duration, timer: Instant -) -> Result<WaitInfo, WaitError> { +) -> Result<ChildExitStatus, WaitError> { let pid = Pid::from_raw(child.id() as i32); let (send, recv) = mpsc::channel(); let thr = thread::spawn(move || wait4_pid(pid, send, timer)); match recv.recv_timeout(timeout) { - Ok(Ok(usg)) => Ok(usg), + Ok(Ok(wait_info)) => wait_info.try_into(), Ok(Err(err)) => Err(err.into()), Err(mpsc::RecvTimeoutError::Timeout) => { drop(recv); |