1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * NAME
22 * waitpid13.c
23 *
24 * DESCRIPTION
25 * Tests to see if pid's returned from fork and waitpid are same
26 *
27 * ALGORITHM
28 * Check proper functioning of waitpid with pid = 0 and < -1 with arg
29 * WUNTRACED
30 *
31 * USAGE: <for command-line>
32 * waitpid13 [-c n] [-t]
33 * where, -c n : Run n copies concurrently.
34 * -t : Turn on syscall timing.
35 *
36 * History
37 * 07/2001 John George
38 * -Ported
39 * 04/2002 wjhuie sigset cleanups
40 *
41 * Restrictions
42 * None
43 */
44
45 #include <sys/types.h>
46 #include <signal.h>
47 #include <errno.h>
48 #include <sys/wait.h>
49 #include "test.h"
50
51 #define MAXKIDS 8
52
53 char *TCID = "waitpid13";
54 int TST_TOTAL = 1;
55
56 volatile int intintr;
57 static void setup(void);
58 static void cleanup(void);
59 static void inthandlr();
60 static void wait_for_parent(void);
61 static void do_exit(void);
62 static void setup_sigint(void);
63 #ifdef UCLINUX
64 static void do_exit_uclinux(void);
65 #endif
66
67 static int fail;
68
main(int ac,char ** av)69 int main(int ac, char **av)
70 {
71 int kid_count, ret_val, status;
72 int i, j, k, found;
73 int group1, group2;
74 int fork_kid_pid[MAXKIDS], wait_kid_pid[MAXKIDS];
75 int pid;
76
77 tst_parse_opts(ac, av, NULL, NULL);
78
79 #ifdef UCLINUX
80 maybe_run_child(&do_exit_uclinux, "");
81 #endif
82
83 setup();
84
85 tst_count = 0;
86 fail = 0;
87
88 /*
89 * Need to have test run from child as test driver causes
90 * test to be a session leader and setpgrp fails.
91 */
92 pid = FORK_OR_VFORK();
93 if (pid > 0) {
94 waitpid(pid, &status, 0);
95 if (WEXITSTATUS(status) != 0) {
96 tst_resm(TFAIL, "child returned bad status");
97 fail = 1;
98 }
99 if (fail)
100 tst_resm(TFAIL, "%s FAILED", TCID);
101 else
102 tst_resm(TPASS, "%s PASSED", TCID);
103
104 cleanup();
105 tst_exit();
106 } else if (pid < 0) {
107 tst_brkm(TBROK, cleanup, "fork failed");
108 }
109
110 /*
111 * Set up to catch SIGINT. The kids will wait till a SIGINT
112 * has been received before they proceed.
113 */
114 setup_sigint();
115
116 group1 = getpgrp();
117
118 for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
119 if (kid_count == (MAXKIDS / 2))
120 group2 = setpgrp();
121
122 intintr = 0;
123 ret_val = FORK_OR_VFORK();
124 if (ret_val == 0) {
125 #ifdef UCLINUX
126 if (self_exec(av[0], "") < 0) {
127 tst_resm(TFAIL | TERRNO, "self_exec kid %d "
128 "failed", kid_count);
129
130 }
131 #else
132 do_exit();
133 #endif
134 }
135
136 if (ret_val < 0)
137 tst_resm(TFAIL | TERRNO, "forking kid %d failed",
138 kid_count);
139
140 /* parent */
141 fork_kid_pid[kid_count] = ret_val;
142 }
143
144 /* Check that waitpid with WNOHANG|WUNTRACED returns zero */
145 ret_val = waitpid(0, &status, WNOHANG | WUNTRACED);
146 if (ret_val != 0) {
147 tst_resm(TFAIL, "Waitpid returned wrong value"
148 "from waitpid(WNOHANG|WUNTRACED)");
149 tst_resm(TFAIL, "Expected 0 got %d", ret_val);
150 fail = 1;
151 }
152 #ifdef UCLINUX
153 /* Give the kids a chance to setup SIGINT again, since this is
154 * cleared by exec().
155 */
156 sleep(3);
157 #endif
158
159 /* Now send all the kids a SIGINT to tell them to proceed */
160 for (i = 0; i < MAXKIDS; i++) {
161 if (kill(fork_kid_pid[i], SIGINT) < 0) {
162 tst_resm(TFAIL | TERRNO, "killing child %d failed", i);
163 fail = 1;
164 }
165 }
166
167 /*
168 * Wait till all kids have terminated. Stash away their
169 * pid's in an array.
170 */
171 kid_count = 0;
172 errno = 0;
173 while (((ret_val = waitpid(0, &status, WUNTRACED)) != -1) ||
174 (errno == EINTR)) {
175 if (ret_val == -1)
176 continue;
177
178 if (!WIFEXITED(status)) {
179 if (!WIFSTOPPED(status)) {
180 tst_resm(TFAIL, "Child %d is not "
181 "stopped", ret_val);
182 fail = 1;
183 } else {
184 if (WSTOPSIG(status) != SIGSTOP) {
185 tst_resm(TFAIL, "Child %d "
186 "exited with wrong "
187 "status", ret_val);
188 tst_resm(TFAIL, "Expected "
189 "SIGSTOP got %d",
190 WEXITSTATUS(status));
191 fail = 1;
192 }
193 }
194 if (kill(ret_val, SIGCONT) < 0) {
195 tst_resm(TFAIL | TERRNO,
196 "killing child %d failed", ret_val);
197 fail = 1;
198 }
199 }
200 found = 0;
201 for (j = 0; j < kid_count; j++) {
202 if (ret_val == wait_kid_pid[j]) {
203 found = 1;
204 break;
205 }
206 }
207 if (!found)
208 wait_kid_pid[kid_count++] = ret_val;
209 }
210
211 /*
212 * Check that for every entry in the fork_kid_pid array,
213 * there is a matching pid in the wait_kid_pid array. If
214 * not, it's an error.
215 */
216 for (i = 0; i < kid_count; i++) {
217 found = 0;
218 for (j = (MAXKIDS / 2); j < MAXKIDS; j++) {
219 if (fork_kid_pid[j] == wait_kid_pid[i]) {
220 found = 1;
221 break;
222 }
223 }
224 if (!found) {
225 tst_resm(TFAIL, "Did not find a wait_kid_pid "
226 "for the fork_kid_pid of %d", wait_kid_pid[i]);
227 for (k = 0; k < MAXKIDS; k++)
228 tst_resm(TFAIL, "fork_kid_pid[%d] = "
229 "%d", k, fork_kid_pid[k]);
230 for (k = 0; k < kid_count; k++)
231 tst_resm(TFAIL, "wait_kid_pid[%d] = "
232 "%d", k, wait_kid_pid[k]);
233 fail = 1;
234 }
235 }
236
237 if (kid_count != (MAXKIDS / 2)) {
238 tst_resm(TFAIL, "Wrong number of children waited on "
239 "for pid = 0");
240 tst_resm(TFAIL, "Expected %d got %d", MAXKIDS, kid_count);
241 fail = 1;
242 }
243
244 /* Make sure can pickup children in a diff. process group */
245
246 kid_count = 0;
247 errno = 0;
248 while (((ret_val = waitpid(-(group1), &status, WUNTRACED)) !=
249 -1) || (errno == EINTR)) {
250 if (ret_val == -1)
251 continue;
252 if (!WIFEXITED(status)) {
253 if (!WIFSTOPPED(status)) {
254 tst_resm(TFAIL, "Child %d is not "
255 "stopped", ret_val);
256 fail = 1;
257 } else {
258 if (WSTOPSIG(status) != SIGSTOP) {
259 tst_resm(TFAIL, "Child %d "
260 "exited with wrong "
261 "status", ret_val);
262 tst_resm(TFAIL, "Expected "
263 "SIGSTOP got %d",
264 WEXITSTATUS(status));
265 fail = 1;
266 }
267 }
268 if (kill(ret_val, SIGCONT) < 0) {
269 tst_resm(TFAIL | TERRNO,
270 "Killing child %d failed", ret_val);
271 fail = 1;
272 }
273 }
274 found = 0;
275 for (j = 0; j < kid_count; j++) {
276 if (ret_val == wait_kid_pid[j]) {
277 found = 1;
278 break;
279 }
280 }
281 if (!found)
282 wait_kid_pid[kid_count++] = ret_val;
283 }
284
285 /*
286 * Check that for every entry in the fork_kid_pid array,
287 * there is a matching pid in the wait_kid_pid array. If
288 * not, it's an error.
289 */
290 for (i = 0; i < kid_count; i++) {
291 found = 0;
292 for (j = 0; j < (MAXKIDS / 2); j++) {
293 if (fork_kid_pid[j] == wait_kid_pid[i]) {
294 found = 1;
295 break;
296 }
297 }
298 if (!found) {
299 tst_resm(TFAIL, "Did not find a wait_kid_pid "
300 "for the fork_kid_pid of %d", fork_kid_pid[j]);
301 for (k = 0; k < MAXKIDS; k++)
302 tst_resm(TFAIL, "fork_kid_pid[%d] = "
303 "%d", k, fork_kid_pid[k]);
304 for (k = 0; k < kid_count; k++)
305 tst_resm(TFAIL, "wait_kid_pid[%d] = "
306 "%d", k, wait_kid_pid[k]);
307 fail = 1;
308 }
309 }
310 if (kid_count != (MAXKIDS / 2)) {
311 tst_resm(TFAIL, "Wrong number of children waited on "
312 "for pid = 0");
313 tst_resm(TFAIL, "Expected %d got %d", MAXKIDS, kid_count);
314 fail = 1;
315 }
316
317 /*
318 * Check that waitpid(WUNTRACED) returns -1 when no stopped
319 * children
320 */
321 ret_val = waitpid(-1, &status, WUNTRACED);
322 if (ret_val != -1) {
323 tst_resm(TFAIL, "Waitpid returned wrong value.");
324 tst_resm(TFAIL, "Expected -1 got %d", ret_val);
325 fail = 1;
326 }
327
328 if (errno != ECHILD) {
329 tst_resm(TFAIL, "Expected ECHILD from waitpid(WUNTRACED)");
330 fail = 1;
331 }
332
333 if (fail)
334 tst_resm(TFAIL, "Test FAILED");
335 else
336 tst_resm(TPASS, "Test PASSED");
337
338 tst_exit();
339 }
340
setup_sigint(void)341 static void setup_sigint(void)
342 {
343 if (signal(SIGINT, inthandlr) == SIG_ERR)
344 tst_brkm(TFAIL | TERRNO, NULL, "signal SIGINT failed");
345 }
346
setup(void)347 static void setup(void)
348 {
349 TEST_PAUSE;
350 }
351
cleanup(void)352 static void cleanup(void)
353 {
354 }
355
inthandlr(void)356 static void inthandlr(void)
357 {
358 intintr++;
359 }
360
wait_for_parent(void)361 static void wait_for_parent(void)
362 {
363 int testvar;
364
365 while (!intintr)
366 testvar = 0;
367 }
368
do_exit(void)369 static void do_exit(void)
370 {
371 wait_for_parent();
372 kill(getpid(), SIGSTOP);
373 exit(3);
374 }
375
376 #ifdef UCLINUX
do_exit_uclinux(void)377 static void do_exit_uclinux(void)
378 {
379 setup_sigint();
380 do_exit();
381 }
382 #endif
383