S/390: Fix uc_link == NULL handling for makecontext
[platform/upstream/glibc.git] / posix / tst-waitid.c
1 /* Tests for waitid.
2    Copyright (C) 2004 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    <http://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 #define TIMEOUT 15
27
28 static void
29 test_child (void)
30 {
31   /* Wait a second to be sure the parent set his variables before we
32      produce a SIGCHLD.  */
33   sleep (1);
34
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
49 static sig_atomic_t expecting_sigchld, spurious_sigchld;
50 #ifdef SA_SIGINFO
51 static siginfo_t sigchld_info;
52
53 static void
54 sigchld (int signo, siginfo_t *info, void *ctx)
55 {
56   if (signo != SIGCHLD)
57     {
58       printf ("SIGCHLD handler got signal %d instead!\n", signo);
59       _exit (EXIT_FAILURE);
60     }
61
62   if (! expecting_sigchld)
63     {
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);
67     }
68   else
69     {
70       sigchld_info = *info;
71       expecting_sigchld = 0;
72     }
73 }
74
75 static void
76 check_sigchld (const char *phase, int *ok, int code, int status, pid_t pid)
77 {
78   if (expecting_sigchld)
79     {
80       printf ("missing SIGCHLD on %s\n", phase);
81       *ok = EXIT_FAILURE;
82       expecting_sigchld = 0;
83       return;
84     }
85
86   if (sigchld_info.si_signo != SIGCHLD)
87     {
88       printf ("SIGCHLD for %s signal %d\n", phase, sigchld_info.si_signo);
89       *ok = EXIT_FAILURE;
90     }
91   if (sigchld_info.si_code != code)
92     {
93       printf ("SIGCHLD for %s code %d\n", phase, sigchld_info.si_code);
94       *ok = EXIT_FAILURE;
95     }
96   if (sigchld_info.si_status != status)
97     {
98       printf ("SIGCHLD for %s status %d\n", phase, sigchld_info.si_status);
99       *ok = EXIT_FAILURE;
100     }
101   if (sigchld_info.si_pid != pid)
102     {
103       printf ("SIGCHLD for %s pid %d\n", phase, sigchld_info.si_pid);
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
113 static int
114 do_test (int argc, char *argv[])
115 {
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     {
122       printf ("setting SIGCHLD handler: %m\n");
123       return EXIT_FAILURE;
124     }
125 #endif
126
127   expecting_sigchld = 1;
128
129   pid_t pid = fork ();
130   if (pid < 0)
131     {
132       printf ("fork: %m\n");
133       return EXIT_FAILURE;
134     }
135   else if (pid == 0)
136     {
137       test_child ();
138       _exit (127);
139     }
140
141   int status = EXIT_SUCCESS;
142 #define RETURN(ok) \
143     do { if (status == EXIT_SUCCESS) status = (ok); goto out; } while (0)
144
145   /* Give the child a chance to stop.  */
146   sleep (3);
147
148   CHECK_SIGCHLD ("stopped", CLD_STOPPED, SIGSTOP);
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:
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);
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:
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)
187         {
188           printf ("waitid WSTOPPED|WNOHANG on stopped signal %d\n",
189                   info.si_signo);
190           RETURN (EXIT_FAILURE);
191         }
192       if (info.si_code != CLD_STOPPED)
193         {
194           printf ("waitid WSTOPPED|WNOHANG on stopped code %d\n",
195                   info.si_code);
196           RETURN (EXIT_FAILURE);
197         }
198       if (info.si_status != SIGSTOP)
199         {
200           printf ("waitid WSTOPPED|WNOHANG on stopped status %d\n",
201                   info.si_status);
202           RETURN (EXIT_FAILURE);
203         }
204       if (info.si_pid != pid)
205         {
206           printf ("waitid WSTOPPED|WNOHANG on stopped pid %d != %d\n",
207                   info.si_pid, pid);
208           RETURN (EXIT_FAILURE);
209         }
210     }
211
212   expecting_sigchld = WCONTINUED != 0;
213
214   if (kill (pid, SIGCONT) != 0)
215     {
216       printf ("kill (%d, SIGCONT): %m\n", pid);
217       RETURN (EXIT_FAILURE);
218     }
219
220   /* Wait for the child to have continued.  */
221   sleep (2);
222
223 #if WCONTINUED != 0
224   if (expecting_sigchld)
225     {
226       printf ("no SIGCHLD seen for SIGCONT (optional)\n");
227       expecting_sigchld = 0;
228     }
229   else
230     CHECK_SIGCHLD ("continued", CLD_CONTINUED, SIGCONT);
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:
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)
246         {
247           printf ("waitid WCONTINUED|WNOWAIT on continued signal %d\n",
248                   info.si_signo);
249           RETURN (EXIT_FAILURE);
250         }
251       if (info.si_code != CLD_CONTINUED)
252         {
253           printf ("waitid WCONTINUED|WNOWAIT on continued code %d\n",
254                   info.si_code);
255           RETURN (EXIT_FAILURE);
256         }
257       if (info.si_status != SIGCONT)
258         {
259           printf ("waitid WCONTINUED|WNOWAIT on continued status %d\n",
260                   info.si_status);
261           RETURN (EXIT_FAILURE);
262         }
263       if (info.si_pid != pid)
264         {
265           printf ("waitid WCONTINUED|WNOWAIT on continued pid %d != %d\n",
266                   info.si_pid, pid);
267           RETURN (EXIT_FAILURE);
268         }
269     }
270
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)
277     {
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)
286         {
287           printf ("waitid WCONTINUED on continued signal %d\n", info.si_signo);
288           RETURN (EXIT_FAILURE);
289         }
290       if (info.si_code != CLD_CONTINUED)
291         {
292           printf ("waitid WCONTINUED on continued code %d\n", info.si_code);
293           RETURN (EXIT_FAILURE);
294         }
295       if (info.si_status != SIGCONT)
296         {
297           printf ("waitid WCONTINUED on continued status %d\n",
298                   info.si_status);
299           RETURN (EXIT_FAILURE);
300         }
301       if (info.si_pid != pid)
302         {
303           printf ("waitid WCONTINUED on continued pid %d != %d\n",
304                   info.si_pid, pid);
305           RETURN (EXIT_FAILURE);
306         }
307     }
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:
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);
330     }
331
332   /* Now stop him again and test waitpid with WCONTINUED.  */
333   expecting_sigchld = 1;
334   if (kill (pid, SIGSTOP) != 0)
335     {
336       printf ("kill (%d, SIGSTOP): %m\n", pid);
337       RETURN (EXIT_FAILURE);
338     }
339   pid_t wpid = waitpid (pid, &fail, WUNTRACED);
340   if (wpid < 0)
341     {
342       printf ("waitpid WUNTRACED on stopped: %m\n");
343       RETURN (EXIT_FAILURE);
344     }
345   else if (wpid != pid)
346     {
347       printf ("waitpid WUNTRACED on stopped returned %d != %d (status %x)\n",
348               wpid, pid, fail);
349       RETURN (EXIT_FAILURE);
350     }
351   else if (!WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
352            || WIFCONTINUED (fail) || WSTOPSIG (fail) != SIGSTOP)
353     {
354       printf ("waitpid WUNTRACED on stopped: status %x\n", fail);
355       RETURN (EXIT_FAILURE);
356     }
357   CHECK_SIGCHLD ("stopped", CLD_STOPPED, SIGSTOP);
358
359   expecting_sigchld = 1;
360   if (kill (pid, SIGCONT) != 0)
361     {
362       printf ("kill (%d, SIGCONT): %m\n", pid);
363       RETURN (EXIT_FAILURE);
364     }
365
366   /* Wait for the child to have continued.  */
367   sleep (2);
368
369   if (expecting_sigchld)
370     {
371       printf ("no SIGCHLD seen for SIGCONT (optional)\n");
372       expecting_sigchld = 0;
373     }
374   else
375     CHECK_SIGCHLD ("continued", CLD_CONTINUED, SIGCONT);
376
377   wpid = waitpid (pid, &fail, WCONTINUED);
378   if (wpid < 0)
379     {
380       if (errno == EINVAL)
381         printf ("waitpid does not support WCONTINUED\n");
382       else
383         {
384           printf ("waitpid WCONTINUED on continued: %m\n");
385           RETURN (EXIT_FAILURE);
386         }
387     }
388   else if (wpid != pid)
389     {
390       printf ("\
391 waitpid WCONTINUED on continued returned %d != %d (status %x)\n",
392              wpid, pid, fail);
393       RETURN (EXIT_FAILURE);
394     }
395   else if (WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
396            || !WIFCONTINUED (fail))
397     {
398       printf ("waitpid WCONTINUED on continued: status %x\n", fail);
399       RETURN (EXIT_FAILURE);
400     }
401 #endif
402
403   expecting_sigchld = 1;
404
405   /* Die, child, die!  */
406   if (kill (pid, SIGKILL) != 0)
407     {
408       printf ("kill (%d, SIGKILL): %m\n", pid);
409       RETURN (EXIT_FAILURE);
410     }
411
412 #ifdef WNOWAIT
413   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
414   info.si_pid = -1;
415   info.si_status = -1;
416   fail = waitid (P_PID, pid, &info, WEXITED|WNOWAIT);
417   switch (fail)
418     {
419     default:
420       printf ("waitid WNOWAIT returned bogus value %d\n", fail);
421       RETURN (EXIT_FAILURE);
422     case -1:
423       printf ("waitid WNOWAIT on killed: %m\n");
424       RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
425     case 0:
426       if (info.si_signo != SIGCHLD)
427         {
428           printf ("waitid WNOWAIT on killed signal %d\n", info.si_signo);
429           RETURN (EXIT_FAILURE);
430         }
431       if (info.si_code != CLD_KILLED)
432         {
433           printf ("waitid WNOWAIT on killed code %d\n", info.si_code);
434           RETURN (EXIT_FAILURE);
435         }
436       if (info.si_status != SIGKILL)
437         {
438           printf ("waitid WNOWAIT on killed status %d\n", info.si_status);
439           RETURN (EXIT_FAILURE);
440         }
441       if (info.si_pid != pid)
442         {
443           printf ("waitid WNOWAIT on killed pid %d != %d\n", info.si_pid, pid);
444           RETURN (EXIT_FAILURE);
445         }
446     }
447 #else
448   /* Allow enough time to be sure the child died; we didn't synchronize.  */
449   sleep (2);
450 #endif
451
452   CHECK_SIGCHLD ("killed", CLD_KILLED, SIGKILL);
453
454   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
455   info.si_pid = -1;
456   info.si_status = -1;
457   fail = waitid (P_PID, pid, &info, WEXITED|WNOHANG);
458   switch (fail)
459     {
460     default:
461       printf ("waitid WNOHANG returned bogus value %d\n", fail);
462       RETURN (EXIT_FAILURE);
463     case -1:
464       printf ("waitid WNOHANG on killed: %m\n");
465       RETURN (EXIT_FAILURE);
466     case 0:
467       if (info.si_signo != SIGCHLD)
468         {
469           printf ("waitid WNOHANG on killed signal %d\n", info.si_signo);
470           RETURN (EXIT_FAILURE);
471         }
472       if (info.si_code != CLD_KILLED)
473         {
474           printf ("waitid WNOHANG on killed code %d\n", info.si_code);
475           RETURN (EXIT_FAILURE);
476         }
477       if (info.si_status != SIGKILL)
478         {
479           printf ("waitid WNOHANG on killed status %d\n", info.si_status);
480           RETURN (EXIT_FAILURE);
481         }
482       if (info.si_pid != pid)
483         {
484           printf ("waitid WNOHANG on killed pid %d != %d\n", info.si_pid, pid);
485           RETURN (EXIT_FAILURE);
486         }
487     }
488
489   fail = waitid (P_PID, pid, &info, WEXITED);
490   if (fail == -1)
491     {
492       if (errno != ECHILD)
493         {
494           printf ("waitid WEXITED on killed: %m\n");
495           RETURN (EXIT_FAILURE);
496         }
497     }
498   else
499     {
500       printf ("waitid WEXITED returned bogus value %d\n", fail);
501       RETURN (EXIT_FAILURE);
502     }
503
504 #undef RETURN
505  out:
506   if (spurious_sigchld)
507     status = EXIT_FAILURE;
508   signal (SIGCHLD, SIG_IGN);
509   kill (pid, SIGKILL);          /* Make sure it's dead if we bailed early.  */
510   return status;
511 }
512
513 #include "../test-skeleton.c"