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