summaryrefslogtreecommitdiffstats
path: root/src/wait
diff options
context:
space:
mode:
authorsyn <isaqtm@gmail.com>2020-02-09 19:17:57 +0300
committersyn <isaqtm@gmail.com>2020-02-09 19:17:57 +0300
commit30e1e3a13dc19c47afc517d1178e1dbf5b401596 (patch)
treeb57b23cb10d468325bc259e05dfb6901b9b56f59 /src/wait
parentdf090c4c8caa0632ce1fa802faf8752c2c861517 (diff)
downloadevr-30e1e3a13dc19c47afc517d1178e1dbf5b401596.tar.gz
timeout'ed waiter for process
Diffstat (limited to 'src/wait')
-rw-r--r--src/wait/error.rs32
-rw-r--r--src/wait/mod.rs81
-rw-r--r--src/wait/rusage_ffi.rs53
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,
+ }
+ }
+}