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