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 * waitpid08.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 =
29 * WUNTRACED
30 *
31 * USAGE: <for command-line>
32 * waitpid08 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
33 * where, -c n : Run n copies concurrently.
34 * -e : Turn on errno logging.
35 * -i n : Execute test n times.
36 * -I x : Execute test for x seconds.
37 * -P x : Pause for x seconds between iterations.
38 * -t : Turn on syscall timing.
39 *
40 * History
41 * 07/2001 John George
42 * -Ported
43 * 04/2002 wjhuie sigset cleanups
44 *
45 * Restrictions
46 * None
47 */
48
49 #include <sys/types.h>
50 #include <signal.h>
51 #include <errno.h>
52 #include <sys/wait.h>
53 #include "test.h"
54
55 static void inthandlr();
56 static void do_exit(void);
57 static void setup_sigint(void);
58 static void do_child_1(void);
59 static void setup(void);
60 static void cleanup(void);
61
62 char *TCID = "waitpid08";
63 int TST_TOTAL = 1;
64 volatile int intintr;
65 static int fail;
66
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
78 int status;
79 int pid;
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 /* check for looping state if -i option is given */
93 for (lc = 0; TEST_LOOPING(lc); lc++) {
94 /* reset tst_count in case we are looping */
95 tst_count = 0;
96 fail = 0;
97
98 pid = FORK_OR_VFORK();
99 if (pid < 0) {
100 tst_resm(TFAIL, "Fork Failed, may be OK under stress");
101
102 } else if (pid == 0) {
103 /*
104 * Child:
105 * Set up to catch SIGINT.
106 * The kids will wait till a SIGINT has been received
107 * before they proceed.
108 */
109 #ifdef UCLINUX
110 if (self_exec(argv[0], "n", 1) < 0) {
111 tst_resm(TINFO, "self_exec failed");
112 exit(pid);
113 }
114 #else
115 do_child_1();
116 #endif
117 } else { /* parent */
118 waitpid(pid, &status, 0);
119 if (WEXITSTATUS(status) != 0) {
120 tst_resm(TFAIL, "child returned bad status");
121 fail = 1;
122 }
123 if (fail)
124 tst_resm(TFAIL, "%s FAILED", TCID);
125 else
126 tst_resm(TPASS, "%s PASSED", TCID);
127 }
128 }
129
130 cleanup();
131 tst_exit();
132 }
133
134 /*
135 * setup_sigint()
136 * Sets up a SIGINT handler
137 */
setup_sigint(void)138 static void setup_sigint(void)
139 {
140 if ((sig_t) signal(SIGINT, inthandlr) == SIG_ERR) {
141 tst_resm(TFAIL, "signal SIGINT failed. " "errno = %d", errno);
142 exit(-1);
143 }
144 }
145
do_child_1(void)146 static void do_child_1(void)
147 {
148 int kid_count, fork_kid_pid[MAXKIDS];
149 int ret_val;
150 int i, j, k, found;
151 int group1, group2;
152 int wait_kid_pid[MAXKIDS], status;
153
154 setup_sigint();
155
156 group1 = getpgrp();
157
158 for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
159 if (kid_count == (MAXKIDS / 2))
160 group2 = setpgrp();
161
162 intintr = 0;
163 ret_val = FORK_OR_VFORK();
164 if (ret_val == 0) {
165 #ifdef UCLINUX
166 if (self_exec(argv0, "n", 2) < 0) {
167 tst_resm(TFAIL, "Fork kid %d failed. "
168 "errno = %d", kid_count, errno);
169 exit(ret_val);
170 }
171 #else
172 do_exit();
173 #endif
174 }
175
176 if (ret_val < 0) {
177 tst_resm(TFAIL, "Fork kid %d failed. "
178 "errno = %d", kid_count, errno);
179 exit(ret_val);
180 }
181
182 /* parent */
183 fork_kid_pid[kid_count] = ret_val;
184 }
185
186 /* Check that waitpid with WNOHANG|WUNTRACED returns
187 * zero
188 */
189 ret_val = waitpid(-1, &status, WNOHANG | WUNTRACED);
190 if (ret_val != 0) {
191 tst_resm(TFAIL, "Waitpid returned wrong value");
192 tst_resm(TFAIL, "Expected 0 got %d", ret_val);
193 fail = 1;
194 }
195 #ifdef UCLINUX
196 /* Give the kids a chance to setup SIGINT again, since this is
197 * cleared by exec().
198 */
199 sleep(3);
200 #endif
201
202 /* Now send all the kids a SIGINT to tell them to
203 * proceed
204 */
205 for (i = 0; i < MAXKIDS; i++) {
206 if (kill(fork_kid_pid[i], SIGINT) < 0) {
207 tst_brkm(TFAIL, NULL, "Kill of child %d "
208 "failed, errno = %d", i, errno);
209 }
210 }
211
212 /*
213 * Wait till all kids have terminated. Stash away their
214 * pid's in an array.
215 */
216 kid_count = 0;
217 errno = 0;
218 while (((ret_val = waitpid(-1, &status, WUNTRACED)) !=
219 -1) || (errno == EINTR)) {
220 if (ret_val == -1)
221 continue;
222
223 if (!WIFEXITED(status)) {
224 if (!WIFSTOPPED(status)) {
225 tst_resm(TFAIL, "Child %d did "
226 "not stopped", ret_val);
227 fail = 1;
228 } else {
229 if (WSTOPSIG(status) != SIGSTOP) {
230 tst_resm(TFAIL,
231 "Child %d "
232 "exited with "
233 "wrong status", ret_val);
234 tst_resm(TFAIL,
235 "Expected "
236 "SIGSTOP got %d",
237 WSTOPSIG(status));
238 fail = 1;
239 }
240 }
241 if (kill(ret_val, SIGCONT) < 0) {
242 tst_resm(TFAIL, "Kill of child "
243 "%d failed, errno = %d",
244 ret_val, errno);
245 fail = 1;
246 }
247 }
248 wait_kid_pid[kid_count++] = ret_val;
249 }
250
251 /*
252 * Check that for every entry in the fork_kid_pid array,
253 * there is a matching pid in the wait_kid_pid array. If
254 * not, it's an error.
255 */
256 for (i = 0; i < kid_count; i++) {
257 found = 0;
258 for (j = 0; j < MAXKIDS; j++) {
259 if (fork_kid_pid[j] == wait_kid_pid[i]) {
260 found = 1;
261 break;
262 }
263 }
264 if (!found) {
265 tst_resm(TFAIL,
266 "Did not find a wait_kid_pid "
267 "for the fork_kid_pid of %d", wait_kid_pid[i]);
268 for (k = 0; k < MAXKIDS; k++) {
269 tst_resm(TFAIL,
270 "fork_kid_pid[%d] = "
271 "%d", k, fork_kid_pid[k]);
272 }
273 for (k = 0; k < kid_count; k++) {
274 tst_resm(TFAIL,
275 "wait_kid_pid[%d] = "
276 "%d", k, wait_kid_pid[k]);
277 }
278 fail = 1;
279 }
280 }
281
282 /*
283 * Check that waitpid(WUNTRACED) returns -1 when no
284 * stopped children
285 */
286 ret_val = waitpid(-1, &status, WUNTRACED);
287 if (ret_val != -1) {
288 tst_resm(TFAIL, "Waitpid returned wrong value.");
289 tst_resm(TFAIL, "Expected -1 got %d from "
290 "waitpid(WUNTRACED)", ret_val);
291 fail = 1;
292 }
293
294 if (errno != ECHILD) {
295 tst_resm(TFAIL, "Waitpid returned wrong errno.");
296 tst_resm(TFAIL, "Expected ECHILD got %d", errno);
297 fail = 1;
298 }
299
300 exit(fail);
301 }
302
303 #ifdef UCLINUX
304 /*
305 * do_child_2_uclinux()
306 * sets up sigint handler again, then calls the normal child 2 function
307 */
do_child_2_uclinux(void)308 static void do_child_2_uclinux(void)
309 {
310 setup_sigint();
311 do_exit();
312 }
313 #endif
314
setup(void)315 static void setup(void)
316 {
317 TEST_PAUSE;
318 }
319
cleanup(void)320 static void cleanup(void)
321 {
322 }
323
inthandlr(void)324 static void inthandlr(void)
325 {
326 intintr++;
327 }
328
wait_for_parent(void)329 static void wait_for_parent(void)
330 {
331 int testvar;
332
333 while (!intintr)
334 testvar = 0;
335 }
336
do_exit(void)337 static void do_exit(void)
338 {
339 wait_for_parent();
340 exit(3);
341 }
342