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