1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use core::mem::MaybeUninit as MU;
pub use libc::id_t as Id;
use Error;
#[inline]
pub fn fork() -> Result<Id, Error> { unsafe { esyscall!(FORK).map(|pid| pid as _) } }
#[inline]
pub fn quit(code: isize) -> ! { unsafe {
#[cfg(target_os = "linux")]
syscall!(EXIT_GROUP, code);
syscall!(EXIT, code);
::core::intrinsics::abort()
} }
#[inline]
pub fn pid() -> Id { unsafe { syscall!(GETPID) as _ } }
#[inline]
pub fn ppid() -> Id { unsafe { syscall!(GETPPID) as _ } }
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum WaitSpec {
Pid(Id),
Gid(Id),
All,
}
impl WaitSpec {
#[inline]
pub fn wait(self, flags: WaitFlags) -> Result<(WaitInfo, ::libc::rusage), Error> {
unsafe {
let (id_type, id) = self.to_wait_args();
let mut si = siginfo_ { u: () };
let mut ru = MU::<::libc::rusage>::uninit();
si.si.si_pid = 0;
#[cfg(target_os = "linux")]
esyscall!(WAITID, id_type, id, &mut si as *mut _, flags.bits(), ru.as_mut_ptr())?;
#[cfg(target_os = "freebsd")]
esyscall!(WAIT6, id_type, id, &mut 0usize as *mut _, flags.bits(), ru.as_mut_ptr(), &mut si as *mut _)?;
if 0 == si.si.si_pid { return Err(Error::EWOULDBLOCK) }
Ok((WaitInfo::from_c(si.si), ru.assume_init()))
}
}
#[inline]
unsafe fn to_wait_args(self) -> (::libc::idtype_t, Id) {
use self::WaitSpec::*;
match self {
Pid(pid) => (::libc::P_PID, pid),
Gid(gid) => (::libc::P_PGID, gid),
All => (::libc::P_ALL, MU::uninit().assume_init()),
}
}
}
#[allow(missing_docs)]
mod wait_flags { bitflags! {
pub struct WaitFlags: usize {
const Exit = ::libc::WEXITED as usize;
const Stop = ::libc::WSTOPPED as usize;
const Cont = ::libc::WCONTINUED as usize;
const NoHang = ::libc::WNOHANG as usize;
const NoWait = ::libc::WNOWAIT as usize;
}
} } pub use self::wait_flags::WaitFlags;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct WaitInfo {
pid: Id,
code: WaitCode,
status: isize,
}
impl WaitInfo {
#[inline]
unsafe fn from_c(si: siginfo) -> Self {
WaitInfo {
pid: si.si_pid as _,
code: WaitCode(si.si_code),
status: si.si_status as _,
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct WaitCode(::libc::c_int);
#[allow(missing_docs)]
impl WaitCode {
pub const Exit: Self = WaitCode(1);
pub const Kill: Self = WaitCode(2);
pub const Dump: Self = WaitCode(3);
pub const Trap: Self = WaitCode(4);
pub const Stop: Self = WaitCode(5);
pub const Cont: Self = WaitCode(6);
}
#[cfg(target_os = "linux")]
#[repr(C)]
#[derive(Clone, Copy)]
struct siginfo {
si_signo: ::libc::c_int,
si_errno: ::libc::c_int,
si_code: ::libc::c_int,
si_pid: ::libc::pid_t,
si_uid: ::libc::uid_t,
si_value: ::libc::sigval,
si_status: ::libc::c_int,
}
#[cfg(target_os = "freebsd")]
type siginfo = ::libc::siginfo_t;
#[repr(C)]
union siginfo_ {
si: siginfo,
pad: [u8; 0x80],
u: (),
}