Skip to content

Commit

Permalink
Merge #741
Browse files Browse the repository at this point in the history
741: Expose `decode` on `WaitStatus` and make it return a `Result` r=Susurrus a=rocallahan

Closes #740.
  • Loading branch information
bors[bot] committed Dec 9, 2017
2 parents e5cc915 + 996bc6b commit e1ce361
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 33 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#785](https://github.com/nix-rust/nix/pull/785))
- Added `nix::unistd::execveat` on Linux and Android.
([#800](https://github.com/nix-rust/nix/pull/800))
- Added the `from_raw()` method to `WaitStatus` for converting raw status values
to `WaitStatus` independent of syscalls.
([#741](https://github.com/nix-rust/nix/pull/741))

### Changed
- Use native `pipe2` on all BSD targets. Users should notice no difference.
Expand Down
85 changes: 52 additions & 33 deletions src/sys/wait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ fn signaled(status: i32) -> bool {
unsafe { libc::WIFSIGNALED(status) }
}

fn term_signal(status: i32) -> Signal {
Signal::from_c_int(unsafe { libc::WTERMSIG(status) }).unwrap()
fn term_signal(status: i32) -> Result<Signal> {
Signal::from_c_int(unsafe { libc::WTERMSIG(status) })
}

fn dumped_core(status: i32) -> bool {
Expand All @@ -142,8 +142,8 @@ fn stopped(status: i32) -> bool {
unsafe { libc::WIFSTOPPED(status) }
}

fn stop_signal(status: i32) -> Signal {
Signal::from_c_int(unsafe { libc::WSTOPSIG(status) }).unwrap()
fn stop_signal(status: i32) -> Result<Signal> {
Signal::from_c_int(unsafe { libc::WSTOPSIG(status) })
}

fn syscall_stop(status: i32) -> bool {
Expand All @@ -162,34 +162,53 @@ fn continued(status: i32) -> bool {
unsafe { libc::WIFCONTINUED(status) }
}

fn decode(pid: Pid, status: i32) -> WaitStatus {
if exited(status) {
WaitStatus::Exited(pid, exit_status(status))
} else if signaled(status) {
WaitStatus::Signaled(pid, term_signal(status), dumped_core(status))
} else if stopped(status) {
cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
fn decode_stopped(pid: Pid, status: i32) -> WaitStatus {
let status_additional = stop_additional(status);
if syscall_stop(status) {
WaitStatus::PtraceSyscall(pid)
} else if status_additional == 0 {
WaitStatus::Stopped(pid, stop_signal(status))
} else {
WaitStatus::PtraceEvent(pid, stop_signal(status), stop_additional(status))
impl WaitStatus {
/// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus`
///
/// # Errors
///
/// Returns an `Error` corresponding to `EINVAL` for invalid status values.
///
/// # Examples
///
/// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`:
///
/// ```
/// use nix::sys::wait::WaitStatus;
/// use nix::sys::signal::Signal;
/// let pid = nix::unistd::Pid::from_raw(1);
/// let status = WaitStatus::from_raw(pid, 0x0002);
/// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
/// ```
pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> {
Ok(if exited(status) {
WaitStatus::Exited(pid, exit_status(status))
} else if signaled(status) {
WaitStatus::Signaled(pid, try!(term_signal(status)), dumped_core(status))
} else if stopped(status) {
cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
let status_additional = stop_additional(status);
Ok(if syscall_stop(status) {
WaitStatus::PtraceSyscall(pid)
} else if status_additional == 0 {
WaitStatus::Stopped(pid, try!(stop_signal(status)))
} else {
WaitStatus::PtraceEvent(pid, try!(stop_signal(status)), stop_additional(status))
})
}
} else {
fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
Ok(WaitStatus::Stopped(pid, try!(stop_signal(status))))
}
}
} else {
fn decode_stopped(pid: Pid, status: i32) -> WaitStatus {
WaitStatus::Stopped(pid, stop_signal(status))
}
}
}
decode_stopped(pid, status)
} else {
assert!(continued(status));
WaitStatus::Continued(pid)
return decode_stopped(pid, status);
} else {
assert!(continued(status));
WaitStatus::Continued(pid)
})
}
}

Expand All @@ -211,10 +230,10 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re
)
};

Ok(match try!(Errno::result(res)) {
0 => StillAlive,
res => decode(Pid::from_raw(res), status),
})
match try!(Errno::result(res)) {
0 => Ok(StillAlive),
res => WaitStatus::from_raw(Pid::from_raw(res), status),
}
}

pub fn wait() -> Result<WaitStatus> {
Expand Down
9 changes: 9 additions & 0 deletions test/sys/test_wait.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use nix::Error;
use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::sys::signal::*;
Expand Down Expand Up @@ -37,6 +38,14 @@ fn test_wait_exit() {
}
}

#[test]
fn test_waitstatus_from_raw() {
let pid = Pid::from_raw(1);
assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument()));
}

#[test]
fn test_waitstatus_pid() {
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
Expand Down

0 comments on commit e1ce361

Please sign in to comment.