2 Copyright (C) 2004 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
32 /* Wait a second to be sure the parent set his variables before we
36 /* First thing, we stop ourselves. */
39 /* Hey, we got continued! */
47 # define WSTOPPED WUNTRACED
50 static sig_atomic_t expecting_sigchld
, spurious_sigchld
;
52 static siginfo_t sigchld_info
;
55 sigchld (int signo
, siginfo_t
*info
, void *ctx
)
59 error (0, 0, "SIGCHLD handler got signal %d instead!", signo
);
63 if (! expecting_sigchld
)
67 "spurious SIGCHLD: signo %d code %d status %d pid %d\n",
68 info
->si_signo
, info
->si_code
, info
->si_status
, info
->si_pid
);
73 expecting_sigchld
= 0;
78 check_sigchld (const char *phase
, int *ok
, int code
, int status
, pid_t pid
)
80 if (expecting_sigchld
)
82 error (0, 0, "missing SIGCHLD on %s", phase
);
84 expecting_sigchld
= 0;
88 if (sigchld_info
.si_signo
!= SIGCHLD
)
90 error (0, 0, "SIGCHLD for %s signal %d", phase
, sigchld_info
.si_signo
);
93 if (sigchld_info
.si_code
!= code
)
95 error (0, 0, "SIGCHLD for %s code %d", phase
, sigchld_info
.si_code
);
98 if (sigchld_info
.si_status
!= status
)
100 error (0, 0, "SIGCHLD for %s status %d", phase
, sigchld_info
.si_status
);
103 if (sigchld_info
.si_pid
!= pid
)
105 error (0, 0, "SIGCHLD for %s pid %d", phase
, sigchld_info
.si_pid
);
109 # define CHECK_SIGCHLD(phase, code_check, status_check) \
110 check_sigchld ((phase), &status, (code_check), (status_check), pid)
112 # define CHECK_SIGCHLD(phase, code, status) ((void) 0)
116 do_test (int argc
, char *argv
[])
120 sa
.sa_flags
= SA_SIGINFO
|SA_RESTART
;
121 sa
.sa_sigaction
= &sigchld
;
122 if (sigemptyset (&sa
.sa_mask
) < 0 || sigaction (SIGCHLD
, &sa
, NULL
) < 0)
124 error (0, errno
, "setting SIGCHLD handler");
129 expecting_sigchld
= 1;
134 error (0, errno
, "fork");
143 int status
= EXIT_SUCCESS
;
145 do { if (status == EXIT_SUCCESS) status = (ok); goto out; } while (0)
147 /* Give the child a chance to stop. */
150 CHECK_SIGCHLD ("stopped", CLD_STOPPED
, SIGSTOP
);
152 /* Now try a wait that should not succeed. */
154 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
155 int fail
= waitid (P_PID
, pid
, &info
, WEXITED
|WCONTINUED
|WNOHANG
);
159 error (0, 0, "waitid returned bogus value %d\n", fail
);
160 RETURN (EXIT_FAILURE
);
162 error (0, errno
, "waitid WNOHANG on stopped");
163 RETURN (errno
== ENOTSUP
? EXIT_SUCCESS
: EXIT_FAILURE
);
165 if (info
.si_signo
== 0)
167 if (info
.si_signo
== SIGCHLD
)
168 error (0, 0, "waitid WNOHANG on stopped status %d\n", info
.si_status
);
170 error (0, 0, "waitid WNOHANG on stopped signal %d\n", info
.si_signo
);
171 RETURN (EXIT_FAILURE
);
174 /* Next the wait that should succeed right away. */
175 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
178 fail
= waitid (P_PID
, pid
, &info
, WSTOPPED
|WNOHANG
);
182 error (0, 0, "waitid WSTOPPED|WNOHANG returned bogus value %d\n", fail
);
183 RETURN (EXIT_FAILURE
);
185 error (0, errno
, "waitid WSTOPPED|WNOHANG on stopped");
186 RETURN (errno
== ENOTSUP
? EXIT_SUCCESS
: EXIT_FAILURE
);
188 if (info
.si_signo
!= SIGCHLD
)
190 error (0, 0, "waitid WSTOPPED|WNOHANG on stopped signal %d\n",
192 RETURN (EXIT_FAILURE
);
194 if (info
.si_code
!= CLD_STOPPED
)
196 error (0, 0, "waitid WSTOPPED|WNOHANG on stopped code %d\n",
198 RETURN (EXIT_FAILURE
);
200 if (info
.si_status
!= SIGSTOP
)
202 error (0, 0, "waitid WSTOPPED|WNOHANG on stopped status %d\n",
204 RETURN (EXIT_FAILURE
);
206 if (info
.si_pid
!= pid
)
208 error (0, 0, "waitid WSTOPPED|WNOHANG on stopped pid %d != %d\n",
210 RETURN (EXIT_FAILURE
);
214 expecting_sigchld
= WCONTINUED
!= 0;
216 if (kill (pid
, SIGCONT
) != 0)
218 error (0, errno
, "kill (%d, SIGCONT)", pid
);
219 RETURN (EXIT_FAILURE
);
222 /* Wait for the child to have continued. */
226 if (expecting_sigchld
)
228 error (0, 0, "no SIGCHLD seen for SIGCONT (optional)");
229 expecting_sigchld
= 0;
232 CHECK_SIGCHLD ("continued", CLD_CONTINUED
, SIGCONT
);
234 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
237 fail
= waitid (P_PID
, pid
, &info
, WCONTINUED
|WNOWAIT
);
242 "waitid WCONTINUED|WNOWAIT returned bogus value %d\n", fail
);
243 RETURN (EXIT_FAILURE
);
245 error (0, errno
, "waitid WCONTINUED|WNOWAIT on continued");
246 RETURN (errno
== ENOTSUP
? EXIT_SUCCESS
: EXIT_FAILURE
);
248 if (info
.si_signo
!= SIGCHLD
)
250 error (0, 0, "waitid WCONTINUED|WNOWAIT on continued signal %d\n",
252 RETURN (EXIT_FAILURE
);
254 if (info
.si_code
!= CLD_CONTINUED
)
256 error (0, 0, "waitid WCONTINUED|WNOWAIT on continued code %d\n",
258 RETURN (EXIT_FAILURE
);
260 if (info
.si_status
!= SIGCONT
)
262 error (0, 0, "waitid WCONTINUED|WNOWAIT on continued status %d\n",
264 RETURN (EXIT_FAILURE
);
266 if (info
.si_pid
!= pid
)
268 error (0, 0, "waitid WCONTINUED|WNOWAIT on continued pid %d != %d\n",
270 RETURN (EXIT_FAILURE
);
274 /* That should leave the CLD_CONTINUED state waiting to be seen again. */
275 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
278 fail
= waitid (P_PID
, pid
, &info
, WCONTINUED
);
282 error (0, 0, "waitid WCONTINUED returned bogus value %d\n", fail
);
283 RETURN (EXIT_FAILURE
);
285 error (0, errno
, "waitid WCONTINUED on continued");
286 RETURN (errno
== ENOTSUP
? EXIT_SUCCESS
: EXIT_FAILURE
);
288 if (info
.si_signo
!= SIGCHLD
)
290 error (0, 0, "waitid WCONTINUED on continued signal %d\n",
292 RETURN (EXIT_FAILURE
);
294 if (info
.si_code
!= CLD_CONTINUED
)
296 error (0, 0, "waitid WCONTINUED on continued code %d\n",
298 RETURN (EXIT_FAILURE
);
300 if (info
.si_status
!= SIGCONT
)
302 error (0, 0, "waitid WCONTINUED on continued status %d\n",
304 RETURN (EXIT_FAILURE
);
306 if (info
.si_pid
!= pid
)
308 error (0, 0, "waitid WCONTINUED on continued pid %d != %d\n",
310 RETURN (EXIT_FAILURE
);
314 /* Now try a wait that should not succeed. */
315 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
316 fail
= waitid (P_PID
, pid
, &info
, WCONTINUED
|WNOHANG
);
320 error (0, 0, "waitid returned bogus value %d\n", fail
);
321 RETURN (EXIT_FAILURE
);
323 error (0, errno
, "waitid WCONTINUED|WNOHANG on waited continued");
324 RETURN (errno
== ENOTSUP
? EXIT_SUCCESS
: EXIT_FAILURE
);
326 if (info
.si_signo
== 0)
328 if (info
.si_signo
== SIGCHLD
)
330 "waitid WCONTINUED|WNOHANG on waited continued status %d\n",
334 "waitid WCONTINUED|WNOHANG on waited continued signal %d\n",
336 RETURN (EXIT_FAILURE
);
339 /* Now stop him again and test waitpid with WCONTINUED. */
340 expecting_sigchld
= 1;
341 if (kill (pid
, SIGSTOP
) != 0)
343 error (0, errno
, "kill (%d, SIGSTOP)", pid
);
344 RETURN (EXIT_FAILURE
);
346 pid_t wpid
= waitpid (pid
, &fail
, WUNTRACED
);
349 error (0, errno
, "waitpid WUNTRACED on stopped");
350 RETURN (EXIT_FAILURE
);
352 else if (wpid
!= pid
)
355 "waitpid WUNTRACED on stopped returned %d != %d (status %x)",
357 RETURN (EXIT_FAILURE
);
359 else if (!WIFSTOPPED (fail
) || WIFSIGNALED (fail
) || WIFEXITED (fail
)
360 || WIFCONTINUED (fail
) || WSTOPSIG (fail
) != SIGSTOP
)
362 error (0, 0, "waitpid WUNTRACED on stopped: status %x", fail
);
363 RETURN (EXIT_FAILURE
);
365 CHECK_SIGCHLD ("stopped", CLD_STOPPED
, SIGSTOP
);
367 expecting_sigchld
= 1;
368 if (kill (pid
, SIGCONT
) != 0)
370 error (0, errno
, "kill (%d, SIGCONT)", pid
);
371 RETURN (EXIT_FAILURE
);
374 /* Wait for the child to have continued. */
377 if (expecting_sigchld
)
379 error (0, 0, "no SIGCHLD seen for SIGCONT (optional)");
380 expecting_sigchld
= 0;
383 CHECK_SIGCHLD ("continued", CLD_CONTINUED
, SIGCONT
);
385 wpid
= waitpid (pid
, &fail
, WCONTINUED
);
389 error (0, 0, "waitpid does not support WCONTINUED");
392 error (0, errno
, "waitpid WCONTINUED on continued");
393 RETURN (EXIT_FAILURE
);
396 else if (wpid
!= pid
)
399 "waitpid WCONTINUED on continued returned %d != %d (status %x)",
401 RETURN (EXIT_FAILURE
);
403 else if (WIFSTOPPED (fail
) || WIFSIGNALED (fail
) || WIFEXITED (fail
)
404 || !WIFCONTINUED (fail
))
406 error (0, 0, "waitpid WCONTINUED on continued: status %x", fail
);
407 RETURN (EXIT_FAILURE
);
411 expecting_sigchld
= 1;
413 /* Die, child, die! */
414 if (kill (pid
, SIGKILL
) != 0)
416 error (0, errno
, "kill (%d, SIGKILL)", pid
);
417 RETURN (EXIT_FAILURE
);
421 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
424 fail
= waitid (P_PID
, pid
, &info
, WEXITED
|WNOWAIT
);
428 error (0, 0, "waitid WNOWAIT returned bogus value %d\n", fail
);
429 RETURN (EXIT_FAILURE
);
431 error (0, errno
, "waitid WNOWAIT on killed");
432 RETURN (errno
== ENOTSUP
? EXIT_SUCCESS
: EXIT_FAILURE
);
434 if (info
.si_signo
!= SIGCHLD
)
436 error (0, 0, "waitid WNOWAIT on killed signal %d\n",
438 RETURN (EXIT_FAILURE
);
440 if (info
.si_code
!= CLD_KILLED
)
442 error (0, 0, "waitid WNOWAIT on killed code %d\n",
444 RETURN (EXIT_FAILURE
);
446 if (info
.si_status
!= SIGKILL
)
448 error (0, 0, "waitid WNOWAIT on killed status %d\n",
450 RETURN (EXIT_FAILURE
);
452 if (info
.si_pid
!= pid
)
454 error (0, 0, "waitid WNOWAIT on killed pid %d != %d\n",
456 RETURN (EXIT_FAILURE
);
460 /* Allow enough time to be sure the child died; we didn't synchronize. */
464 CHECK_SIGCHLD ("killed", CLD_KILLED
, SIGKILL
);
466 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
469 fail
= waitid (P_PID
, pid
, &info
, WEXITED
|WNOHANG
);
473 error (0, 0, "waitid WNOHANG returned bogus value %d\n", fail
);
474 RETURN (EXIT_FAILURE
);
476 error (0, errno
, "waitid WNOHANG on killed");
477 RETURN (EXIT_FAILURE
);
479 if (info
.si_signo
!= SIGCHLD
)
481 error (0, 0, "waitid WNOHANG on killed signal %d\n",
483 RETURN (EXIT_FAILURE
);
485 if (info
.si_code
!= CLD_KILLED
)
487 error (0, 0, "waitid WNOHANG on killed code %d\n",
489 RETURN (EXIT_FAILURE
);
491 if (info
.si_status
!= SIGKILL
)
493 error (0, 0, "waitid WNOHANG on killed status %d\n",
495 RETURN (EXIT_FAILURE
);
497 if (info
.si_pid
!= pid
)
499 error (0, 0, "waitid WNOHANG on killed pid %d != %d\n",
501 RETURN (EXIT_FAILURE
);
505 fail
= waitid (P_PID
, pid
, &info
, WEXITED
);
510 error (0, errno
, "waitid WEXITED on killed");
511 RETURN (EXIT_FAILURE
);
516 error (0, 0, "waitid WEXITED returned bogus value %d\n", fail
);
517 RETURN (EXIT_FAILURE
);
522 if (spurious_sigchld
)
523 status
= EXIT_FAILURE
;
524 signal (SIGCHLD
, SIG_IGN
);
525 kill (pid
, SIGKILL
); /* Make sure it's dead if we bailed early. */
529 #include "../test-skeleton.c"