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 * waitpid06.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 * waitpid06 [-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 = "waitpid06";
60 int TST_TOTAL = 1;
61 volatile int intintr;
62 static void inthandlr();
63 static void do_exit(void);
64 static int flag;
65
66 #define FAILED 1
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 int fail = 0;
78 int pid;
79 int status;
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 for (lc = 0; TEST_LOOPING(lc); lc++) {
93 /* reset tst_count in case we are looping */
94 tst_count = 0;
95
96 pid = FORK_OR_VFORK();
97 if (pid < 0) {
98 tst_resm(TINFO, "Fork Failed, may be OK under stress");
99 exit(pid);
100 } else if (pid == 0) {
101 /*
102 * Child:
103 * Set up to catch SIGINT. The kids will wait till a
104 * SIGINT has been received before they proceed.
105 */
106 #ifdef UCLINUX
107 if (self_exec(argv[0], "n", 1) < 0) {
108 tst_resm(TINFO, "self_exec failed");
109 exit(pid);
110 }
111 #else
112 do_child_1();
113 #endif
114 } else { /* parent */
115 fail = 0;
116 waitpid(pid, &status, 0);
117 if (WEXITSTATUS(status) != 0) {
118 tst_resm(TFAIL, "child returned bad status");
119 fail = 1;
120 }
121 if (fail)
122 tst_resm(TFAIL, "%s FAILED", TCID);
123 else
124 tst_resm(TPASS, "%s PASSED", TCID);
125 }
126 }
127
128 cleanup();
129 tst_exit();
130 }
131
132 /*
133 * setup_sigint()
134 * Sets up a SIGINT handler
135 */
setup_sigint(void)136 static void setup_sigint(void)
137 {
138 if ((sig_t) signal(SIGINT, inthandlr) == SIG_ERR) {
139 tst_resm(TFAIL, "signal SIGINT failed. " "errno = %d", errno);
140 exit(-1);
141 }
142 }
143
do_child_1(void)144 static void do_child_1(void)
145 {
146 int kid_count, fork_kid_pid[MAXKIDS];
147 int ret_val;
148 int i, j, k, found;
149 int group1, group2;
150 int wait_kid_pid[MAXKIDS], status;
151
152 setup_sigint();
153
154 group1 = getpgrp();
155 for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
156 if (kid_count == (MAXKIDS / 2))
157 group2 = setpgrp();
158
159 intintr = 0;
160 ret_val = FORK_OR_VFORK();
161 if (ret_val == 0) { /* child */
162 #ifdef UCLINUX
163 if (self_exec(argv0, "n", 2) < 0) {
164 tst_resm(TFAIL, "Fork kid %d failed. "
165 "errno = %d", kid_count, errno);
166 exit(ret_val);
167 }
168 #else
169 do_exit();
170 #endif
171 } else if (ret_val < 0) {
172 tst_resm(TFAIL, "Fork kid %d failed. "
173 "errno = %d", kid_count, errno);
174 exit(ret_val);
175 }
176
177 /* parent */
178 fork_kid_pid[kid_count] = ret_val;
179 }
180
181 #ifdef UCLINUX
182 /* Give the kids a chance to setup SIGINT again, since this is
183 * cleared by exec().
184 */
185 sleep(3);
186 #endif
187
188 /* Now send all the kids a SIGINT to tell them to
189 * proceed
190 */
191 for (i = 0; i < MAXKIDS; i++) {
192 if (kill(fork_kid_pid[i], SIGINT) < 0) {
193 tst_resm(TFAIL, "Kill of child %d "
194 "failed, errno = %d", i, errno);
195 exit(-1);
196 }
197 }
198
199 /*
200 * Wait till all kids have terminated. Stash away their
201 * pid's in an array.
202 */
203 kid_count = 0;
204 errno = 0;
205 while (((ret_val = waitpid(-1, &status, 0)) != -1) || (errno == EINTR)) {
206 if (ret_val == -1)
207 continue;
208
209 if (!WIFEXITED(status)) {
210 tst_resm(TFAIL, "Child %d did not exit "
211 "normally", ret_val);
212 flag = FAILED;
213 printf("status: %d\n", status);
214 } else {
215 if (WEXITSTATUS(status) != 3) {
216 tst_resm(TFAIL, "Child %d"
217 "exited with wrong "
218 "status", ret_val);
219 tst_resm(TFAIL, "Expected 3 "
220 "got %d ", WEXITSTATUS(status));
221 flag = FAILED;
222 }
223 }
224 wait_kid_pid[kid_count++] = ret_val;
225 }
226
227 /*
228 * Check that for every entry in the fork_kid_pid array,
229 * there is a matching pid in the wait_kid_pid array. If
230 * not, it's an error.
231 */
232 for (i = 0; i < kid_count; i++) {
233 found = 0;
234 for (j = 0; j < MAXKIDS; j++) {
235 if (fork_kid_pid[j] == wait_kid_pid[i]) {
236 found = 1;
237 break;
238 }
239 }
240
241 if (!found) {
242 tst_resm(TFAIL, "Did not find a "
243 "wait_kid_pid for the "
244 "fork_kid_pid of %d", wait_kid_pid[i]);
245 for (k = 0; k < MAXKIDS; k++) {
246 tst_resm(TFAIL,
247 "fork_kid_pid[%d] = "
248 "%d", k, fork_kid_pid[k]);
249 }
250 for (k = 0; k < kid_count; k++) {
251 tst_resm(TFAIL,
252 "wait_kid_pid[%d] = "
253 "%d", k, wait_kid_pid[k]);
254 }
255 flag = FAILED;
256 }
257 }
258
259 if (flag)
260 exit(1);
261 else
262 exit(0);
263 }
264
265 #ifdef UCLINUX
266 /*
267 * do_child_2_uclinux()
268 * sets up sigint handler again, then calls the normal child 2 function
269 */
do_child_2_uclinux(void)270 static void do_child_2_uclinux(void)
271 {
272 setup_sigint();
273 do_exit();
274 }
275 #endif
276
setup(void)277 static void setup(void)
278 {
279 TEST_PAUSE;
280 }
281
cleanup(void)282 static void cleanup(void)
283 {
284 }
285
inthandlr(void)286 static void inthandlr(void)
287 {
288 intintr++;
289 }
290
wait_for_parent(void)291 static void wait_for_parent(void)
292 {
293 int testvar;
294
295 while (!intintr)
296 testvar = 0;
297 }
298
do_exit(void)299 static void do_exit(void)
300 {
301 wait_for_parent();
302 exit(3);
303 }
304