1 /*
2  * Copyright (c) International Business Machines  Corp., 2001
3  *  07/2001 John George - Ported
4  *  04/2002 wjhuie sigset cleanups
5  *
6  * This program is free software;  you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14  * the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program;  if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * Tests to see if pid's returned from fork and waitpid are same
23  *
24  * Set up to catch SIGINTs, SIGALRMs, and the real time timer. Until the timer
25  * interrupts, do the following. Fork 8 kids, 2 will immediately exit, 2 will
26  * sleep, 2 will be compute bound, and 2 will fork another child, both which
27  * will do mkdirs on the same directory 50 times. When the timer expires, kill
28  * all kids and remove the directory.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34 
35 #include <stdio.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include "test.h"
39 
40 #define	MAXKIDS	8
41 
42 char *TCID = "waitpid10";
43 int TST_TOTAL = 1;
44 
45 volatile int intintr;
46 
47 static void setup(void);
48 static void cleanup(void);
49 static void inthandlr();
50 static void wait_for_parent(void);
51 static void do_exit(void);
52 static void do_compute(void);
53 static void do_fork(void);
54 static void do_sleep(void);
55 
56 static int fail;
57 static int fork_kid_pid[MAXKIDS];
58 
59 #ifdef UCLINUX
60 static char *argv0;
61 #endif
62 
main(int ac,char ** av)63 int main(int ac, char **av)
64 {
65 	int kid_count, ret_val, status, nkids;
66 	int i, j, k, found;
67 	int wait_kid_pid[MAXKIDS];
68 
69 	int lc;
70 
71 	tst_parse_opts(ac, av, NULL, NULL);
72 
73 #ifdef UCLINUX
74 	argv0 = av[0];
75 
76 	maybe_run_child(&do_exit, "n", 1);
77 	maybe_run_child(&do_compute, "n", 2);
78 	maybe_run_child(&do_fork, "n", 3);
79 	maybe_run_child(&do_sleep, "n", 4);
80 #endif
81 
82 	setup();
83 
84 	for (lc = 0; TEST_LOOPING(lc); lc++) {
85 		fail = 0;
86 		kid_count = 0;
87 		intintr = 0;
88 		for (i = 0; i < MAXKIDS; i++) {
89 			ret_val = FORK_OR_VFORK();
90 			if (ret_val < 0)
91 				tst_brkm(TBROK|TERRNO, cleanup,
92 					 "Fork kid %d failed.", i);
93 
94 			if (ret_val == 0) {
95 				if (i == 0 || i == 1) {
96 #ifdef UCLINUX
97 					if (self_exec(argv0, "n", 1) < 0)
98 						tst_brkm(TBROK|TERRNO, cleanup,
99 							 "self_exec %d failed",
100 							 i);
101 #else
102 					do_exit();
103 #endif
104 				}
105 
106 				if (i == 2 || i == 3) {
107 #ifdef UCLINUX
108 					if (self_exec(argv0, "n", 2) < 0)
109 						tst_brkm(TBROK|TERRNO, cleanup,
110 							 "self_exec %d failed",
111 							 i);
112 #else
113 					do_compute();
114 #endif
115 				}
116 
117 				if (i == 4 || i == 5) {
118 #ifdef UCLINUX
119 					if (self_exec(argv0, "n", 3) < 0)
120 						tst_brkm(TBROK|TERRNO, cleanup,
121 							 "self_exec %d failed",
122 							 i);
123 #else
124 					do_fork();
125 #endif
126 				}
127 
128 				if (i == 6 || i == 7) {
129 #ifdef UCLINUX
130 					if (self_exec(argv0, "n", 4) < 0)
131 						tst_brkm(TBROK|TERRNO, cleanup,
132 							 "self_exec %d failed",
133 							 i);
134 #else
135 					do_sleep();
136 #endif
137 
138 				}
139 
140 			}
141 
142 			fork_kid_pid[kid_count++] = ret_val;
143 		}
144 
145 		nkids = kid_count;
146 
147 		/*
148 		 * Now send all the kids a SIGUSR1 to tell them to
149 		 * proceed. We sleep for a while first to allow the
150 		 * children to initialize their "intintr" variables
151 		 * and get set up.
152 		 */
153 		sleep(15);
154 
155 		for (i = 0; i < nkids; i++) {
156 			if (kill(fork_kid_pid[i], SIGUSR1) < 0) {
157 				tst_brkm(TBROK|TERRNO, cleanup, "Kill of child "
158 						"%d failed", i);
159 			}
160 		}
161 
162 		/* Wait till all kids have terminated. */
163 		kid_count = 0;
164 		errno = 0;
165 		for (i = 0; i < nkids; i++) {
166 			while (((ret_val = waitpid(fork_kid_pid[i],
167 							&status, 0)) != -1)
168 					|| (errno == EINTR)) {
169 				if (ret_val == -1)
170 					continue;
171 
172 				wait_kid_pid[kid_count++] = ret_val;
173 			}
174 		}
175 
176 		/*
177 		 * Check that for every entry in the fork_kid_pid
178 		 * array, there is a matching pid in the
179 		 * wait_kid_pid array.
180 		 */
181 		for (i = 0; i < MAXKIDS; i++) {
182 			found = 0;
183 			for (j = 0; j < MAXKIDS; j++) {
184 				if (fork_kid_pid[i] == wait_kid_pid[j]) {
185 					found = 1;
186 					break;
187 				}
188 			}
189 			if (!found) {
190 				tst_resm(TFAIL, "Did not find a "
191 						"wait_kid_pid for the "
192 						"fork_kid_pid of %d",
193 						fork_kid_pid[i]);
194 				for (k = 0; k < nkids; k++) {
195 					tst_resm(TFAIL,
196 							"fork_kid_pid[%d] = "
197 							"%d", k,
198 							fork_kid_pid[k]);
199 				}
200 				for (k = 0; k < kid_count; k++) {
201 					tst_resm(TFAIL,
202 							"wait_kid_pid[%d] = "
203 							"%d", k,
204 							wait_kid_pid[k]);
205 				}
206 				fail = 1;
207 			}
208 		}
209 
210 		memset(fork_kid_pid, 0, sizeof(fork_kid_pid));
211 
212 		if (fail)
213 			tst_resm(TFAIL, "Test FAILED");
214 		else
215 			tst_resm(TPASS, "Test PASSED");
216 	}
217 
218 	cleanup();
219 	tst_exit();
220 }
221 
setup(void)222 static void setup(void)
223 {
224 	struct sigaction act;
225 
226 	tst_sig(FORK, DEF_HANDLER, cleanup);
227 
228 	TEST_PAUSE;
229 
230 	act.sa_handler = inthandlr;
231 	act.sa_flags = SA_RESTART;
232 	sigemptyset(&act.sa_mask);
233 
234 	if (sigaction(SIGUSR1, &act, NULL) < 0)
235 		tst_brkm(TBROK|TERRNO, cleanup,
236 			 "sigaction(SIGUSR1, ...) failed");
237 
238 	intintr = 0;
239 
240 }
241 
cleanup(void)242 static void cleanup(void)
243 {
244 	int i;
245 
246 	for (i = 0; i < MAXKIDS; i++) {
247 		if (fork_kid_pid[i] > 0)
248 			kill(fork_kid_pid[i], SIGKILL);
249 	}
250 }
251 
inthandlr(void)252 static void inthandlr(void)
253 {
254 	intintr++;
255 }
256 
wait_for_parent(void)257 static void wait_for_parent(void)
258 {
259 	while (!intintr)
260 		usleep(100);
261 }
262 
do_exit(void)263 static void do_exit(void)
264 {
265 	wait_for_parent();
266 	exit(3);
267 }
268 
do_compute(void)269 static void do_compute(void)
270 {
271 	int i;
272 
273 	wait_for_parent();
274 
275 	for (i = 0; i < 100000; i++) ;
276 	for (i = 0; i < 100000; i++) ;
277 	for (i = 0; i < 100000; i++) ;
278 	for (i = 0; i < 100000; i++) ;
279 	for (i = 0; i < 100000; i++) ;
280 	for (i = 0; i < 100000; i++) ;
281 	for (i = 0; i < 100000; i++) ;
282 	for (i = 0; i < 100000; i++) ;
283 	for (i = 0; i < 100000; i++) ;
284 	for (i = 0; i < 100000; i++) ;
285 
286 	exit(4);
287 }
288 
do_fork(void)289 static void do_fork(void)
290 {
291 	int fork_pid, wait_pid;
292 	int status, i;
293 
294 	wait_for_parent();
295 
296 	for (i = 0; i < 50; i++) {
297 		fork_pid = FORK_OR_VFORK();
298 		if (fork_pid < 0) {
299 			tst_brkm(TBROK|TERRNO, NULL, "Fork failed");
300 		}
301 		if (fork_pid == 0) {
302 #ifdef UCLINUX
303 			if (self_exec(argv0, "n", 1) < 0) {
304 				tst_brkm(TFAIL, NULL,
305 					 "do_fork self_exec failed");
306 			}
307 #else
308 			do_exit();
309 #endif
310 		}
311 
312 		errno = 0;
313 		while (((wait_pid = waitpid(fork_pid, &status, 0)) != -1) ||
314 		       (errno == EINTR)) {
315 			if (wait_pid == -1)
316 				continue;
317 
318 			if (fork_pid != wait_pid) {
319 				tst_resm(TFAIL, "Didnt get a pid returned "
320 					 "from waitpid that matches the one "
321 					 "returned by fork");
322 				tst_resm(TFAIL, "fork pid = %d, wait pid = "
323 					 "%d", fork_pid, wait_pid);
324 				fail = 1;
325 			}
326 		}
327 	}
328 
329 	exit(4);
330 }
331 
do_sleep(void)332 static void do_sleep(void)
333 {
334 	wait_for_parent();
335 	sleep(1);
336 	sleep(1);
337 
338 	exit(4);
339 }
340