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