@@ -23,6 +23,33 @@ fn test_wait_signal() {
23
23
}
24
24
}
25
25
26
+ #[ test]
27
+ #[ cfg( any(
28
+ target_os = "android" ,
29
+ target_os = "freebsd" ,
30
+ target_os = "haiku" ,
31
+ all( target_os = "linux" , not( target_env = "uclibc" ) ) ,
32
+ ) ) ]
33
+ #[ cfg( not( any( target_arch = "mips" , target_arch = "mips64" ) ) ) ]
34
+ fn test_waitid_signal ( ) {
35
+ let _m = crate :: FORK_MTX . lock ( ) ;
36
+
37
+ // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
38
+ match unsafe { fork ( ) } . expect ( "Error: Fork Failed" ) {
39
+ Child => {
40
+ pause ( ) ;
41
+ unsafe { _exit ( 123 ) }
42
+ } ,
43
+ Parent { child } => {
44
+ kill ( child, Some ( SIGKILL ) ) . expect ( "Error: Kill Failed" ) ;
45
+ assert_eq ! (
46
+ waitid( Id :: Pid ( child) , WaitPidFlag :: WEXITED ) ,
47
+ Ok ( WaitStatus :: Signaled ( child, SIGKILL , false ) ) ,
48
+ ) ;
49
+ } ,
50
+ }
51
+ }
52
+
26
53
#[ test]
27
54
fn test_wait_exit ( ) {
28
55
let _m = crate :: FORK_MTX . lock ( ) ;
@@ -36,6 +63,29 @@ fn test_wait_exit() {
36
63
}
37
64
}
38
65
66
+ #[ test]
67
+ #[ cfg( any(
68
+ target_os = "android" ,
69
+ target_os = "freebsd" ,
70
+ target_os = "haiku" ,
71
+ all( target_os = "linux" , not( target_env = "uclibc" ) ) ,
72
+ ) ) ]
73
+ #[ cfg( not( any( target_arch = "mips" , target_arch = "mips64" ) ) ) ]
74
+ fn test_waitid_exit ( ) {
75
+ let _m = crate :: FORK_MTX . lock ( ) ;
76
+
77
+ // Safe: Child only calls `_exit`, which is async-signal-safe.
78
+ match unsafe { fork ( ) } . expect ( "Error: Fork Failed" ) {
79
+ Child => unsafe { _exit ( 12 ) ; } ,
80
+ Parent { child } => {
81
+ assert_eq ! (
82
+ waitid( Id :: Pid ( child) , WaitPidFlag :: WEXITED ) ,
83
+ Ok ( WaitStatus :: Exited ( child, 12 ) ) ,
84
+ ) ;
85
+ }
86
+ }
87
+ }
88
+
39
89
#[ test]
40
90
fn test_waitstatus_from_raw ( ) {
41
91
let pid = Pid :: from_raw ( 1 ) ;
@@ -57,6 +107,25 @@ fn test_waitstatus_pid() {
57
107
}
58
108
}
59
109
110
+ #[ test]
111
+ #[ cfg( any(
112
+ target_os = "android" ,
113
+ target_os = "freebsd" ,
114
+ target_os = "haiku" ,
115
+ all( target_os = "linux" , not( target_env = "uclibc" ) ) ,
116
+ ) ) ]
117
+ fn test_waitid_pid ( ) {
118
+ let _m = crate :: FORK_MTX . lock ( ) ;
119
+
120
+ match unsafe { fork ( ) } . unwrap ( ) {
121
+ Child => unsafe { _exit ( 0 ) } ,
122
+ Parent { child } => {
123
+ let status = waitid ( Id :: Pid ( child) , WaitPidFlag :: WEXITED ) . unwrap ( ) ;
124
+ assert_eq ! ( status. pid( ) , Some ( child) ) ;
125
+ }
126
+ }
127
+ }
128
+
60
129
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
61
130
// FIXME: qemu-user doesn't implement ptrace on most arches
62
131
#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
@@ -77,7 +146,7 @@ mod ptrace {
77
146
unsafe { _exit ( 0 ) }
78
147
}
79
148
80
- fn ptrace_parent ( child : Pid ) {
149
+ fn ptrace_wait_parent ( child : Pid ) {
81
150
// Wait for the raised SIGTRAP
82
151
assert_eq ! ( waitpid( child, None ) , Ok ( WaitStatus :: Stopped ( child, SIGTRAP ) ) ) ;
83
152
// We want to test a syscall stop and a PTRACE_EVENT stop
@@ -94,14 +163,59 @@ mod ptrace {
94
163
assert_eq ! ( waitpid( child, None ) , Ok ( WaitStatus :: Exited ( child, 0 ) ) ) ;
95
164
}
96
165
166
+ #[ cfg( not( target_env = "uclibc" ) ) ]
167
+ fn ptrace_waitid_parent ( child : Pid ) {
168
+ // Wait for the raised SIGTRAP
169
+ //
170
+ // Unlike waitpid(), waitid() can distinguish trap events from regular
171
+ // stop events, so unlike ptrace_wait_parent(), we get a PtraceEvent here
172
+ assert_eq ! (
173
+ waitid( Id :: Pid ( child) , WaitPidFlag :: WEXITED ) ,
174
+ Ok ( WaitStatus :: PtraceEvent ( child, SIGTRAP , 0 ) ) ,
175
+ ) ;
176
+ // We want to test a syscall stop and a PTRACE_EVENT stop
177
+ assert ! ( ptrace:: setoptions( child, Options :: PTRACE_O_TRACESYSGOOD | Options :: PTRACE_O_TRACEEXIT ) . is_ok( ) ) ;
178
+
179
+ // First, stop on the next system call, which will be exit()
180
+ assert ! ( ptrace:: syscall( child, None ) . is_ok( ) ) ;
181
+ assert_eq ! (
182
+ waitid( Id :: Pid ( child) , WaitPidFlag :: WEXITED ) ,
183
+ Ok ( WaitStatus :: PtraceSyscall ( child) ) ,
184
+ ) ;
185
+ // Then get the ptrace event for the process exiting
186
+ assert ! ( ptrace:: cont( child, None ) . is_ok( ) ) ;
187
+ assert_eq ! (
188
+ waitid( Id :: Pid ( child) , WaitPidFlag :: WEXITED ) ,
189
+ Ok ( WaitStatus :: PtraceEvent ( child, SIGTRAP , Event :: PTRACE_EVENT_EXIT as i32 ) ) ,
190
+ ) ;
191
+ // Finally get the normal wait() result, now that the process has exited
192
+ assert ! ( ptrace:: cont( child, None ) . is_ok( ) ) ;
193
+ assert_eq ! (
194
+ waitid( Id :: Pid ( child) , WaitPidFlag :: WEXITED ) ,
195
+ Ok ( WaitStatus :: Exited ( child, 0 ) ) ,
196
+ ) ;
197
+ }
198
+
97
199
#[ test]
98
200
fn test_wait_ptrace ( ) {
99
201
require_capability ! ( "test_wait_ptrace" , CAP_SYS_PTRACE ) ;
100
202
let _m = crate :: FORK_MTX . lock ( ) ;
101
203
102
204
match unsafe { fork ( ) } . expect ( "Error: Fork Failed" ) {
103
205
Child => ptrace_child ( ) ,
104
- Parent { child } => ptrace_parent ( child) ,
206
+ Parent { child } => ptrace_wait_parent ( child) ,
207
+ }
208
+ }
209
+
210
+ #[ test]
211
+ #[ cfg( not( target_env = "uclibc" ) ) ]
212
+ fn test_waitid_ptrace ( ) {
213
+ require_capability ! ( "test_waitid_ptrace" , CAP_SYS_PTRACE ) ;
214
+ let _m = crate :: FORK_MTX . lock ( ) ;
215
+
216
+ match unsafe { fork ( ) } . expect ( "Error: Fork Failed" ) {
217
+ Child => ptrace_child ( ) ,
218
+ Parent { child } => ptrace_waitid_parent ( child) ,
105
219
}
106
220
}
107
221
}
0 commit comments