Skip to content

Commit a5acccc

Browse files
authored
Use i32 for exit statuses too. (#1384)
* Use `i32` for exit statuses too. Following up on #1378, make process exit statuses be `i32` too, for compatibility with `exit`, `exit_group`, and related things. * Add a comment about why some features are disabled on NetBSD.
1 parent 7cab925 commit a5acccc

File tree

6 files changed

+83
-37
lines changed

6 files changed

+83
-37
lines changed

CHANGES.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@ the functions in the [`rustix::thread::futex`] module instead.
3535

3636
[`terminating_signal`] and other functions in [`rustix::process::WaitStatus`] changed
3737
from returning `u32` to returning `i32`, for better compatibility with the new
38-
[`Signal`] type.
38+
[`Signal`] type and [`exit`].
3939

4040
[`terminating_signal`]: https://docs.rs/rustix/1.0.0/rustix/process/struct.WaitStatus.html#method.terminating_signal
4141
[`rustix::process::WaitStatus`]: https://docs.rs/rustix/1.0.0/rustix/process/struct.WaitStatus.html
4242
[`Signal`]: https://docs.rs/rustix/1.0.0/rustix/process/struct.Signal.html
43+
[`exit`]: std::process::exit
4344

4445
The `SLAVE` flag in [`rustix::mount::MountPropagationFlags`] is renamed to
4546
[`DOWNSTREAM`].

src/backend/linux_raw/process/syscalls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ pub(crate) fn _waitpid(
298298
waitopts: WaitOptions,
299299
) -> io::Result<Option<(Pid, WaitStatus)>> {
300300
unsafe {
301-
let mut status = MaybeUninit::<u32>::uninit();
301+
let mut status = MaybeUninit::<i32>::uninit();
302302
let pid = ret_c_int(syscall!(
303303
__NR_wait4,
304304
c_int(pid as _),

src/backend/linux_raw/process/wait.rs

+17-15
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,37 @@ pub(crate) use linux_raw_sys::general::{
77
};
88

99
#[inline]
10-
pub(crate) fn WIFSTOPPED(status: u32) -> bool {
10+
pub(crate) fn WIFSTOPPED(status: i32) -> bool {
1111
(status & 0xff) == 0x7f
1212
}
1313

1414
#[inline]
15-
pub(crate) fn WSTOPSIG(status: u32) -> u32 {
15+
pub(crate) fn WSTOPSIG(status: i32) -> i32 {
1616
(status >> 8) & 0xff
1717
}
1818

1919
#[inline]
20-
pub(crate) fn WIFCONTINUED(status: u32) -> bool {
20+
pub(crate) fn WIFCONTINUED(status: i32) -> bool {
2121
status == 0xffff
2222
}
2323

2424
#[inline]
25-
pub(crate) fn WIFSIGNALED(status: u32) -> bool {
25+
pub(crate) fn WIFSIGNALED(status: i32) -> bool {
2626
((status & 0x7f) + 1) as i8 >= 2
2727
}
2828

2929
#[inline]
30-
pub(crate) fn WTERMSIG(status: u32) -> u32 {
30+
pub(crate) fn WTERMSIG(status: i32) -> i32 {
3131
status & 0x7f
3232
}
3333

3434
#[inline]
35-
pub(crate) fn WIFEXITED(status: u32) -> bool {
35+
pub(crate) fn WIFEXITED(status: i32) -> bool {
3636
(status & 0x7f) == 0
3737
}
3838

3939
#[inline]
40-
pub(crate) fn WEXITSTATUS(status: u32) -> u32 {
40+
pub(crate) fn WEXITSTATUS(status: i32) -> i32 {
4141
(status >> 8) & 0xff
4242
}
4343

@@ -107,15 +107,17 @@ mod tests {
107107
4095,
108108
4096,
109109
4097,
110-
u32::MAX,
110+
i32::MAX,
111+
i32::MIN,
112+
u32::MAX as i32,
111113
] {
112-
assert_eq!(WIFSTOPPED(status), libc::WIFSTOPPED(status as i32));
113-
assert_eq!(WSTOPSIG(status), libc::WSTOPSIG(status as i32) as u32);
114-
assert_eq!(WIFCONTINUED(status), libc::WIFCONTINUED(status as i32));
115-
assert_eq!(WIFSIGNALED(status), libc::WIFSIGNALED(status as i32));
116-
assert_eq!(WTERMSIG(status), libc::WTERMSIG(status as i32) as u32);
117-
assert_eq!(WIFEXITED(status), libc::WIFEXITED(status as i32));
118-
assert_eq!(WEXITSTATUS(status), libc::WEXITSTATUS(status as i32) as u32);
114+
assert_eq!(WIFSTOPPED(status), libc::WIFSTOPPED(status));
115+
assert_eq!(WSTOPSIG(status), libc::WSTOPSIG(status));
116+
assert_eq!(WIFCONTINUED(status), libc::WIFCONTINUED(status));
117+
assert_eq!(WIFSIGNALED(status), libc::WIFSIGNALED(status));
118+
assert_eq!(WTERMSIG(status), libc::WTERMSIG(status));
119+
assert_eq!(WIFEXITED(status), libc::WIFEXITED(status));
120+
assert_eq!(WEXITSTATUS(status), libc::WEXITSTATUS(status));
119121
}
120122
}
121123
}

src/process/wait.rs

+56-16
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use crate::process::Pid;
1010
use crate::{backend, io};
1111
use bitflags::bitflags;
12+
use core::fmt;
1213

1314
#[cfg(target_os = "linux")]
1415
use crate::fd::BorrowedFd;
@@ -73,51 +74,51 @@ bitflags! {
7374
/// The status of a child process after calling [`wait`]/[`waitpid`].
7475
#[derive(Debug, Clone, Copy)]
7576
#[repr(transparent)]
76-
pub struct WaitStatus(u32);
77+
pub struct WaitStatus(i32);
7778

7879
impl WaitStatus {
7980
/// Creates a `WaitStatus` out of an integer.
8081
#[inline]
81-
pub(crate) fn new(status: u32) -> Self {
82+
pub(crate) fn new(status: i32) -> Self {
8283
Self(status)
8384
}
8485

8586
/// Converts a `WaitStatus` into its raw representation as an integer.
8687
#[inline]
87-
pub const fn as_raw(self) -> u32 {
88+
pub const fn as_raw(self) -> i32 {
8889
self.0
8990
}
9091

9192
/// Returns whether the process is currently stopped.
9293
#[inline]
9394
pub fn stopped(self) -> bool {
94-
backend::process::wait::WIFSTOPPED(self.0 as _)
95+
backend::process::wait::WIFSTOPPED(self.0)
9596
}
9697

9798
/// Returns whether the process has exited normally.
9899
#[inline]
99100
pub fn exited(self) -> bool {
100-
backend::process::wait::WIFEXITED(self.0 as _)
101+
backend::process::wait::WIFEXITED(self.0)
101102
}
102103

103104
/// Returns whether the process was terminated by a signal.
104105
#[inline]
105106
pub fn signaled(self) -> bool {
106-
backend::process::wait::WIFSIGNALED(self.0 as _)
107+
backend::process::wait::WIFSIGNALED(self.0)
107108
}
108109

109110
/// Returns whether the process has continued from a job control stop.
110111
#[inline]
111112
pub fn continued(self) -> bool {
112-
backend::process::wait::WIFCONTINUED(self.0 as _)
113+
backend::process::wait::WIFCONTINUED(self.0)
113114
}
114115

115116
/// Returns the number of the signal that stopped the process, if the
116117
/// process was stopped by a signal.
117118
#[inline]
118119
pub fn stopping_signal(self) -> Option<i32> {
119120
if self.stopped() {
120-
Some(backend::process::wait::WSTOPSIG(self.0 as _) as _)
121+
Some(backend::process::wait::WSTOPSIG(self.0))
121122
} else {
122123
None
123124
}
@@ -126,9 +127,9 @@ impl WaitStatus {
126127
/// Returns the exit status number returned by the process, if it exited
127128
/// normally.
128129
#[inline]
129-
pub fn exit_status(self) -> Option<u32> {
130+
pub fn exit_status(self) -> Option<i32> {
130131
if self.exited() {
131-
Some(backend::process::wait::WEXITSTATUS(self.0 as _) as _)
132+
Some(backend::process::wait::WEXITSTATUS(self.0))
132133
} else {
133134
None
134135
}
@@ -139,7 +140,7 @@ impl WaitStatus {
139140
#[inline]
140141
pub fn terminating_signal(self) -> Option<i32> {
141142
if self.signaled() {
142-
Some(backend::process::wait::WTERMSIG(self.0 as _) as _)
143+
Some(backend::process::wait::WTERMSIG(self.0))
143144
} else {
144145
None
145146
}
@@ -217,7 +218,7 @@ impl WaitIdStatus {
217218
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
218219
pub fn stopping_signal(&self) -> Option<i32> {
219220
if self.stopped() {
220-
Some(self.si_status() as _)
221+
Some(self.si_status())
221222
} else {
222223
None
223224
}
@@ -229,7 +230,7 @@ impl WaitIdStatus {
229230
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
230231
pub fn trapping_signal(&self) -> Option<i32> {
231232
if self.trapped() {
232-
Some(self.si_status() as _)
233+
Some(self.si_status())
233234
} else {
234235
None
235236
}
@@ -239,9 +240,9 @@ impl WaitIdStatus {
239240
/// normally.
240241
#[inline]
241242
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
242-
pub fn exit_status(&self) -> Option<u32> {
243+
pub fn exit_status(&self) -> Option<i32> {
243244
if self.exited() {
244-
Some(self.si_status() as _)
245+
Some(self.si_status())
245246
} else {
246247
None
247248
}
@@ -253,7 +254,7 @@ impl WaitIdStatus {
253254
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
254255
pub fn terminating_signal(&self) -> Option<i32> {
255256
if self.killed() || self.dumped() {
256-
Some(self.si_status() as _)
257+
Some(self.si_status())
257258
} else {
258259
None
259260
}
@@ -295,6 +296,10 @@ impl WaitIdStatus {
295296
self.0.si_code
296297
}
297298

299+
// This is disabled on NetBSD because the libc crate's `si_status()`
300+
// implementation doesn't appear to match what's in NetBSD's headers and we
301+
// don't get a meaningful value returned.
302+
// TODO: Report this upstream.
298303
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
299304
#[allow(unsafe_code)]
300305
fn si_status(&self) -> crate::ffi::c_int {
@@ -306,6 +311,41 @@ impl WaitIdStatus {
306311
}
307312
}
308313

314+
#[cfg(not(any(
315+
target_os = "horizon",
316+
target_os = "openbsd",
317+
target_os = "redox",
318+
target_os = "wasi"
319+
)))]
320+
impl fmt::Debug for WaitIdStatus {
321+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322+
let mut s = f.debug_struct("WaitIdStatus");
323+
s.field("stopped", &self.stopped());
324+
s.field("exited", &self.exited());
325+
s.field("killed", &self.killed());
326+
s.field("trapped", &self.trapped());
327+
s.field("dumped", &self.dumped());
328+
s.field("continued", &self.continued());
329+
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
330+
if let Some(stopping_signal) = self.stopping_signal() {
331+
s.field("stopping_signal", &stopping_signal);
332+
}
333+
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
334+
if let Some(trapping_signal) = self.trapping_signal() {
335+
s.field("trapping_signal", &trapping_signal);
336+
}
337+
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
338+
if let Some(exit_status) = self.exit_status() {
339+
s.field("exit_status", &exit_status);
340+
}
341+
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
342+
if let Some(terminating_signal) = self.terminating_signal() {
343+
s.field("terminating_signal", &terminating_signal);
344+
}
345+
s.finish()
346+
}
347+
}
348+
309349
/// The identifier to wait on in a call to [`waitid`].
310350
#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))]
311351
#[derive(Debug, Clone)]

tests/process/pidfd.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::process::Command;
1212
#[serial]
1313
fn test_pidfd_waitid() {
1414
// Create a new process.
15-
let child = Command::new("yes")
15+
let mut child = Command::new("yes")
1616
.stdout(std::process::Stdio::null())
1717
.stderr(std::process::Stdio::null())
1818
.spawn()
@@ -25,6 +25,7 @@ fn test_pidfd_waitid() {
2525
Err(io::Errno::NOSYS) => {
2626
// The kernel does not support pidfds.
2727
unsafe { kill(child.id() as _, SIGINT) };
28+
child.wait().unwrap();
2829
return;
2930
}
3031
Err(e) => panic!("failed to open pidfd: {}", e),
@@ -104,7 +105,7 @@ fn test_pidfd_waitid() {
104105
#[serial]
105106
fn test_pidfd_send_signal() {
106107
// Create a new process.
107-
let child = Command::new("yes")
108+
let mut child = Command::new("yes")
108109
.stdout(std::process::Stdio::null())
109110
.stderr(std::process::Stdio::null())
110111
.spawn()
@@ -117,6 +118,7 @@ fn test_pidfd_send_signal() {
117118
Err(io::Errno::NOSYS) => {
118119
// The kernel does not support pidfds.
119120
process::kill_process(process::Pid::from_child(&child), process::Signal::INT).unwrap();
121+
child.wait().unwrap();
120122
return;
121123
}
122124
Err(e) => panic!("failed to open pidfd: {}", e),
@@ -195,7 +197,7 @@ fn test_pidfd_send_signal() {
195197
#[serial]
196198
fn test_pidfd_poll() {
197199
// Create a new process.
198-
let child = Command::new("sleep")
200+
let mut child = Command::new("sleep")
199201
.arg("1")
200202
.stdout(std::process::Stdio::null())
201203
.stderr(std::process::Stdio::null())
@@ -209,6 +211,7 @@ fn test_pidfd_poll() {
209211
Err(io::Errno::NOSYS) | Err(io::Errno::INVAL) => {
210212
// The kernel does not support non-blocking pidfds.
211213
process::kill_process(process::Pid::from_child(&child), process::Signal::INT).unwrap();
214+
child.wait().unwrap();
212215
return;
213216
}
214217
Err(e) => panic!("failed to open pidfd: {}", e),

tests/process/wait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ fn test_waitid() {
161161
assert!(status.continued());
162162

163163
let status = process::waitid(
164-
process::WaitId::All,
164+
process::WaitId::Pid(pid),
165165
process::WaitIdOptions::EXITED | process::WaitIdOptions::NOHANG,
166166
)
167167
.expect("failed to wait");

0 commit comments

Comments
 (0)