Skip to content

Commit 996bc6b

Browse files
committed
Expose from_raw on WaitStatus and make it return a Result
1 parent 3871586 commit 996bc6b

File tree

3 files changed

+64
-33
lines changed

3 files changed

+64
-33
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4545
([#785](https://github.com/nix-rust/nix/pull/785))
4646
- Added `nix::unistd::execveat` on Linux and Android.
4747
([#800](https://github.com/nix-rust/nix/pull/800))
48+
- Added the `from_raw()` method to `WaitStatus` for converting raw status values
49+
to `WaitStatus` independent of syscalls.
50+
([#741](https://github.com/nix-rust/nix/pull/741))
4851

4952
### Changed
5053
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))

src/sys/wait.rs

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ fn signaled(status: i32) -> bool {
129129
unsafe { libc::WIFSIGNALED(status) }
130130
}
131131

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

136136
fn dumped_core(status: i32) -> bool {
@@ -141,8 +141,8 @@ fn stopped(status: i32) -> bool {
141141
unsafe { libc::WIFSTOPPED(status) }
142142
}
143143

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

148148
fn syscall_stop(status: i32) -> bool {
@@ -161,34 +161,53 @@ fn continued(status: i32) -> bool {
161161
unsafe { libc::WIFCONTINUED(status) }
162162
}
163163

164-
fn decode(pid: Pid, status: i32) -> WaitStatus {
165-
if exited(status) {
166-
WaitStatus::Exited(pid, exit_status(status))
167-
} else if signaled(status) {
168-
WaitStatus::Signaled(pid, term_signal(status), dumped_core(status))
169-
} else if stopped(status) {
170-
cfg_if! {
171-
if #[cfg(any(target_os = "linux", target_os = "android"))] {
172-
fn decode_stopped(pid: Pid, status: i32) -> WaitStatus {
173-
let status_additional = stop_additional(status);
174-
if syscall_stop(status) {
175-
WaitStatus::PtraceSyscall(pid)
176-
} else if status_additional == 0 {
177-
WaitStatus::Stopped(pid, stop_signal(status))
178-
} else {
179-
WaitStatus::PtraceEvent(pid, stop_signal(status), stop_additional(status))
164+
impl WaitStatus {
165+
/// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus`
166+
///
167+
/// # Errors
168+
///
169+
/// Returns an `Error` corresponding to `EINVAL` for invalid status values.
170+
///
171+
/// # Examples
172+
///
173+
/// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`:
174+
///
175+
/// ```
176+
/// use nix::sys::wait::WaitStatus;
177+
/// use nix::sys::signal::Signal;
178+
/// let pid = nix::unistd::Pid::from_raw(1);
179+
/// let status = WaitStatus::from_raw(pid, 0x0002);
180+
/// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
181+
/// ```
182+
pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> {
183+
Ok(if exited(status) {
184+
WaitStatus::Exited(pid, exit_status(status))
185+
} else if signaled(status) {
186+
WaitStatus::Signaled(pid, try!(term_signal(status)), dumped_core(status))
187+
} else if stopped(status) {
188+
cfg_if! {
189+
if #[cfg(any(target_os = "linux", target_os = "android"))] {
190+
fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
191+
let status_additional = stop_additional(status);
192+
Ok(if syscall_stop(status) {
193+
WaitStatus::PtraceSyscall(pid)
194+
} else if status_additional == 0 {
195+
WaitStatus::Stopped(pid, try!(stop_signal(status)))
196+
} else {
197+
WaitStatus::PtraceEvent(pid, try!(stop_signal(status)), stop_additional(status))
198+
})
199+
}
200+
} else {
201+
fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
202+
Ok(WaitStatus::Stopped(pid, try!(stop_signal(status))))
180203
}
181-
}
182-
} else {
183-
fn decode_stopped(pid: Pid, status: i32) -> WaitStatus {
184-
WaitStatus::Stopped(pid, stop_signal(status))
185204
}
186205
}
187-
}
188-
decode_stopped(pid, status)
189-
} else {
190-
assert!(continued(status));
191-
WaitStatus::Continued(pid)
206+
return decode_stopped(pid, status);
207+
} else {
208+
assert!(continued(status));
209+
WaitStatus::Continued(pid)
210+
})
192211
}
193212
}
194213

@@ -210,10 +229,10 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re
210229
)
211230
};
212231

213-
Ok(match try!(Errno::result(res)) {
214-
0 => StillAlive,
215-
res => decode(Pid::from_raw(res), status),
216-
})
232+
match try!(Errno::result(res)) {
233+
0 => Ok(StillAlive),
234+
res => WaitStatus::from_raw(Pid::from_raw(res), status),
235+
}
217236
}
218237

219238
pub fn wait() -> Result<WaitStatus> {

test/sys/test_wait.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use nix::Error;
12
use nix::unistd::*;
23
use nix::unistd::ForkResult::*;
34
use nix::sys::signal::*;
@@ -37,6 +38,14 @@ fn test_wait_exit() {
3738
}
3839
}
3940

41+
#[test]
42+
fn test_waitstatus_from_raw() {
43+
let pid = Pid::from_raw(1);
44+
assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
45+
assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
46+
assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument()));
47+
}
48+
4049
#[test]
4150
fn test_waitstatus_pid() {
4251
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

0 commit comments

Comments
 (0)