Update copyright dates with scripts/update-copyrights.
[glibc.git] / posix / tst-waitid.c
blobf24bd72a312b0e4cde49536f9851155583ef4d59
1 /* Tests for waitid.
2 Copyright (C) 2004-2015 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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 <http://www.gnu.org/licenses/>. */
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>
26 #define TIMEOUT 15
28 static void
29 test_child (void)
31 /* Wait a second to be sure the parent set his variables before we
32 produce a SIGCHLD. */
33 sleep (1);
35 /* First thing, we stop ourselves. */
36 raise (SIGSTOP);
38 /* Hey, we got continued! */
39 while (1)
40 pause ();
43 #ifndef WEXITED
44 # define WEXITED 0
45 # define WCONTINUED 0
46 # define WSTOPPED WUNTRACED
47 #endif
49 static sig_atomic_t expecting_sigchld, spurious_sigchld;
50 #ifdef SA_SIGINFO
51 static siginfo_t sigchld_info;
53 static void
54 sigchld (int signo, siginfo_t *info, void *ctx)
56 if (signo != SIGCHLD)
58 printf ("SIGCHLD handler got signal %d instead!\n", signo);
59 _exit (EXIT_FAILURE);
62 if (! expecting_sigchld)
64 spurious_sigchld = 1;
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);
68 else
70 sigchld_info = *info;
71 expecting_sigchld = 0;
75 static void
76 check_sigchld (const char *phase, int *ok, int code, int status, pid_t pid)
78 if (expecting_sigchld)
80 printf ("missing SIGCHLD on %s\n", phase);
81 *ok = EXIT_FAILURE;
82 expecting_sigchld = 0;
83 return;
86 if (sigchld_info.si_signo != SIGCHLD)
88 printf ("SIGCHLD for %s signal %d\n", phase, sigchld_info.si_signo);
89 *ok = EXIT_FAILURE;
91 if (sigchld_info.si_code != code)
93 printf ("SIGCHLD for %s code %d\n", phase, sigchld_info.si_code);
94 *ok = EXIT_FAILURE;
96 if (sigchld_info.si_status != status)
98 printf ("SIGCHLD for %s status %d\n", phase, sigchld_info.si_status);
99 *ok = EXIT_FAILURE;
101 if (sigchld_info.si_pid != pid)
103 printf ("SIGCHLD for %s pid %d\n", phase, sigchld_info.si_pid);
104 *ok = EXIT_FAILURE;
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
113 static int
114 do_test (int argc, char *argv[])
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)
122 printf ("setting SIGCHLD handler: %m\n");
123 return EXIT_FAILURE;
125 #endif
127 expecting_sigchld = 1;
129 pid_t pid = fork ();
130 if (pid < 0)
132 printf ("fork: %m\n");
133 return EXIT_FAILURE;
135 else if (pid == 0)
137 test_child ();
138 _exit (127);
141 int status = EXIT_SUCCESS;
142 #define RETURN(ok) \
143 do { if (status == EXIT_SUCCESS) status = (ok); goto out; } while (0)
145 /* Give the child a chance to stop. */
146 sleep (3);
148 CHECK_SIGCHLD ("stopped (before waitid)", CLD_STOPPED, SIGSTOP);
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)
156 default:
157 printf ("waitid returned bogus value %d\n", fail);
158 RETURN (EXIT_FAILURE);
159 case -1:
160 printf ("waitid WNOHANG on stopped: %m\n");
161 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
162 case 0:
163 if (info.si_signo == 0)
164 break;
165 if (info.si_signo == SIGCHLD)
166 printf ("waitid WNOHANG on stopped status %d\n", info.si_status);
167 else
168 printf ("waitid WNOHANG on stopped signal %d\n", info.si_signo);
169 RETURN (EXIT_FAILURE);
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)
179 default:
180 printf ("waitid WSTOPPED|WNOHANG returned bogus value %d\n", fail);
181 RETURN (EXIT_FAILURE);
182 case -1:
183 printf ("waitid WSTOPPED|WNOHANG on stopped: %m\n");
184 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
185 case 0:
186 if (info.si_signo != SIGCHLD)
188 printf ("waitid WSTOPPED|WNOHANG on stopped signal %d\n",
189 info.si_signo);
190 RETURN (EXIT_FAILURE);
192 if (info.si_code != CLD_STOPPED)
194 printf ("waitid WSTOPPED|WNOHANG on stopped code %d\n",
195 info.si_code);
196 RETURN (EXIT_FAILURE);
198 if (info.si_status != SIGSTOP)
200 printf ("waitid WSTOPPED|WNOHANG on stopped status %d\n",
201 info.si_status);
202 RETURN (EXIT_FAILURE);
204 if (info.si_pid != pid)
206 printf ("waitid WSTOPPED|WNOHANG on stopped pid %d != %d\n",
207 info.si_pid, pid);
208 RETURN (EXIT_FAILURE);
212 expecting_sigchld = WCONTINUED != 0;
214 if (kill (pid, SIGCONT) != 0)
216 printf ("kill (%d, SIGCONT): %m\n", pid);
217 RETURN (EXIT_FAILURE);
220 /* Wait for the child to have continued. */
221 sleep (2);
223 #if WCONTINUED != 0
224 if (expecting_sigchld)
226 printf ("no SIGCHLD seen for SIGCONT (optional)\n");
227 expecting_sigchld = 0;
229 else
230 CHECK_SIGCHLD ("continued (before waitid)", CLD_CONTINUED, SIGCONT);
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)
238 default:
239 printf ("waitid WCONTINUED|WNOWAIT returned bogus value %d\n", fail);
240 RETURN (EXIT_FAILURE);
241 case -1:
242 printf ("waitid WCONTINUED|WNOWAIT on continued: %m\n");
243 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
244 case 0:
245 if (info.si_signo != SIGCHLD)
247 printf ("waitid WCONTINUED|WNOWAIT on continued signal %d\n",
248 info.si_signo);
249 RETURN (EXIT_FAILURE);
251 if (info.si_code != CLD_CONTINUED)
253 printf ("waitid WCONTINUED|WNOWAIT on continued code %d\n",
254 info.si_code);
255 RETURN (EXIT_FAILURE);
257 if (info.si_status != SIGCONT)
259 printf ("waitid WCONTINUED|WNOWAIT on continued status %d\n",
260 info.si_status);
261 RETURN (EXIT_FAILURE);
263 if (info.si_pid != pid)
265 printf ("waitid WCONTINUED|WNOWAIT on continued pid %d != %d\n",
266 info.si_pid, pid);
267 RETURN (EXIT_FAILURE);
271 /* That should leave the CLD_CONTINUED state waiting to be seen again. */
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)
278 default:
279 printf ("waitid WCONTINUED returned bogus value %d\n", fail);
280 RETURN (EXIT_FAILURE);
281 case -1:
282 printf ("waitid WCONTINUED on continued: %m\n");
283 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
284 case 0:
285 if (info.si_signo != SIGCHLD)
287 printf ("waitid WCONTINUED on continued signal %d\n", info.si_signo);
288 RETURN (EXIT_FAILURE);
290 if (info.si_code != CLD_CONTINUED)
292 printf ("waitid WCONTINUED on continued code %d\n", info.si_code);
293 RETURN (EXIT_FAILURE);
295 if (info.si_status != SIGCONT)
297 printf ("waitid WCONTINUED on continued status %d\n",
298 info.si_status);
299 RETURN (EXIT_FAILURE);
301 if (info.si_pid != pid)
303 printf ("waitid WCONTINUED on continued pid %d != %d\n",
304 info.si_pid, pid);
305 RETURN (EXIT_FAILURE);
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)
314 default:
315 printf ("waitid returned bogus value %d\n", fail);
316 RETURN (EXIT_FAILURE);
317 case -1:
318 printf ("waitid WCONTINUED|WNOHANG on waited continued: %m\n");
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)
324 printf ("waitid WCONTINUED|WNOHANG on waited continued status %d\n",
325 info.si_status);
326 else
327 printf ("waitid WCONTINUED|WNOHANG on waited continued signal %d\n",
328 info.si_signo);
329 RETURN (EXIT_FAILURE);
332 /* Now stop him again and test waitpid with WCONTINUED. */
333 expecting_sigchld = 1;
334 if (kill (pid, SIGSTOP) != 0)
336 printf ("kill (%d, SIGSTOP): %m\n", pid);
337 RETURN (EXIT_FAILURE);
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);
346 pid_t wpid = waitpid (pid, &fail, WUNTRACED);
347 if (wpid < 0)
349 printf ("waitpid WUNTRACED on stopped: %m\n");
350 RETURN (EXIT_FAILURE);
352 else if (wpid != pid)
354 printf ("waitpid WUNTRACED on stopped returned %d != %d (status %x)\n",
355 wpid, pid, fail);
356 RETURN (EXIT_FAILURE);
358 else if (!WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
359 || WIFCONTINUED (fail) || WSTOPSIG (fail) != SIGSTOP)
361 printf ("waitpid WUNTRACED on stopped: status %x\n", fail);
362 RETURN (EXIT_FAILURE);
364 CHECK_SIGCHLD ("stopped (after waitpid)", CLD_STOPPED, SIGSTOP);
366 expecting_sigchld = 1;
367 if (kill (pid, SIGCONT) != 0)
369 printf ("kill (%d, SIGCONT): %m\n", pid);
370 RETURN (EXIT_FAILURE);
373 /* Wait for the child to have continued. */
374 sleep (2);
376 if (expecting_sigchld)
378 printf ("no SIGCHLD seen for SIGCONT (optional)\n");
379 expecting_sigchld = 0;
381 else
382 CHECK_SIGCHLD ("continued (before waitpid)", CLD_CONTINUED, SIGCONT);
384 wpid = waitpid (pid, &fail, WCONTINUED);
385 if (wpid < 0)
387 if (errno == EINVAL)
388 printf ("waitpid does not support WCONTINUED\n");
389 else
391 printf ("waitpid WCONTINUED on continued: %m\n");
392 RETURN (EXIT_FAILURE);
395 else if (wpid != pid)
397 printf ("\
398 waitpid WCONTINUED on continued returned %d != %d (status %x)\n",
399 wpid, pid, fail);
400 RETURN (EXIT_FAILURE);
402 else if (WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
403 || !WIFCONTINUED (fail))
405 printf ("waitpid WCONTINUED on continued: status %x\n", fail);
406 RETURN (EXIT_FAILURE);
408 #endif
410 expecting_sigchld = 1;
412 /* Die, child, die! */
413 if (kill (pid, SIGKILL) != 0)
415 printf ("kill (%d, SIGKILL): %m\n", pid);
416 RETURN (EXIT_FAILURE);
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)
426 default:
427 printf ("waitid WNOWAIT returned bogus value %d\n", fail);
428 RETURN (EXIT_FAILURE);
429 case -1:
430 printf ("waitid WNOWAIT on killed: %m\n");
431 RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
432 case 0:
433 if (info.si_signo != SIGCHLD)
435 printf ("waitid WNOWAIT on killed signal %d\n", info.si_signo);
436 RETURN (EXIT_FAILURE);
438 if (info.si_code != CLD_KILLED)
440 printf ("waitid WNOWAIT on killed code %d\n", info.si_code);
441 RETURN (EXIT_FAILURE);
443 if (info.si_status != SIGKILL)
445 printf ("waitid WNOWAIT on killed status %d\n", info.si_status);
446 RETURN (EXIT_FAILURE);
448 if (info.si_pid != pid)
450 printf ("waitid WNOWAIT on killed pid %d != %d\n", info.si_pid, pid);
451 RETURN (EXIT_FAILURE);
454 #else
455 /* Allow enough time to be sure the child died; we didn't synchronize. */
456 sleep (2);
457 #endif
459 CHECK_SIGCHLD ("killed", CLD_KILLED, SIGKILL);
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)
467 default:
468 printf ("waitid WNOHANG returned bogus value %d\n", fail);
469 RETURN (EXIT_FAILURE);
470 case -1:
471 printf ("waitid WNOHANG on killed: %m\n");
472 RETURN (EXIT_FAILURE);
473 case 0:
474 if (info.si_signo != SIGCHLD)
476 printf ("waitid WNOHANG on killed signal %d\n", info.si_signo);
477 RETURN (EXIT_FAILURE);
479 if (info.si_code != CLD_KILLED)
481 printf ("waitid WNOHANG on killed code %d\n", info.si_code);
482 RETURN (EXIT_FAILURE);
484 if (info.si_status != SIGKILL)
486 printf ("waitid WNOHANG on killed status %d\n", info.si_status);
487 RETURN (EXIT_FAILURE);
489 if (info.si_pid != pid)
491 printf ("waitid WNOHANG on killed pid %d != %d\n", info.si_pid, pid);
492 RETURN (EXIT_FAILURE);
496 fail = waitid (P_PID, pid, &info, WEXITED);
497 if (fail == -1)
499 if (errno != ECHILD)
501 printf ("waitid WEXITED on killed: %m\n");
502 RETURN (EXIT_FAILURE);
505 else
507 printf ("waitid WEXITED returned bogus value %d\n", fail);
508 RETURN (EXIT_FAILURE);
511 #undef RETURN
512 out:
513 if (spurious_sigchld)
514 status = EXIT_FAILURE;
515 signal (SIGCHLD, SIG_IGN);
516 kill (pid, SIGKILL); /* Make sure it's dead if we bailed early. */
517 return status;
520 #include "../test-skeleton.c"