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