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/>. */
26 #include <stdatomic.h>
29 #include <support/xsignal.h>
30 #include <support/xunistd.h>
31 #include <support/check.h>
32 #include <support/process_state.h>
35 test_child (bool setgroup
)
38 TEST_COMPARE (setpgid (0, 0), 0);
40 /* First thing, we stop ourselves. */
43 /* Hey, we got continued! */
51 # define WSTOPPED WUNTRACED
54 /* Set with only SIGCHLD on do_test_waitid. */
55 static sigset_t chldset
;
59 sigchld (int signo
, siginfo_t
*info
, void *ctx
)
65 check_sigchld (int code
, int status
, pid_t pid
)
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
);
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. */
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. */
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
);
121 check_sigchld (CLD_CONTINUED
, SIGCONT
, pid
);
123 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
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. */
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
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
);
191 /* Die, child, die! */
192 if (kill (pid
, SIGKILL
) != 0)
193 FAIL_RET ("kill (%d, SIGKILL): %m\n", pid
);
196 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
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
);
208 support_process_state_wait (pid
, support_process_state_zombie
);
210 check_sigchld (CLD_KILLED
, SIGKILL
, pid
);
212 info
.si_signo
= 0; /* A successful call sets it to SIGCHLD. */
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
);
230 do_test_waitid (idtype_t type
)
235 sa
.sa_flags
= SA_SIGINFO
| SA_RESTART
;
236 sa
.sa_sigaction
= sigchld
;
237 sigemptyset (&sa
.sa_mask
);
238 xsigaction (SIGCHLD
, &sa
, NULL
);
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 ();
252 test_child (type
== P_PGID
|| type
== P_ALL
);
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. */
268 ret
|= do_test_waitid (P_PID
);
269 ret
|= do_test_waitid (P_PGID
);
270 ret
|= do_test_waitid (P_ALL
);
275 #include <support/test-driver.c>