Skip to content

Commit e1ce361

Browse files
committed
Merge #741
741: Expose `decode` on `WaitStatus` and make it return a `Result` r=Susurrus a=rocallahan Closes #740.
2 parents e5cc915 + 996bc6b commit e1ce361

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
- Use native `pipe2` on all BSD targets. Users should notice no difference.

src/sys/wait.rs

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

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

137137
fn dumped_core(status: i32) -> bool {
@@ -142,8 +142,8 @@ fn stopped(status: i32) -> bool {
142142
unsafe { libc::WIFSTOPPED(status) }
143143
}
144144

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

149149
fn syscall_stop(status: i32) -> bool {
@@ -162,34 +162,53 @@ fn continued(status: i32) -> bool {
162162
unsafe { libc::WIFCONTINUED(status) }
163163
}
164164

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

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

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

220239
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)