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