linux: Decorate __libc_fatal error buffer
[glibc.git] / posix / tst-waitid.c
blob9316c2c4ff023a68fbae1983d7739833a1af5c83
1 /* Tests for waitid.
2 Copyright (C) 2004-2023 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 <https://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>
25 #include <time.h>
26 #include <stdatomic.h>
27 #include <stdbool.h>
29 #include <support/xsignal.h>
30 #include <support/xunistd.h>
31 #include <support/check.h>
32 #include <support/process_state.h>
34 static void
35 test_child (bool setgroup)
37 if (setgroup)
38 TEST_COMPARE (setpgid (0, 0), 0);
40 /* First thing, we stop ourselves. */
41 raise (SIGSTOP);
43 /* Hey, we got continued! */
44 while (1)
45 pause ();
48 #ifndef WEXITED
49 # define WEXITED 0
50 # define WCONTINUED 0
51 # define WSTOPPED WUNTRACED
52 #endif
54 /* Set with only SIGCHLD on do_test_waitid. */
55 static sigset_t chldset;
57 #ifdef SA_SIGINFO
58 static void
59 sigchld (int signo, siginfo_t *info, void *ctx)
62 #endif
64 static void
65 check_sigchld (int code, int status, pid_t pid)
67 #ifdef SA_SIGINFO
68 siginfo_t siginfo;
69 TEST_COMPARE (sigwaitinfo (&chldset, &siginfo), SIGCHLD);
71 TEST_COMPARE (siginfo.si_signo, SIGCHLD);
72 TEST_COMPARE (siginfo.si_code, code);
73 TEST_COMPARE (siginfo.si_status, status);
74 TEST_COMPARE (siginfo.si_pid, pid);
75 #endif
78 static int
79 do_test_waitd_common (idtype_t type, pid_t pid)
81 /* Adding process_state_tracing_stop ('t') allows the test to work under
82 trace programs such as ptrace. */
83 enum support_process_state stop_state = support_process_state_stopped
84 | support_process_state_tracing_stop;
86 support_process_state_wait (pid, stop_state);
88 check_sigchld (CLD_STOPPED, SIGSTOP, pid);
90 /* Now try a wait that should not succeed. */
91 siginfo_t info;
92 int fail;
94 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
95 fail = waitid (P_PID, pid, &info, WEXITED|WCONTINUED|WNOHANG);
96 if (fail == -1 && errno == ENOTSUP)
97 FAIL_RET ("waitid WNOHANG on stopped: %m");
98 TEST_COMPARE (fail, 0);
99 TEST_COMPARE (info.si_signo, 0);
101 /* Next the wait that should succeed right away. */
102 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
103 info.si_pid = -1;
104 info.si_status = -1;
105 fail = waitid (P_PID, pid, &info, WSTOPPED|WNOHANG);
106 if (fail == -1 && errno == ENOTSUP)
107 FAIL_RET ("waitid WNOHANG on stopped: %m");
108 TEST_COMPARE (fail, 0);
109 TEST_COMPARE (info.si_signo, SIGCHLD);
110 TEST_COMPARE (info.si_code, CLD_STOPPED);
111 TEST_COMPARE (info.si_status, SIGSTOP);
112 TEST_COMPARE (info.si_pid, pid);
114 if (kill (pid, SIGCONT) != 0)
115 FAIL_RET ("kill (%d, SIGCONT): %m\n", pid);
117 /* Wait for the child to have continued. */
118 support_process_state_wait (pid, support_process_state_sleeping);
120 #if WCONTINUED != 0
121 check_sigchld (CLD_CONTINUED, SIGCONT, pid);
123 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
124 info.si_pid = -1;
125 info.si_status = -1;
126 fail = waitid (P_PID, pid, &info, WCONTINUED|WNOWAIT);
127 if (fail == -1 && errno == ENOTSUP)
128 FAIL_RET ("waitid WCONTINUED|WNOWAIT on continued: %m");
129 TEST_COMPARE (fail, 0);
130 TEST_COMPARE (info.si_signo, SIGCHLD);
131 TEST_COMPARE (info.si_code, CLD_CONTINUED);
132 TEST_COMPARE (info.si_status, SIGCONT);
133 TEST_COMPARE (info.si_pid, pid);
135 /* That should leave the CLD_CONTINUED state waiting to be seen again. */
136 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
137 info.si_pid = -1;
138 info.si_status = -1;
139 fail = waitid (P_PID, pid, &info, WCONTINUED);
140 if (fail == -1 && errno == ENOTSUP)
141 FAIL_RET ("waitid WCONTINUED on continued: %m");
142 TEST_COMPARE (fail, 0);
143 TEST_COMPARE (info.si_signo, SIGCHLD);
144 TEST_COMPARE (info.si_code, CLD_CONTINUED);
145 TEST_COMPARE (info.si_status, SIGCONT);
146 TEST_COMPARE (info.si_pid, pid);
148 /* Now try a wait that should not succeed. */
149 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
150 fail = waitid (P_PID, pid, &info, WCONTINUED|WNOHANG);
151 if (fail == -1 && errno == ENOTSUP)
152 FAIL_RET ("waitid WCONTINUED|WNOHANG on waited continued: %m");
153 TEST_COMPARE (fail, 0);
154 TEST_COMPARE (info.si_signo, 0);
156 /* Now stop him again and test waitpid with WCONTINUED. */
157 if (kill (pid, SIGSTOP) != 0)
158 FAIL_RET ("kill (%d, SIGSTOP): %m\n", pid);
160 /* Wait the child stop. The waitid call below will block until it has
161 stopped, but if we are real quick and enter the waitid system call
162 before the SIGCHLD has been generated, then it will be discarded and
163 never delivered. */
164 support_process_state_wait (pid, stop_state);
166 fail = waitid (type, pid, &info, WEXITED|WSTOPPED);
167 TEST_COMPARE (fail, 0);
168 TEST_COMPARE (info.si_signo, SIGCHLD);
169 TEST_COMPARE (info.si_code, CLD_STOPPED);
170 TEST_COMPARE (info.si_status, SIGSTOP);
171 TEST_COMPARE (info.si_pid, pid);
173 check_sigchld (CLD_STOPPED, SIGSTOP, pid);
175 if (kill (pid, SIGCONT) != 0)
176 FAIL_RET ("kill (%d, SIGCONT): %m\n", pid);
178 /* Wait for the child to have continued. */
179 support_process_state_wait (pid, support_process_state_sleeping);
181 check_sigchld (CLD_CONTINUED, SIGCONT, pid);
183 fail = waitid (type, pid, &info, WCONTINUED);
184 TEST_COMPARE (fail, 0);
185 TEST_COMPARE (info.si_signo, SIGCHLD);
186 TEST_COMPARE (info.si_code, CLD_CONTINUED);
187 TEST_COMPARE (info.si_status, SIGCONT);
188 TEST_COMPARE (info.si_pid, pid);
189 #endif
191 /* Die, child, die! */
192 if (kill (pid, SIGKILL) != 0)
193 FAIL_RET ("kill (%d, SIGKILL): %m\n", pid);
195 #ifdef WNOWAIT
196 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
197 info.si_pid = -1;
198 info.si_status = -1;
199 fail = waitid (type, pid, &info, WEXITED|WNOWAIT);
200 if (fail == -1 && errno == ENOTSUP)
201 FAIL_RET ("waitid WNOHANG on killed: %m");
202 TEST_COMPARE (fail, 0);
203 TEST_COMPARE (info.si_signo, SIGCHLD);
204 TEST_COMPARE (info.si_code, CLD_KILLED);
205 TEST_COMPARE (info.si_status, SIGKILL);
206 TEST_COMPARE (info.si_pid, pid);
207 #else
208 support_process_state_wait (pid, support_process_state_zombie);
209 #endif
210 check_sigchld (CLD_KILLED, SIGKILL, pid);
212 info.si_signo = 0; /* A successful call sets it to SIGCHLD. */
213 info.si_pid = -1;
214 info.si_status = -1;
215 fail = waitid (type, pid, &info, WEXITED | WNOHANG);
216 TEST_COMPARE (fail, 0);
217 TEST_COMPARE (info.si_signo, SIGCHLD);
218 TEST_COMPARE (info.si_code, CLD_KILLED);
219 TEST_COMPARE (info.si_status, SIGKILL);
220 TEST_COMPARE (info.si_pid, pid);
222 fail = waitid (P_PID, pid, &info, WEXITED);
223 TEST_COMPARE (fail, -1);
224 TEST_COMPARE (errno, ECHILD);
226 return 0;
229 static int
230 do_test_waitid (idtype_t type)
232 #ifdef SA_SIGINFO
234 struct sigaction sa;
235 sa.sa_flags = SA_SIGINFO | SA_RESTART;
236 sa.sa_sigaction = sigchld;
237 sigemptyset (&sa.sa_mask);
238 xsigaction (SIGCHLD, &sa, NULL);
240 #endif
242 sigemptyset (&chldset);
243 sigaddset (&chldset, SIGCHLD);
245 /* The SIGCHLD shall has blocked at the time of the call to sigwait;
246 otherwise, the behavior is undefined. */
247 sigprocmask (SIG_BLOCK, &chldset, NULL);
249 pid_t pid = xfork ();
250 if (pid == 0)
252 test_child (type == P_PGID || type == P_ALL);
253 _exit (127);
256 int ret = do_test_waitd_common (type, pid);
258 xsignal (SIGCHLD, SIG_IGN);
259 kill (pid, SIGKILL); /* Make sure it's dead if we bailed early. */
260 return ret;
263 static int
264 do_test (void)
266 int ret = 0;
268 ret |= do_test_waitid (P_PID);
269 ret |= do_test_waitid (P_PGID);
270 ret |= do_test_waitid (P_ALL);
272 return ret;
275 #include <support/test-driver.c>