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