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