waitpid07.c revision 9736c6b06b071213e08079dfcfc9117b0defdb9e
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * NAME
22 *	waitpid07.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 = -1 and arg = WNOHANG
29 *
30 * USAGE:  <for command-line>
31 *      waitpid07 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
32 *      where,  -c n : Run n copies concurrently.
33 *              -e   : Turn on errno logging.
34 *              -i n : Execute test n times.
35 *              -I x : Execute test for x seconds.
36 *              -P x : Pause for x seconds between iterations.
37 *              -t   : Turn on syscall timing.
38 *
39 * History
40 *	07/2001 John George
41 *		-Ported
42 *      04/2002 wjhuie sigset cleanups
43 *
44 * Restrictions
45 *	None
46 */
47
48#include <sys/types.h>
49#include <signal.h>
50#include <errno.h>
51#include <sys/wait.h>
52#include <test.h>
53#include <usctest.h>
54
55void setup_sigint(void);
56void do_child_1(void);
57void setup(void);
58void cleanup(void);
59
60char *TCID = "waitpid07";
61int TST_TOTAL = 1;
62extern int Tst_count;
63
64volatile int intintr;
65int flag = 0;
66void inthandlr();
67void do_exit();
68
69#define	FAILED	1
70#define MAXKIDS	8
71
72#ifdef UCLINUX
73static char *argv0;
74void do_child_2_uclinux(void);
75#endif
76
77int main(int argc, char **argv)
78{
79	int lc;				/* loop counter */
80	char *msg;			/* message returned from parse_opts */
81
82	int status;
83	int fail = 0;
84	int pid;
85
86	/* parse standard options */
87	if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) !=
88	    (char *)NULL) {
89		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
90		tst_exit();
91		/*NOTREACHED*/
92	}
93
94#ifdef UCLINUX
95	argv0 = argv[0];
96
97	maybe_run_child(&do_child_1, "n", 1);
98	maybe_run_child(&do_child_2_uclinux, "n", 2);
99#endif
100
101	setup();
102
103	/* check for looping state if -i option is given */
104	for (lc = 0; TEST_LOOPING(lc); lc++) {
105		/* reset Tst_count in case we are looping */
106		Tst_count = 0;
107
108		if ((pid = FORK_OR_VFORK()) < 0) {
109			tst_resm(TFAIL, "Fork Failed, may be OK under stress");
110			tst_exit();
111		} else if (pid == 0) {
112
113			/*
114			 * Child:
115			 * Set up to catch SIGINT.  The kids will wait till a
116			 * SIGINT has been received before they proceed.
117			 */
118#ifdef UCLINUX
119			if (self_exec(argv[0], "n", 1) < 0) {
120				tst_resm(TINFO, "self_exec failed");
121				exit(pid);
122			}
123#else
124			do_child_1();
125#endif
126		} else {	/* parent */
127			fail = 0;
128			waitpid(pid, &status, 0);
129			if (WEXITSTATUS(status) != 0) {
130				tst_resm(TFAIL, "child returned bad status");
131				fail = 1;
132			}
133			if (fail) {
134				tst_resm(TFAIL, "%s FAILED", TCID);
135			} else {
136				tst_resm(TPASS, "%s PASSED", TCID);
137			}
138		}
139	}
140	cleanup();
141	/*NOTREACHED*/
142
143  return(0);
144
145}
146
147/*
148 * setup_sigint()
149 *	Sets up a SIGINT handler
150 */
151void
152setup_sigint(void)
153{
154	if ((sig_t)signal(SIGINT, inthandlr) == SIG_ERR ) {
155		tst_resm(TFAIL, "signal SIGINT failed. "
156			 "errno = %d", errno);
157		exit(-1);
158	}
159}
160
161/*
162 * do_child_1()
163 */
164void
165do_child_1(void)
166{
167	int kid_count, fork_kid_pid[MAXKIDS];
168	int ret_val;
169	int i, j, k, found;
170	int group1, group2;
171	int wait_kid_pid[MAXKIDS], status;
172
173	setup_sigint();
174
175	group1 = getpgrp();
176
177	for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
178		if (kid_count == (MAXKIDS / 2)) {
179			group2 = setpgrp();
180		}
181
182		intintr = 0;
183		ret_val = FORK_OR_VFORK();
184		if (ret_val == 0) {
185#ifdef UCLINUX
186			if (self_exec(argv0, "n", 2) < 0) {
187				tst_resm(TFAIL, "Fork kid %d failed. "
188					 "errno = %d", kid_count,
189					 errno);
190				exit(ret_val);
191			}
192#else
193			do_exit();
194#endif
195			/*NOTREACHED*/
196		}
197
198		if (ret_val < 0) {
199			tst_resm(TFAIL, "Fork kid %d failed. "
200				 "errno = %d", kid_count, errno);
201			tst_exit();
202		}
203
204		/* parent */
205		fork_kid_pid[kid_count] = ret_val;
206	}
207
208	/* Check that waitpid with WNOHANG returns zero */
209	if ((ret_val = waitpid(-1, &status, WNOHANG)) != 0) {
210		tst_resm(TFAIL, "Waitpid returned wrong value");
211		tst_resm(TFAIL, "Expected 0 got %d",
212			 ret_val);
213		flag = FAILED;
214	}
215
216#ifdef UCLINUX
217	/* Give the kids a chance to setup SIGINT again, since this is
218	 * cleared by exec().
219	 */
220	sleep(3);
221#endif
222
223	/* Now send all the kids a SIGINT to tell them to
224	 * proceed
225	 */
226	for (i = 0; i < MAXKIDS; i++) {
227		if (kill(fork_kid_pid[i], SIGINT) < 0) {
228			tst_resm(TFAIL, "Kill of child %d "
229				 "failed, errno = %d", i, errno);
230			tst_exit();
231		}
232	}
233
234	/*
235	 * Wait till all kids have terminated.  Stash away their
236	 * pid's in an array.
237	 */
238	kid_count = 0;
239	errno = 0;
240	while (((ret_val = waitpid(-1, &status, WNOHANG)) != -1)
241	       || (errno == EINTR)) {
242		if ((ret_val == -1) || (ret_val == 0)) {
243			continue;
244		}
245
246		if (!WIFEXITED(status)) {
247			tst_resm(TFAIL, "Child %d did not exit "
248				 "normally", ret_val);
249			flag = FAILED;
250		} else {
251			if (WEXITSTATUS(status) != 3) {
252				tst_resm(TFAIL, "Child %d "
253					 "exited with wrong "
254					 "status", ret_val);
255				tst_resm(TFAIL, "Expected 3 "
256					 "got %d ",
257					 WEXITSTATUS(status));
258				flag = FAILED;
259			}
260		}
261		wait_kid_pid[kid_count++] = ret_val;
262	}
263
264	/*
265	 * Check that for every entry in the fork_kid_pid array,
266	 * there is a matching pid in the wait_kid_pid array. If
267	 * not, it's an error.
268	 */
269	for (i = 0; i < kid_count; i++) {
270		found = 0;
271		for (j = 0; j < MAXKIDS; j++) {
272			if (fork_kid_pid[j] == wait_kid_pid[i]){
273				found = 1;
274				break;
275			}
276		}
277
278		if (!found) {
279			tst_resm(TFAIL, "Did not find a "
280				 "wait_kid_pid for the "
281				 "fork_kid_pid of %d",
282				 wait_kid_pid[i]);
283			for (k = 0; k < MAXKIDS; k++) {
284				tst_resm(TFAIL,
285					 "fork_kid_pid[%d] = "
286					 "%d", k,
287					 fork_kid_pid[k]);
288			}
289			for (k = 0; k < kid_count; k++) {
290				tst_resm(TFAIL,
291					 "wait_kid_pid[%d] = "
292					 "%d", k,
293					 wait_kid_pid[k]);
294			}
295			flag = FAILED;
296		}
297	}
298
299	if (flag) {
300		exit(1);
301	} else {
302		exit(0);
303	}
304}
305
306#ifdef UCLINUX
307/*
308 * do_child_2_uclinux()
309 *	sets up sigint handler again, then calls the normal child 2 function
310 */
311void
312do_child_2_uclinux(void)
313{
314	setup_sigint();
315	do_exit();
316}
317#endif
318
319/*
320 * setup()
321 *	performs all ONE TIME setup for this test
322 */
323void
324setup(void)
325{
326	/* Pause if that option was specified
327	 * TEST_PAUSE contains the code to fork the test with the -c option.
328	 */
329	TEST_PAUSE;
330}
331
332/*
333 * cleanup()
334 *	performs all ONE TIME cleanup for this test at
335 *	completion or premature exit
336 */
337void
338cleanup(void)
339{
340	/*
341	 * print timing stats if that option was specified.
342	 * print errno log if that option was specified.
343	 */
344	TEST_CLEANUP;
345
346	/* exit with return code appropriate for results */
347	tst_exit();
348	/*NOTREACHED*/
349}
350
351void
352inthandlr()
353{
354	intintr++;
355}
356
357void
358wait_for_parent()
359{
360	int testvar;
361
362	while (!intintr) {
363		testvar = 0;
364	}
365}
366
367void
368do_exit()
369{
370	wait_for_parent();
371	exit(3);
372}
373