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 * waitpid09.c
23 *
24 * DESCRIPTION
25 * Check ability of parent to wait until child returns, and that the
26 * child's process id is returned through the waitpid. Check that
27 * waitpid returns immediately if no child is present.
28 *
29 * ALGORITHM
30 * case 0:
31 * Parent forks a child and waits. Parent should do nothing
32 * further until child returns. The pid of the forked child
33 * should match the returned value from the waitpid.
34 *
35 * case 1:
36 * Parent calls a waitpid with no children waiting. Waitpid
37 * should return a -1 since there are no children to wait for.
38 *
39 * USAGE: <for command-line>
40 * waitpid09 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
41 * where, -c n : Run n copies concurrently.
42 * -e : Turn on errno logging.
43 * -i n : Execute test n times.
44 * -I x : Execute test for x seconds.
45 * -P x : Pause for x seconds between iterations.
46 * -t : Turn on syscall timing.
47 *
48 * History
49 * 07/2001 John George
50 * -Ported
51 * 04/2002 wjhuie sigset cleanups
52 *
53 * Restrictions
54 * None
55 */
56
57 #define _GNU_SOURCE 1
58 #include <sys/types.h>
59 #include <signal.h>
60 #include <errno.h>
61 #include <sys/wait.h>
62 #include <stdlib.h>
63
64 #include "test.h"
65
66 char *TCID = "waitpid09";
67 int TST_TOTAL = 1;
68 volatile int intintr;
69
70 static void setup(void);
71 static void cleanup(void);
72 static void inthandlr();
73 static void do_exit(void);
74 static void setup_sigint(void);
75 #ifdef UCLINUX
76 static void do_exit_uclinux(void);
77 #endif
78
main(int argc,char ** argv)79 int main(int argc, char **argv)
80 {
81 int lc;
82
83 int fail, pid, status, ret;
84
85 tst_parse_opts(argc, argv, NULL, NULL);
86
87 #ifdef UCLINUX
88 maybe_run_child(&do_exit_uclinux, "");
89 #endif
90
91 setup();
92
93 pid = FORK_OR_VFORK();
94 if (pid < 0) {
95 tst_brkm(TFAIL, cleanup, "Fork Failed");
96 } else if (pid == 0) {
97 /*
98 * Child:
99 * Set up to catch SIGINT. The kids will wait till a
100 * SIGINT has been received before they proceed.
101 */
102 setup_sigint();
103
104 /* check for looping state if -i option is given */
105 for (lc = 0; TEST_LOOPING(lc); lc++) {
106 /* reset tst_count in case we are looping */
107 tst_count = 0;
108
109 intintr = 0;
110
111 fail = 0;
112 pid = FORK_OR_VFORK();
113 if (pid < 0) {
114 tst_brkm(TFAIL, cleanup, "Fork failed.");
115 } else if (pid == 0) { /* child */
116 #ifdef UCLINUX
117 if (self_exec(argv[0], "") < 0) {
118 tst_brkm(TFAIL, cleanup,
119 "self_exec failed");
120 }
121 #else
122 do_exit();
123 #endif
124 } else { /* parent */
125
126 /*
127 *Check that waitpid with WNOHANG returns zero
128 */
129 while (((ret = waitpid(pid, &status, WNOHANG))
130 != 0) || (errno == EINTR)) {
131 if (ret == -1)
132 continue;
133
134 tst_resm(TFAIL, "return value for "
135 "WNOHANG expected 0 got %d",
136 ret);
137 fail = 1;
138 }
139 #ifdef UCLINUX
140 /* Give the kids a chance to setup SIGINT again, since
141 * this is cleared by exec().
142 */
143 sleep(3);
144 #endif
145
146 /* send SIGINT to child to tell it to proceed */
147 if (kill(pid, SIGINT) < 0) {
148 tst_resm(TFAIL, "Kill of child failed, "
149 "errno = %d", errno);
150 fail = 1;
151 }
152
153 while (((ret = waitpid(pid, &status, 0)) != -1)
154 || (errno == EINTR)) {
155 if (ret == -1)
156 continue;
157
158 if (ret != pid) {
159 tst_resm(TFAIL, "Expected %d "
160 "got %d as proc id of "
161 "child", pid, ret);
162 fail = 1;
163 }
164
165 if (status != 0) {
166 tst_resm(TFAIL, "status value "
167 "got %d expected 0",
168 status);
169 fail = 1;
170 }
171 }
172 }
173
174 pid = FORK_OR_VFORK();
175 if (pid < 0) {
176 tst_brkm(TFAIL, cleanup, "Second fork failed.");
177 } else if (pid == 0) { /* child */
178 exit(0);
179 } else { /* parent */
180 /* Give the child time to startup and exit */
181 sleep(2);
182
183 while (((ret = waitpid(pid, &status, WNOHANG))
184 != -1) || (errno == EINTR)) {
185 if (ret == -1)
186 continue;
187
188 if (ret != pid) {
189 tst_resm(TFAIL, "proc id %d "
190 "and retval %d do not "
191 "match", pid, ret);
192 fail = 1;
193 }
194
195 if (status != 0) {
196 tst_resm(TFAIL, "non zero "
197 "status received %d",
198 status);
199 fail = 1;
200 }
201 }
202 }
203
204 if (fail)
205 tst_resm(TFAIL, "case 1 FAILED");
206 else
207 tst_resm(TPASS, "case 1 PASSED");
208
209 fail = 0;
210 ret = waitpid(pid, &status, 0);
211
212 if (ret != -1) {
213 tst_resm(TFAIL, "Expected -1 got %d", ret);
214 fail = 1;
215 }
216 if (errno != ECHILD) {
217 tst_resm(TFAIL, "Expected ECHILD got %d",
218 errno);
219 fail = 1;
220 }
221
222 ret = waitpid(pid, &status, WNOHANG);
223 if (ret != -1) {
224 tst_resm(TFAIL, "WNOHANG: Expected -1 got %d",
225 ret);
226 fail = 1;
227 }
228 if (errno != ECHILD) {
229 tst_resm(TFAIL, "WNOHANG: Expected ECHILD got "
230 "%d", errno);
231 fail = 1;
232 }
233
234 if (fail)
235 tst_resm(TFAIL, "case 2 FAILED");
236 else
237 tst_resm(TPASS, "case 2 PASSED");
238 }
239
240 cleanup();
241 } else {
242 /* wait for the child to return */
243 waitpid(pid, &status, 0);
244 if (WEXITSTATUS(status) != 0) {
245 tst_brkm(TBROK, cleanup, "child returned bad "
246 "status");
247 }
248 }
249
250 tst_exit();
251 }
252
253 /*
254 * setup_sigint()
255 * sets up a SIGINT handler
256 */
setup_sigint(void)257 static void setup_sigint(void)
258 {
259 if ((sig_t) signal(SIGINT, inthandlr) == SIG_ERR) {
260 tst_brkm(TFAIL, cleanup, "signal SIGINT failed, errno = %d",
261 errno);
262 }
263 }
264
setup(void)265 static void setup(void)
266 {
267 TEST_PAUSE;
268 }
269
cleanup(void)270 static void cleanup(void)
271 {
272 }
273
inthandlr(void)274 static void inthandlr(void)
275 {
276 intintr++;
277 }
278
wait_for_parent(void)279 static void wait_for_parent(void)
280 {
281 int testvar;
282 while (!intintr)
283 testvar = 0;
284 }
285
do_exit(void)286 static void do_exit(void)
287 {
288 wait_for_parent();
289 exit(0);
290 }
291
292 #ifdef UCLINUX
293 /*
294 * do_exit_uclinux()
295 * Sets up SIGINT handler again, then calls do_exit
296 */
do_exit_uclinux(void)297 static void do_exit_uclinux(void)
298 {
299 setup_sigint();
300 do_exit();
301 }
302 #endif
303