posix: Remove alloca usage for internal fnmatch implementation
[platform/upstream/glibc.git] / posix / tst-wait-skeleton.c
1 /* Test framework for wait3 and wait4.
2    Copyright (C) 2020-2021 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 <sys/resource.h>
25 #include <signal.h>
26 #include <time.h>
27 #include <stdatomic.h>
28 #include <stdbool.h>
29
30 #include <support/xsignal.h>
31 #include <support/xunistd.h>
32 #include <support/check.h>
33 #include <support/process_state.h>
34
35 static void
36 test_child (void)
37 {
38   /* First thing, we stop ourselves.  */
39   raise (SIGSTOP);
40
41   /* Hey, we got continued!  */
42   while (1)
43     pause ();
44 }
45
46 #ifndef WEXITED
47 # define WEXITED        0
48 # define WCONTINUED     0
49 # define WSTOPPED       WUNTRACED
50 #endif
51
52 /* Set with only SIGCHLD on do_test_waitid.  */
53 static sigset_t chldset;
54
55 #ifdef SA_SIGINFO
56 static void
57 sigchld (int signo, siginfo_t *info, void *ctx)
58 {
59 }
60 #endif
61
62 static void
63 check_sigchld (int code, int status, pid_t pid)
64 {
65 #ifdef SA_SIGINFO
66   siginfo_t siginfo;
67   TEST_COMPARE (sigwaitinfo (&chldset, &siginfo), SIGCHLD);
68
69   TEST_COMPARE (siginfo.si_signo, SIGCHLD);
70   TEST_COMPARE (siginfo.si_code, code);
71   TEST_COMPARE (siginfo.si_status, status);
72   TEST_COMPARE (siginfo.si_pid, pid);
73 #endif
74 }
75
76 static int
77 do_test_wait (pid_t pid)
78 {
79   /* Adding process_state_tracing_stop ('t') allows the test to work under
80      trace programs such as ptrace.  */
81   enum support_process_state stop_state = support_process_state_stopped
82                                           | support_process_state_tracing_stop;
83
84   support_process_state_wait (pid, stop_state);
85
86   check_sigchld (CLD_STOPPED, SIGSTOP, pid);
87
88   pid_t ret;
89   int wstatus;
90   struct rusage rusage;
91
92   ret = WAIT_CALL (pid, &wstatus, WUNTRACED|WCONTINUED|WNOHANG, NULL);
93   if (ret == -1 && errno == ENOTSUP)
94     FAIL_RET ("waitid WNOHANG on stopped: %m");
95   TEST_COMPARE (ret, pid);
96   TEST_VERIFY (WIFSTOPPED (wstatus));
97
98   /* Issue again but with struct rusage input.  */
99   ret = WAIT_CALL (pid, &wstatus, WUNTRACED|WCONTINUED|WNOHANG, &rusage);
100   /* With WNOHANG and WUNTRACED, if the children has not changes its state
101      since previous call the expected result it 0.  */
102   TEST_COMPARE (ret, 0);
103
104   /* Some sanity tests to check if 'wtatus' and 'rusage' possible
105      input values.  */
106   ret = WAIT_CALL (pid, NULL, WUNTRACED|WCONTINUED|WNOHANG, &rusage);
107   TEST_COMPARE (ret, 0);
108   ret = WAIT_CALL (pid, NULL, WUNTRACED|WCONTINUED|WNOHANG, NULL);
109   TEST_COMPARE (ret, 0);
110
111   if (kill (pid, SIGCONT) != 0)
112     FAIL_RET ("kill (%d, SIGCONT): %m\n", pid);
113
114   /* Wait for the child to have continued.  */
115   support_process_state_wait (pid, support_process_state_sleeping);
116
117 #if WCONTINUED != 0
118   check_sigchld (CLD_CONTINUED, SIGCONT, pid);
119
120   ret = WAIT_CALL (pid, &wstatus, WCONTINUED|WNOHANG, NULL);
121   TEST_COMPARE (ret, pid);
122   TEST_VERIFY (WIFCONTINUED (wstatus));
123
124   /* Issue again but with struct rusage input.  */
125   ret = WAIT_CALL (pid, &wstatus, WUNTRACED|WCONTINUED|WNOHANG, &rusage);
126   /* With WNOHANG and WUNTRACED, if the children has not changes its state
127      since previous call the expected result it 0.  */
128   TEST_COMPARE (ret, 0);
129
130   /* Now stop him again and test waitpid with WCONTINUED.  */
131   if (kill (pid, SIGSTOP) != 0)
132     FAIL_RET ("kill (%d, SIGSTOP): %m\n", pid);
133
134   /* Wait the child stop.  The waitid call below will block until it has
135      stopped, but if we are real quick and enter the waitid system call
136      before the SIGCHLD has been generated, then it will be discarded and
137      never delivered.  */
138   support_process_state_wait (pid, stop_state);
139
140   ret = WAIT_CALL (pid, &wstatus, WUNTRACED|WNOHANG, &rusage);
141   TEST_COMPARE (ret, pid);
142
143   check_sigchld (CLD_STOPPED, SIGSTOP, pid);
144
145   if (kill (pid, SIGCONT) != 0)
146     FAIL_RET ("kill (%d, SIGCONT): %m\n", pid);
147
148   /* Wait for the child to have continued.  */
149   support_process_state_wait (pid, support_process_state_sleeping);
150
151   check_sigchld (CLD_CONTINUED, SIGCONT, pid);
152
153   ret = WAIT_CALL (pid, &wstatus, WCONTINUED|WNOHANG, NULL);
154   TEST_COMPARE (ret, pid);
155   TEST_VERIFY (WIFCONTINUED (wstatus));
156 #endif
157
158   /* Die, child, die!  */
159   if (kill (pid, SIGKILL) != 0)
160     FAIL_RET ("kill (%d, SIGKILL): %m\n", pid);
161
162   support_process_state_wait (pid, support_process_state_zombie);
163
164   ret = WAIT_CALL (pid, &wstatus, 0, &rusage);
165   TEST_COMPARE (ret, pid);
166   TEST_VERIFY (WIFSIGNALED (wstatus));
167   TEST_VERIFY (WTERMSIG (wstatus) == SIGKILL);
168
169   check_sigchld (CLD_KILLED, SIGKILL, pid);
170
171   return 0;
172 }
173
174 static int
175 do_test (void)
176 {
177 #ifdef SA_SIGINFO
178   {
179     struct sigaction sa;
180     sa.sa_flags = SA_SIGINFO | SA_RESTART;
181     sa.sa_sigaction = sigchld;
182     sigemptyset (&sa.sa_mask);
183     xsigaction (SIGCHLD, &sa, NULL);
184   }
185 #endif
186
187   sigemptyset (&chldset);
188   sigaddset (&chldset, SIGCHLD);
189
190   /* The SIGCHLD shall has blocked at the time of the call to sigwait;
191      otherwise, the behavior is undefined.  */
192   sigprocmask (SIG_BLOCK, &chldset, NULL);
193
194   pid_t pid = xfork ();
195   if (pid == 0)
196     {
197       test_child ();
198       _exit (127);
199     }
200
201   do_test_wait (pid);
202
203   xsignal (SIGCHLD, SIG_IGN);
204   kill (pid, SIGKILL);          /* Make sure it's dead if we bailed early.  */
205
206   return 0;
207 }
208
209 #include <support/test-driver.c>