diff options
Diffstat (limited to 'src/wait')
-rw-r--r-- | src/wait/error.rs | 32 | ||||
-rw-r--r-- | src/wait/mod.rs | 81 | ||||
-rw-r--r-- | src/wait/rusage_ffi.rs | 53 |
3 files changed, 166 insertions, 0 deletions
diff --git a/src/wait/error.rs b/src/wait/error.rs new file mode 100644 index 0000000..bb95e81 --- /dev/null +++ b/src/wait/error.rs @@ -0,0 +1,32 @@ +use nix; +use std::time::Duration; + +#[derive(Debug)] +pub enum WaitError { + TimedOut(Duration), + OsError(nix::Error) +} + +impl From<nix::Error> for WaitError { + fn from(err: nix::Error) -> Self { + WaitError::OsError(err) + } +} + +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) + } + } +} + +impl std::error::Error for WaitError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + WaitError::TimedOut(_) => None, + WaitError::OsError(ref e) => Some(e) + } + } +}
\ No newline at end of file diff --git a/src/wait/mod.rs b/src/wait/mod.rs new file mode 100644 index 0000000..9761f08 --- /dev/null +++ b/src/wait/mod.rs @@ -0,0 +1,81 @@ +use nix::libc::{self, c_int}; +use nix::{ + errno::Errno, + sys::wait::WaitStatus, + unistd::Pid +}; +use std::time::{ Instant, Duration }; +use std::process::Child; +use std::thread; +use std::sync::mpsc; + +mod error; +mod rusage_ffi; +pub use rusage_ffi::Rusage; + +pub use error::WaitError; + +#[derive(Debug)] +pub struct WaitInfo { + pub status: WaitStatus, + pub usage: Rusage, + pub wall_time: Duration +} + + +fn wait4_pid( + pid: Pid, + chan: mpsc::Sender<std::result::Result<WaitInfo, nix::Error>>, + timer: Instant +) { + let mut status: c_int = 0; + let mut usg: libc::rusage; + let wait_ret; + + unsafe { + usg = std::mem::zeroed(); + wait_ret = libc::wait4(pid.as_raw(), &mut status, 0 as c_int, &mut usg); + } + + #[allow(unused_must_use)] { + chan.send(match wait_ret { + -1 => Err(nix::Error::Sys(Errno::last())), + _ => WaitStatus::from_raw(pid, status).map(|nix_status| { + WaitInfo { + status: nix_status, + usage: usg.into(), + wall_time: timer.elapsed() + } + } + ) + }); + }; +} + + +pub fn wait_child( + mut child: Child, + timeout: Duration, + timer: Instant +) -> Result<WaitInfo, 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(Err(err)) => Err(err.into()), + Err(mpsc::RecvTimeoutError::Timeout) => { + drop(recv); + drop(thr); + + #[allow(unused_must_use)] { + child.kill(); + } + + Err(WaitError::TimedOut(timeout)) + }, + Err(mpsc::RecvTimeoutError::Disconnected) => unreachable!() + } +} diff --git a/src/wait/rusage_ffi.rs b/src/wait/rusage_ffi.rs new file mode 100644 index 0000000..5948958 --- /dev/null +++ b/src/wait/rusage_ffi.rs @@ -0,0 +1,53 @@ +use nix::libc; +use std::time::Duration; + +#[derive(Debug)] +pub struct Rusage { + pub ru_utime: Duration, + pub ru_stime: Duration, + pub ru_maxrss: i64, + pub ru_ixrss: i64, + pub ru_idrss: i64, + pub ru_isrss: i64, + pub ru_minflt: i64, + pub ru_majflt: i64, + pub ru_nswap: i64, + pub ru_inblock: i64, + pub ru_oublock: i64, + pub ru_msgsnd: i64, + pub ru_msgrcv: i64, + pub ru_nsignals: i64, + pub ru_nvcsw: i64, + pub ru_nivcsw: i64, +} + +impl From<libc::rusage> for Rusage { + fn from(usg: libc::rusage) -> Rusage { + const MICROS_IN_SEC: u64 = 1_000_000; + let convert_timeval = |tv: libc::timeval| { + Duration::from_micros( + tv.tv_sec as u64 * MICROS_IN_SEC + + tv.tv_usec as u64 + ) + }; + + Rusage { + ru_utime: convert_timeval(usg.ru_utime), + ru_stime: convert_timeval(usg.ru_stime), + ru_maxrss: usg.ru_maxrss, + ru_ixrss: usg.ru_ixrss, + ru_idrss: usg.ru_idrss, + ru_isrss: usg.ru_isrss, + ru_minflt: usg.ru_minflt, + ru_majflt: usg.ru_majflt, + ru_nswap: usg.ru_nswap, + ru_inblock: usg.ru_inblock, + ru_oublock: usg.ru_oublock, + ru_msgsnd: usg.ru_msgsnd, + ru_msgrcv: usg.ru_msgrcv, + ru_nsignals: usg.ru_nsignals, + ru_nvcsw: usg.ru_nvcsw, + ru_nivcsw: usg.ru_nivcsw, + } + } +} |