summaryrefslogtreecommitdiffstats
path: root/src/wait
diff options
context:
space:
mode:
Diffstat (limited to 'src/wait')
-rw-r--r--src/wait/error.rs26
-rw-r--r--src/wait/mod.rs31
2 files changed, 51 insertions, 6 deletions
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);