waitpid07.c revision 5086d421be015b45dbe40af25a77e3841c0d8851
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 *	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
55static void setup_sigint(void);
56static void do_child_1(void);
57static void setup(void);
58static void cleanup(void);
59
60char *TCID = "waitpid07";
61int TST_TOTAL = 1;
62
63volatile int intintr;
64static int flag;
65static void inthandlr();
66static void do_exit(void);
67
68#define	FAILED	1
69#define MAXKIDS	8
70
71#ifdef UCLINUX
72static char *argv0;
73static void do_child_2_uclinux(void);
74#endif
75
76int main(int argc, char **argv)
77{
78	int lc;
79	char *msg;
80
81	int status;
82	int fail = 0;
83	int pid;
84
85	msg = parse_opts(argc, argv, NULL, NULL);
86	if (msg != NULL)
87		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
88
89#ifdef UCLINUX
90	argv0 = argv[0];
91
92	maybe_run_child(&do_child_1, "n", 1);
93	maybe_run_child(&do_child_2_uclinux, "n", 2);
94#endif
95
96	setup();
97
98	/* check for looping state if -i option is given */
99	for (lc = 0; TEST_LOOPING(lc); lc++) {
100		/* reset Tst_count in case we are looping */
101		Tst_count = 0;
102
103		pid = FORK_OR_VFORK();
104		if (pid < 0) {
105			tst_resm(TFAIL, "Fork Failed, may be OK under stress");
106		} else if (pid == 0) {
107
108			/*
109			 * Child:
110			 * Set up to catch SIGINT.  The kids will wait till a
111			 * SIGINT has been received before they proceed.
112			 */
113#ifdef UCLINUX
114			if (self_exec(argv[0], "n", 1) < 0) {
115				tst_resm(TINFO, "self_exec failed");
116				exit(pid);
117			}
118#else
119			do_child_1();
120#endif
121		} else {
122			fail = 0;
123			waitpid(pid, &status, 0);
124			if (WEXITSTATUS(status) != 0) {
125				tst_resm(TFAIL, "child returned bad status");
126				fail = 1;
127			}
128			if (fail)
129				tst_resm(TFAIL, "%s FAILED", TCID);
130			else
131				tst_resm(TPASS, "%s PASSED", TCID);
132		}
133	}
134
135	cleanup();
136	tst_exit();
137}
138
139/*
140 * setup_sigint()
141 *	Sets up a SIGINT handler
142 */
143static void setup_sigint(void)
144{
145	if ((sig_t) signal(SIGINT, inthandlr) == SIG_ERR) {
146		tst_resm(TFAIL, "signal SIGINT failed. " "errno = %d", errno);
147		exit(-1);
148	}
149}
150
151static void do_child_1(void)
152{
153	int kid_count, fork_kid_pid[MAXKIDS];
154	int ret_val;
155	int i, j, k, found;
156	int group1, group2;
157	int wait_kid_pid[MAXKIDS], status;
158
159	setup_sigint();
160
161	group1 = getpgrp();
162
163	for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
164		if (kid_count == (MAXKIDS / 2))
165			group2 = setpgrp();
166
167		intintr = 0;
168		ret_val = FORK_OR_VFORK();
169		if (ret_val == 0) {
170#ifdef UCLINUX
171			if (self_exec(argv0, "n", 2) < 0) {
172				tst_resm(TFAIL, "Fork kid %d failed. "
173					 "errno = %d", kid_count, errno);
174				exit(ret_val);
175			}
176#else
177			do_exit();
178#endif
179		}
180
181		if (ret_val < 0) {
182			tst_resm(TFAIL, "Fork kid %d failed. "
183				 "errno = %d", kid_count, errno);
184			tst_exit();
185		}
186
187		/* parent */
188		fork_kid_pid[kid_count] = ret_val;
189	}
190
191	/* Check that waitpid with WNOHANG returns zero */
192	ret_val = waitpid(-1, &status, WNOHANG);
193	if (ret_val != 0) {
194		tst_resm(TFAIL, "Waitpid returned wrong value");
195		tst_resm(TFAIL, "Expected 0 got %d", ret_val);
196		flag = FAILED;
197	}
198#ifdef UCLINUX
199	/* Give the kids a chance to setup SIGINT again, since this is
200	 * cleared by exec().
201	 */
202	sleep(3);
203#endif
204
205	/* Now send all the kids a SIGINT to tell them to
206	 * proceed
207	 */
208	for (i = 0; i < MAXKIDS; i++) {
209		if (kill(fork_kid_pid[i], SIGINT) < 0) {
210			tst_resm(TFAIL, "Kill of child %d "
211				 "failed, errno = %d", i, errno);
212			tst_exit();
213		}
214	}
215
216	/*
217	 * Wait till all kids have terminated.  Stash away their
218	 * pid's in an array.
219	 */
220	kid_count = 0;
221	errno = 0;
222	while (((ret_val = waitpid(-1, &status, WNOHANG)) != -1)
223	       || (errno == EINTR)) {
224		if ((ret_val == -1) || (ret_val == 0))
225			continue;
226
227		if (!WIFEXITED(status)) {
228			tst_resm(TFAIL, "Child %d did not exit "
229				 "normally", ret_val);
230			flag = FAILED;
231		} else {
232			if (WEXITSTATUS(status) != 3) {
233				tst_resm(TFAIL, "Child %d "
234					 "exited with wrong "
235					 "status", ret_val);
236				tst_resm(TFAIL, "Expected 3 "
237					 "got %d ", WEXITSTATUS(status));
238				flag = FAILED;
239			}
240		}
241		wait_kid_pid[kid_count++] = ret_val;
242	}
243
244	/*
245	 * Check that for every entry in the fork_kid_pid array,
246	 * there is a matching pid in the wait_kid_pid array. If
247	 * not, it's an error.
248	 */
249	for (i = 0; i < kid_count; i++) {
250		found = 0;
251		for (j = 0; j < MAXKIDS; j++) {
252			if (fork_kid_pid[j] == wait_kid_pid[i]) {
253				found = 1;
254				break;
255			}
256		}
257
258		if (!found) {
259			tst_resm(TFAIL, "Did not find a "
260				 "wait_kid_pid for the "
261				 "fork_kid_pid of %d", wait_kid_pid[i]);
262			for (k = 0; k < MAXKIDS; k++) {
263				tst_resm(TFAIL,
264					 "fork_kid_pid[%d] = "
265					 "%d", k, fork_kid_pid[k]);
266			}
267			for (k = 0; k < kid_count; k++) {
268				tst_resm(TFAIL,
269					 "wait_kid_pid[%d] = "
270					 "%d", k, wait_kid_pid[k]);
271			}
272			flag = FAILED;
273		}
274	}
275
276	if (flag)
277		exit(1);
278	else
279		exit(0);
280}
281
282#ifdef UCLINUX
283/*
284 * do_child_2_uclinux()
285 *	sets up sigint handler again, then calls the normal child 2 function
286 */
287static void do_child_2_uclinux(void)
288{
289	setup_sigint();
290	do_exit();
291}
292#endif
293
294static void setup(void)
295{
296	TEST_PAUSE;
297}
298
299static void cleanup(void)
300{
301	TEST_CLEANUP;
302}
303
304static void inthandlr()
305{
306	intintr++;
307}
308
309static void wait_for_parent(void)
310{
311	int testvar;
312
313	while (!intintr)
314		testvar = 0;
315}
316
317static void do_exit(void)
318{
319	wait_for_parent();
320	exit(3);
321}
322