]> git.ipfire.org Git - thirdparty/glibc.git/blob - posix/tst-waitid.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / posix / tst-waitid.c
1 /* Tests for waitid.
2 Copyright (C) 2004-2019 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/wait.h>
24 #include <signal.h>
25
26 static void
27 test_child (void)
28 {
29 /* Wait a second to be sure the parent set his variables before we
30 produce a SIGCHLD. */
31 sleep (1);
32
33 /* First thing, we stop ourselves. */
34 raise (SIGSTOP);
35
36 /* Hey, we got continued! */
37 while (1)
38 pause ();
39 }
40
41 #ifndef WEXITED
42 # define WEXITED 0
43 # define WCONTINUED 0
44 # define WSTOPPED WUNTRACED
45 #endif
46
47 static sig_atomic_t expecting_sigchld, spurious_sigchld;
48 #ifdef SA_SIGINFO
49 static siginfo_t sigchld_info;
50
51 static void
52 sigchld (int signo, siginfo_t *info, void *ctx)
53 {
54 if (signo != SIGCHLD)
55 {
56 printf ("SIGCHLD handler got signal %d instead!\n", signo);
57 _exit (EXIT_FAILURE);
58 }
59
60 if (! expecting_sigchld)
61 {
62 spurious_sigchld = 1;
63 printf ("spurious SIGCHLD: signo %d code %d status %d pid %d\n",
64 info->si_signo, info->si_code, info->si_status, info->si_pid);
65 }
66 else
67 {
68 sigchld_info = *info;
69 expecting_sigchld = 0;
70 }
71 }
72
73 static void
74 check_sigchld (const char *phase, int *ok, int code, int status, pid_t pid)
75 {
76 if (expecting_sigchld)
77 {
78 printf ("missing SIGCHLD on %s\n", phase);
79 *ok = EXIT_FAILURE;
80 expecting_sigchld = 0;
81 return;
82 }
83
84 if (sigchld_info.si_signo != SIGCHLD)
85 {
86 printf ("SIGCHLD for %s signal %d\n", phase, sigchld_info.si_signo);
87 *ok = EXIT_FAILURE;
88 }
89 if (sigchld_info.si_code != code)
90 {
91 printf ("SIGCHLD for %s code %d\n", phase, sigchld_info.si_code);
92 *ok = EXIT_FAILURE;
93 }
94 if (sigchld_info.si_status != status)
95 {
96 printf ("SIGCHLD for %s status %d\n", phase, sigchld_info.si_status);
97 *ok = EXIT_FAILURE;
98 }
99 if (sigchld_info.si_pid != pid)
100 {
101 printf ("SIGCHLD for %s pid %d\n", phase, sigchld_info.si_pid);
102 *ok = EXIT_FAILURE;
103 }
104 }
105 # define CHECK_SIGCHLD(phase, code_check, status_check) \
106 check_sigchld ((phase), &status, (code_check), (status_check), pid)
107 #else
108 # define CHECK_SIGCHLD(phase, code, status) ((void) 0)
109 #endif
110
111 static int
112 do_test (int argc, char *argv[])
113 {
114 #ifdef SA_SIGINFO
115 struct sigaction sa;
116 sa.sa_flags = SA_SIGINFO|SA_RESTART;
117 sa.sa_sigaction = &sigchld;
118 if (sigemptyset (&sa.sa_mask) < 0 || sigaction (SIGCHLD, &sa, NULL) < 0)
119 {
120 printf ("setting SIGCHLD handler: %m\n");
121 return EXIT_FAILURE;
122 }
123 #endif
124
125 expecting_sigchld = 1;
126
127 pid_t pid = fork ();
128 if (pid < 0)
129 {
130 printf ("fork: %m\n");
131 return EXIT_FAILURE;
132 }
133 else if (pid == 0)
134 {
135 test_child ();
136 _exit (127);
137 }
138
139 int status = EXIT_SUCCESS;
140 #define RETURN(ok) \
141 do { if (status == EXIT_SUCCESS) status = (ok); goto out; } while (0)
142
143 /* Give the child a chance to stop. */
144 sleep (3);
145
146 CHECK_SIGCHLD ("stopped (before waitid)", CLD_STOPPED, SIGSTOP);
147
148 /* Now try a wait that should not succeed. */
149 siginfo_t info;
150 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
151 int fail = waitid (P_PID, pid, &info, WEXITED|WCONTINUED|WNOHANG);
152 switch (fail)
153 {
154 default:
155 printf ("waitid returned bogus value %d\n", fail);
156 RETURN (EXIT_FAILURE);
157 case -1:
158 printf ("waitid WNOHANG on stopped: %m\n");
159 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
160 case 0:
161 if (info.si_signo == 0)
162 break;
163 if (info.si_signo == SIGCHLD)
164 printf ("waitid WNOHANG on stopped status %d\n", info.si_status);
165 else
166 printf ("waitid WNOHANG on stopped signal %d\n", info.si_signo);
167 RETURN (EXIT_FAILURE);
168 }
169
170 /* Next the wait that should succeed right away. */
171 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
172 info.si_pid = -1;
173 info.si_status = -1;
174 fail = waitid (P_PID, pid, &info, WSTOPPED|WNOHANG);
175 switch (fail)
176 {
177 default:
178 printf ("waitid WSTOPPED|WNOHANG returned bogus value %d\n", fail);
179 RETURN (EXIT_FAILURE);
180 case -1:
181 printf ("waitid WSTOPPED|WNOHANG on stopped: %m\n");
182 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
183 case 0:
184 if (info.si_signo != SIGCHLD)
185 {
186 printf ("waitid WSTOPPED|WNOHANG on stopped signal %d\n",
187 info.si_signo);
188 RETURN (EXIT_FAILURE);
189 }
190 if (info.si_code != CLD_STOPPED)
191 {
192 printf ("waitid WSTOPPED|WNOHANG on stopped code %d\n",
193 info.si_code);
194 RETURN (EXIT_FAILURE);
195 }
196 if (info.si_status != SIGSTOP)
197 {
198 printf ("waitid WSTOPPED|WNOHANG on stopped status %d\n",
199 info.si_status);
200 RETURN (EXIT_FAILURE);
201 }
202 if (info.si_pid != pid)
203 {
204 printf ("waitid WSTOPPED|WNOHANG on stopped pid %d != %d\n",
205 info.si_pid, pid);
206 RETURN (EXIT_FAILURE);
207 }
208 }
209
210 expecting_sigchld = WCONTINUED != 0;
211
212 if (kill (pid, SIGCONT) != 0)
213 {
214 printf ("kill (%d, SIGCONT): %m\n", pid);
215 RETURN (EXIT_FAILURE);
216 }
217
218 /* Wait for the child to have continued. */
219 sleep (2);
220
221 #if WCONTINUED != 0
222 if (expecting_sigchld)
223 {
224 printf ("no SIGCHLD seen for SIGCONT (optional)\n");
225 expecting_sigchld = 0;
226 }
227 else
228 CHECK_SIGCHLD ("continued (before waitid)", CLD_CONTINUED, SIGCONT);
229
230 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
231 info.si_pid = -1;
232 info.si_status = -1;
233 fail = waitid (P_PID, pid, &info, WCONTINUED|WNOWAIT);
234 switch (fail)
235 {
236 default:
237 printf ("waitid WCONTINUED|WNOWAIT returned bogus value %d\n", fail);
238 RETURN (EXIT_FAILURE);
239 case -1:
240 printf ("waitid WCONTINUED|WNOWAIT on continued: %m\n");
241 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
242 case 0:
243 if (info.si_signo != SIGCHLD)
244 {
245 printf ("waitid WCONTINUED|WNOWAIT on continued signal %d\n",
246 info.si_signo);
247 RETURN (EXIT_FAILURE);
248 }
249 if (info.si_code != CLD_CONTINUED)
250 {
251 printf ("waitid WCONTINUED|WNOWAIT on continued code %d\n",
252 info.si_code);
253 RETURN (EXIT_FAILURE);
254 }
255 if (info.si_status != SIGCONT)
256 {
257 printf ("waitid WCONTINUED|WNOWAIT on continued status %d\n",
258 info.si_status);
259 RETURN (EXIT_FAILURE);
260 }
261 if (info.si_pid != pid)
262 {
263 printf ("waitid WCONTINUED|WNOWAIT on continued pid %d != %d\n",
264 info.si_pid, pid);
265 RETURN (EXIT_FAILURE);
266 }
267 }
268
269 /* That should leave the CLD_CONTINUED state waiting to be seen again. */
270 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
271 info.si_pid = -1;
272 info.si_status = -1;
273 fail = waitid (P_PID, pid, &info, WCONTINUED);
274 switch (fail)
275 {
276 default:
277 printf ("waitid WCONTINUED returned bogus value %d\n", fail);
278 RETURN (EXIT_FAILURE);
279 case -1:
280 printf ("waitid WCONTINUED on continued: %m\n");
281 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
282 case 0:
283 if (info.si_signo != SIGCHLD)
284 {
285 printf ("waitid WCONTINUED on continued signal %d\n", info.si_signo);
286 RETURN (EXIT_FAILURE);
287 }
288 if (info.si_code != CLD_CONTINUED)
289 {
290 printf ("waitid WCONTINUED on continued code %d\n", info.si_code);
291 RETURN (EXIT_FAILURE);
292 }
293 if (info.si_status != SIGCONT)
294 {
295 printf ("waitid WCONTINUED on continued status %d\n",
296 info.si_status);
297 RETURN (EXIT_FAILURE);
298 }
299 if (info.si_pid != pid)
300 {
301 printf ("waitid WCONTINUED on continued pid %d != %d\n",
302 info.si_pid, pid);
303 RETURN (EXIT_FAILURE);
304 }
305 }
306
307 /* Now try a wait that should not succeed. */
308 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
309 fail = waitid (P_PID, pid, &info, WCONTINUED|WNOHANG);
310 switch (fail)
311 {
312 default:
313 printf ("waitid returned bogus value %d\n", fail);
314 RETURN (EXIT_FAILURE);
315 case -1:
316 printf ("waitid WCONTINUED|WNOHANG on waited continued: %m\n");
317 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
318 case 0:
319 if (info.si_signo == 0)
320 break;
321 if (info.si_signo == SIGCHLD)
322 printf ("waitid WCONTINUED|WNOHANG on waited continued status %d\n",
323 info.si_status);
324 else
325 printf ("waitid WCONTINUED|WNOHANG on waited continued signal %d\n",
326 info.si_signo);
327 RETURN (EXIT_FAILURE);
328 }
329
330 /* Now stop him again and test waitpid with WCONTINUED. */
331 expecting_sigchld = 1;
332 if (kill (pid, SIGSTOP) != 0)
333 {
334 printf ("kill (%d, SIGSTOP): %m\n", pid);
335 RETURN (EXIT_FAILURE);
336 }
337
338 /* Give the child a chance to stop. The waitpid call below will block
339 until it has stopped, but if we are real quick and enter the waitpid
340 system call before the SIGCHLD has been generated, then it will be
341 discarded and never delivered. */
342 sleep (3);
343
344 pid_t wpid = waitpid (pid, &fail, WUNTRACED);
345 if (wpid < 0)
346 {
347 printf ("waitpid WUNTRACED on stopped: %m\n");
348 RETURN (EXIT_FAILURE);
349 }
350 else if (wpid != pid)
351 {
352 printf ("waitpid WUNTRACED on stopped returned %d != %d (status %x)\n",
353 wpid, pid, fail);
354 RETURN (EXIT_FAILURE);
355 }
356 else if (!WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
357 || WIFCONTINUED (fail) || WSTOPSIG (fail) != SIGSTOP)
358 {
359 printf ("waitpid WUNTRACED on stopped: status %x\n", fail);
360 RETURN (EXIT_FAILURE);
361 }
362 CHECK_SIGCHLD ("stopped (after waitpid)", CLD_STOPPED, SIGSTOP);
363
364 expecting_sigchld = 1;
365 if (kill (pid, SIGCONT) != 0)
366 {
367 printf ("kill (%d, SIGCONT): %m\n", pid);
368 RETURN (EXIT_FAILURE);
369 }
370
371 /* Wait for the child to have continued. */
372 sleep (2);
373
374 if (expecting_sigchld)
375 {
376 printf ("no SIGCHLD seen for SIGCONT (optional)\n");
377 expecting_sigchld = 0;
378 }
379 else
380 CHECK_SIGCHLD ("continued (before waitpid)", CLD_CONTINUED, SIGCONT);
381
382 wpid = waitpid (pid, &fail, WCONTINUED);
383 if (wpid < 0)
384 {
385 if (errno == EINVAL)
386 printf ("waitpid does not support WCONTINUED\n");
387 else
388 {
389 printf ("waitpid WCONTINUED on continued: %m\n");
390 RETURN (EXIT_FAILURE);
391 }
392 }
393 else if (wpid != pid)
394 {
395 printf ("\
396 waitpid WCONTINUED on continued returned %d != %d (status %x)\n",
397 wpid, pid, fail);
398 RETURN (EXIT_FAILURE);
399 }
400 else if (WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
401 || !WIFCONTINUED (fail))
402 {
403 printf ("waitpid WCONTINUED on continued: status %x\n", fail);
404 RETURN (EXIT_FAILURE);
405 }
406 #endif
407
408 expecting_sigchld = 1;
409
410 /* Die, child, die! */
411 if (kill (pid, SIGKILL) != 0)
412 {
413 printf ("kill (%d, SIGKILL): %m\n", pid);
414 RETURN (EXIT_FAILURE);
415 }
416
417 #ifdef WNOWAIT
418 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
419 info.si_pid = -1;
420 info.si_status = -1;
421 fail = waitid (P_PID, pid, &info, WEXITED|WNOWAIT);
422 switch (fail)
423 {
424 default:
425 printf ("waitid WNOWAIT returned bogus value %d\n", fail);
426 RETURN (EXIT_FAILURE);
427 case -1:
428 printf ("waitid WNOWAIT on killed: %m\n");
429 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
430 case 0:
431 if (info.si_signo != SIGCHLD)
432 {
433 printf ("waitid WNOWAIT on killed signal %d\n", info.si_signo);
434 RETURN (EXIT_FAILURE);
435 }
436 if (info.si_code != CLD_KILLED)
437 {
438 printf ("waitid WNOWAIT on killed code %d\n", info.si_code);
439 RETURN (EXIT_FAILURE);
440 }
441 if (info.si_status != SIGKILL)
442 {
443 printf ("waitid WNOWAIT on killed status %d\n", info.si_status);
444 RETURN (EXIT_FAILURE);
445 }
446 if (info.si_pid != pid)
447 {
448 printf ("waitid WNOWAIT on killed pid %d != %d\n", info.si_pid, pid);
449 RETURN (EXIT_FAILURE);
450 }
451 }
452 #else
453 /* Allow enough time to be sure the child died; we didn't synchronize. */
454 sleep (2);
455 #endif
456
457 CHECK_SIGCHLD ("killed", CLD_KILLED, SIGKILL);
458
459 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
460 info.si_pid = -1;
461 info.si_status = -1;
462 fail = waitid (P_PID, pid, &info, WEXITED|WNOHANG);
463 switch (fail)
464 {
465 default:
466 printf ("waitid WNOHANG returned bogus value %d\n", fail);
467 RETURN (EXIT_FAILURE);
468 case -1:
469 printf ("waitid WNOHANG on killed: %m\n");
470 RETURN (EXIT_FAILURE);
471 case 0:
472 if (info.si_signo != SIGCHLD)
473 {
474 printf ("waitid WNOHANG on killed signal %d\n", info.si_signo);
475 RETURN (EXIT_FAILURE);
476 }
477 if (info.si_code != CLD_KILLED)
478 {
479 printf ("waitid WNOHANG on killed code %d\n", info.si_code);
480 RETURN (EXIT_FAILURE);
481 }
482 if (info.si_status != SIGKILL)
483 {
484 printf ("waitid WNOHANG on killed status %d\n", info.si_status);
485 RETURN (EXIT_FAILURE);
486 }
487 if (info.si_pid != pid)
488 {
489 printf ("waitid WNOHANG on killed pid %d != %d\n", info.si_pid, pid);
490 RETURN (EXIT_FAILURE);
491 }
492 }
493
494 fail = waitid (P_PID, pid, &info, WEXITED);
495 if (fail == -1)
496 {
497 if (errno != ECHILD)
498 {
499 printf ("waitid WEXITED on killed: %m\n");
500 RETURN (EXIT_FAILURE);
501 }
502 }
503 else
504 {
505 printf ("waitid WEXITED returned bogus value %d\n", fail);
506 RETURN (EXIT_FAILURE);
507 }
508
509 #undef RETURN
510 out:
511 if (spurious_sigchld)
512 status = EXIT_FAILURE;
513 signal (SIGCHLD, SIG_IGN);
514 kill (pid, SIGKILL); /* Make sure it's dead if we bailed early. */
515 return status;
516 }
517
518 #include "../test-skeleton.c"