blob: 096f4583a04c4ac9b24e452e9aaad7849c3c86ac [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
robbiew4644c7e2002-04-26 14:33:32 +000039 * 04/2002 wjhuie sigset cleanups
plars865695b2001-08-27 22:15:12 +000040 *
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#include <usctest.h>
51
52#define MAXKIDS 8
53
54char *TCID = "waitpid13";
55int TST_TOTAL = 1;
56extern int Tst_count;
57
robbiew3d5c7352003-01-13 17:49:51 +000058volatile int intintr;
plars865695b2001-08-27 22:15:12 +000059void setup(void);
60void cleanup(void);
61void inthandlr();
plars74948ad2002-11-14 16:16:14 +000062void wait_for_parent();
63void do_exit();
plars865695b2001-08-27 22:15:12 +000064
65int fail;
66
plarsac85d1c2002-06-10 14:52:37 +000067int main(int ac, char **av)
plars865695b2001-08-27 22:15:12 +000068{
69 int lc; /* loop counter */
70 char *msg; /* message returned from parse_opts */
71
plars74948ad2002-11-14 16:16:14 +000072 int kid_count, ret_val, status;
73 int i, j, k, found;
plars865695b2001-08-27 22:15:12 +000074 int group1, group2;
75 int fork_kid_pid[MAXKIDS], wait_kid_pid[MAXKIDS];
76 int pid;
77
78 /* parse standard options */
79 if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) !=
80 (char *)NULL) {
81 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
82 }
83
84 setup();
85
86 /* check for looping state if -i option is given */
87 for (lc = 0; TEST_LOOPING(lc); lc++) {
88 /* reset Tst_count in case we are looping */
89 Tst_count = 0;
90
91 /*
92 * Need to have test run from child as test driver causes
93 * test to be a session leader and setpgrp fails.
94 */
plars74948ad2002-11-14 16:16:14 +000095 if ((pid = fork()) != 0) {
plars865695b2001-08-27 22:15:12 +000096 fail = 0;
97 waitpid(pid, &status, 0);
98 if (WEXITSTATUS(status) != 0) {
99 tst_resm(TFAIL, "child returned bad status");
100 fail = 1;
101 }
102 if (fail) {
robbiew3d5c7352003-01-13 17:49:51 +0000103 tst_resm(TFAIL, "%s FAILED", TCID);
plars865695b2001-08-27 22:15:12 +0000104 } else {
robbiew3d5c7352003-01-13 17:49:51 +0000105 tst_resm(TPASS, "%s PASSED", TCID);
plars865695b2001-08-27 22:15:12 +0000106 }
107 cleanup();
108 /*NOTREACHED*/
109 } else if (pid < 0 ) {
110 tst_brkm(TBROK, cleanup, "fork failed");
111 /*NOTREACHED*/
112 }
113
114 /*
115 * Set up to catch SIGINT. The kids will wait till a SIGINT
116 * has been received before they proceed.
117 */
plarsac85d1c2002-06-10 14:52:37 +0000118 if ((sig_t)signal(SIGINT, inthandlr) == SIG_ERR) {
robbiew4644c7e2002-04-26 14:33:32 +0000119 tst_brkm(TFAIL, cleanup, "signal SIGINT failed, "
plars865695b2001-08-27 22:15:12 +0000120 "errno = %d", errno);
121 /*NOTREACHED*/
122 }
123
124 group1 = getpgrp();
125
126 for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
127 if (kid_count == (MAXKIDS / 2)) {
128 group2 = setpgrp();
129 }
130
131 intintr = 0;
132 ret_val = fork();
133 if (ret_val == 0) {
134 do_exit();
135 /*NOTREACHED*/
136 }
137
138 if (ret_val < 0) {
139 tst_resm(TFAIL, "Fork kid %d failed. errno = "
140 "%d", kid_count, errno);
141 tst_exit();
142 /*NOTREACHED*/
143 }
144
145 /* parent */
146 fork_kid_pid[kid_count] = ret_val;
147 }
148
149 /* Check that waitpid with WNOHANG|WUNTRACED returns zero */
150 if ((ret_val = waitpid(0, &status, WNOHANG | WUNTRACED))
151 != 0) {
152 tst_resm(TFAIL, "Waitpid returned wrong value"
153 "from waitpid(WNOHANG|WUNTRACED)");
154 tst_resm(TFAIL, "Expected 0 got %d", ret_val);
155 fail = 1;
156 }
157
158 /* Now send all the kids a SIGINT to tell them to proceed */
159 for (i = 0; i < MAXKIDS; i++) {
160 if (kill(fork_kid_pid[i], SIGINT) < 0) {
161 tst_resm(TFAIL, "Kill of child %d failed, "
162 "errno = %d", i, errno);
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
179 if (!WIFEXITED(status)) {
180 if (!WIFSTOPPED(status)) {
181 tst_resm(TFAIL, "Child %d is not "
182 "stopped", ret_val);
183 fail = 1;
184 } else {
185 if (WSTOPSIG(status) != SIGSTOP) {
186 tst_resm(TFAIL, "Child %d "
187 "exited with wrong "
188 "status", ret_val);
189 tst_resm(TFAIL, "Expected "
190 "SIGSTOP got %d",
191 WEXITSTATUS(status));
192 fail = 1;
193 }
194 }
195 if (kill(ret_val, SIGCONT) < 0) {
196 tst_resm(TFAIL, "Kill of child %d "
197 "failed, errno = %d",
198 ret_val, errno);
199 fail = 1;
200 }
201 }
202 wait_kid_pid[kid_count++] = ret_val;
203 }
204
205 /*
206 * Check that for every entry in the fork_kid_pid array,
207 * there is a matching pid in the wait_kid_pid array. If
208 * not, it's an error.
209 */
210 for (i = 0; i < kid_count; i++) {
211 found = 0;
212 for (j = (MAXKIDS / 2); j < MAXKIDS; j++) {
213 if (fork_kid_pid[j] == wait_kid_pid[i]) {
214 found = 1;
215 break;
216 }
217 }
218 if (!found) {
219 tst_resm(TFAIL, "Did not find a wait_kid_pid "
220 "for the fork_kid_pid of %d",
221 fork_kid_pid[j]);
222 for (k = 0; k < MAXKIDS; k++) {
223 tst_resm(TFAIL, "fork_kid_pid[%d] = "
224 "%d", k, fork_kid_pid[k]);
225 }
226 for (k = 0; k < kid_count; k++) {
227 tst_resm(TFAIL, "wait_kid_pid[%d] = "
228 "%d", k, wait_kid_pid[k]);
229 }
230 fail = 1;
231 }
232 }
233
234 if (kid_count != MAXKIDS) {
235 tst_resm(TFAIL, "Wrong number of children waited on "
236 "for pid = 0");
237 tst_resm(TFAIL, "Expected %d got %d", MAXKIDS,
238 kid_count);
239 fail = 1;
240 }
241
242 /* Make sure can pickup children in a diff. process group */
243
244 kid_count = 0;
245 errno = 0;
246 while (((ret_val = waitpid(-(group1), &status, WUNTRACED)) !=
247 -1) || (errno == EINTR)) {
248 if (ret_val == -1) {
249 continue;
250 }
251 if (!WIFEXITED(status)) {
252 if (!WIFSTOPPED(status)) {
253 tst_resm(TFAIL, "Child %d is not "
254 "stopped", ret_val);
255 fail = 1;
256 } else {
257 if (WSTOPSIG(status) != SIGSTOP) {
258 tst_resm(TFAIL, "Child %d "
259 "exited with wrong "
260 "status", ret_val);
261 tst_resm(TFAIL, "Expected "
262 "SIGSTOP got %d",
263 WEXITSTATUS(status));
264 fail = 1;
265 }
266 }
267 if (kill(ret_val, SIGCONT) < 0) {
268 tst_resm(TFAIL, "Kill of child %d "
269 "failed, errno = %d",
270 ret_val, errno);
271 fail = 1;
272 }
273 }
274 wait_kid_pid[kid_count++] = ret_val;
275 }
276
277 /*
278 * Check that for every entry in the fork_kid_pid array,
279 * there is a matching pid in the wait_kid_pid array. If
280 * not, it's an error.
281 */
282 for (i = 0; i < kid_count; i++) {
283 found = 0;
284 for (j = 0; j < (MAXKIDS / 2); j++) {
285 if (fork_kid_pid[j] == wait_kid_pid[i]) {
286 found = 1;
287 break;
288 }
289 }
290 if (!found) {
291 tst_resm(TFAIL, "Did not find a wait_kid_pid "
292 "for the fork_kid_pid of %d",
293 fork_kid_pid[j]);
294 for (k = 0; k < MAXKIDS; k++) {
295 tst_resm(TFAIL, "fork_kid_pid[%d] = "
296 "%d", k, fork_kid_pid[k]);
297 }
298 for (k = 0; k < kid_count; k++) {
299 tst_resm(TFAIL, "wait_kid_pid[%d] = "
300 "%d", k, wait_kid_pid[k]);
301 }
302 fail = 1;
303 }
304 }
305 if (kid_count != MAXKIDS) {
306 tst_resm(TFAIL, "Wrong number of children waited on "
307 "for pid = 0");
308 tst_resm(TFAIL, "Expected %d got %d", MAXKIDS,
309 kid_count);
310 fail = 1;
311 }
312
313 /*
314 * Check that waitpid(WUNTRACED) returns -1 when no stopped
315 * children
316 */
317 if ((ret_val = waitpid(-1, &status, WUNTRACED)) != -1) {
318 tst_resm(TFAIL, "Waitpid returned wrong value.");
319 tst_resm(TFAIL, "Expected -1 got %d", ret_val);
320 fail = 1;
321 }
322
323 if (errno != ECHILD) {
324 tst_resm(TFAIL, "Waitpid returned wrong errno");
325 tst_resm(TFAIL, "Expected ECHILD from "
326 "waitpid(WUNTRACED) got %d", errno);
327 fail = 1;
328 }
329
330 if (fail) {
331 tst_resm(TFAIL, "Test FAILED");
332 exit(1);
333 } else {
334 tst_resm(TPASS, "Test PASSED");
335 exit(0);
336 }
337 }
robbiewaa01abd2003-03-27 18:39:24 +0000338
339 return(0);
340
plars865695b2001-08-27 22:15:12 +0000341}
342
343/*
344 * setup()
345 * performs all ONE TIME setup for this test
346 */
347void
348setup(void)
349{
350 /* Pause if that option was specified
351 * TEST_PAUSE contains the code to fork the test with the -c option.
352 */
353 TEST_PAUSE;
354}
355
356/*
357 * cleanup()
358 * performs all ONE TIME cleanup for this test at
359 * completion or premature exit
360 */
361void
362cleanup(void)
363{
364 /*
365 * print timing stats if that option was specified.
366 * print errno log if that option was specified.
367 */
368 TEST_CLEANUP;
369
370 /* exit with return code appropriate for results */
371 tst_exit();
372 /*NOTREACHED*/
373}
374
375void
376inthandlr()
377{
378 intintr++;
379}
380
plars74948ad2002-11-14 16:16:14 +0000381void
plars865695b2001-08-27 22:15:12 +0000382wait_for_parent()
383{
384 int testvar;
385
386 while (!intintr) {
387 testvar = 0;
388 }
389}
390
plars74948ad2002-11-14 16:16:14 +0000391void
plars865695b2001-08-27 22:15:12 +0000392do_exit()
393{
394 wait_for_parent();
395 kill(getpid(), SIGSTOP);
396 exit(3);
397}