waitpid07.c revision 9736c6b06b071213e08079dfcfc9117b0defdb9e
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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#include <usctest.h> 54 55void setup_sigint(void); 56void do_child_1(void); 57void setup(void); 58void cleanup(void); 59 60char *TCID = "waitpid07"; 61int TST_TOTAL = 1; 62extern int Tst_count; 63 64volatile int intintr; 65int flag = 0; 66void inthandlr(); 67void do_exit(); 68 69#define FAILED 1 70#define MAXKIDS 8 71 72#ifdef UCLINUX 73static char *argv0; 74void do_child_2_uclinux(void); 75#endif 76 77int main(int argc, char **argv) 78{ 79 int lc; /* loop counter */ 80 char *msg; /* message returned from parse_opts */ 81 82 int status; 83 int fail = 0; 84 int pid; 85 86 /* parse standard options */ 87 if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != 88 (char *)NULL) { 89 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 90 tst_exit(); 91 /*NOTREACHED*/ 92 } 93 94#ifdef UCLINUX 95 argv0 = argv[0]; 96 97 maybe_run_child(&do_child_1, "n", 1); 98 maybe_run_child(&do_child_2_uclinux, "n", 2); 99#endif 100 101 setup(); 102 103 /* check for looping state if -i option is given */ 104 for (lc = 0; TEST_LOOPING(lc); lc++) { 105 /* reset Tst_count in case we are looping */ 106 Tst_count = 0; 107 108 if ((pid = FORK_OR_VFORK()) < 0) { 109 tst_resm(TFAIL, "Fork Failed, may be OK under stress"); 110 tst_exit(); 111 } else if (pid == 0) { 112 113 /* 114 * Child: 115 * Set up to catch SIGINT. The kids will wait till a 116 * SIGINT has been received before they proceed. 117 */ 118#ifdef UCLINUX 119 if (self_exec(argv[0], "n", 1) < 0) { 120 tst_resm(TINFO, "self_exec failed"); 121 exit(pid); 122 } 123#else 124 do_child_1(); 125#endif 126 } else { /* parent */ 127 fail = 0; 128 waitpid(pid, &status, 0); 129 if (WEXITSTATUS(status) != 0) { 130 tst_resm(TFAIL, "child returned bad status"); 131 fail = 1; 132 } 133 if (fail) { 134 tst_resm(TFAIL, "%s FAILED", TCID); 135 } else { 136 tst_resm(TPASS, "%s PASSED", TCID); 137 } 138 } 139 } 140 cleanup(); 141 /*NOTREACHED*/ 142 143 return(0); 144 145} 146 147/* 148 * setup_sigint() 149 * Sets up a SIGINT handler 150 */ 151void 152setup_sigint(void) 153{ 154 if ((sig_t)signal(SIGINT, inthandlr) == SIG_ERR ) { 155 tst_resm(TFAIL, "signal SIGINT failed. " 156 "errno = %d", errno); 157 exit(-1); 158 } 159} 160 161/* 162 * do_child_1() 163 */ 164void 165do_child_1(void) 166{ 167 int kid_count, fork_kid_pid[MAXKIDS]; 168 int ret_val; 169 int i, j, k, found; 170 int group1, group2; 171 int wait_kid_pid[MAXKIDS], status; 172 173 setup_sigint(); 174 175 group1 = getpgrp(); 176 177 for (kid_count = 0; kid_count < MAXKIDS; kid_count++) { 178 if (kid_count == (MAXKIDS / 2)) { 179 group2 = setpgrp(); 180 } 181 182 intintr = 0; 183 ret_val = FORK_OR_VFORK(); 184 if (ret_val == 0) { 185#ifdef UCLINUX 186 if (self_exec(argv0, "n", 2) < 0) { 187 tst_resm(TFAIL, "Fork kid %d failed. " 188 "errno = %d", kid_count, 189 errno); 190 exit(ret_val); 191 } 192#else 193 do_exit(); 194#endif 195 /*NOTREACHED*/ 196 } 197 198 if (ret_val < 0) { 199 tst_resm(TFAIL, "Fork kid %d failed. " 200 "errno = %d", kid_count, errno); 201 tst_exit(); 202 } 203 204 /* parent */ 205 fork_kid_pid[kid_count] = ret_val; 206 } 207 208 /* Check that waitpid with WNOHANG returns zero */ 209 if ((ret_val = waitpid(-1, &status, WNOHANG)) != 0) { 210 tst_resm(TFAIL, "Waitpid returned wrong value"); 211 tst_resm(TFAIL, "Expected 0 got %d", 212 ret_val); 213 flag = FAILED; 214 } 215 216#ifdef UCLINUX 217 /* Give the kids a chance to setup SIGINT again, since this is 218 * cleared by exec(). 219 */ 220 sleep(3); 221#endif 222 223 /* Now send all the kids a SIGINT to tell them to 224 * proceed 225 */ 226 for (i = 0; i < MAXKIDS; i++) { 227 if (kill(fork_kid_pid[i], SIGINT) < 0) { 228 tst_resm(TFAIL, "Kill of child %d " 229 "failed, errno = %d", i, errno); 230 tst_exit(); 231 } 232 } 233 234 /* 235 * Wait till all kids have terminated. Stash away their 236 * pid's in an array. 237 */ 238 kid_count = 0; 239 errno = 0; 240 while (((ret_val = waitpid(-1, &status, WNOHANG)) != -1) 241 || (errno == EINTR)) { 242 if ((ret_val == -1) || (ret_val == 0)) { 243 continue; 244 } 245 246 if (!WIFEXITED(status)) { 247 tst_resm(TFAIL, "Child %d did not exit " 248 "normally", ret_val); 249 flag = FAILED; 250 } else { 251 if (WEXITSTATUS(status) != 3) { 252 tst_resm(TFAIL, "Child %d " 253 "exited with wrong " 254 "status", ret_val); 255 tst_resm(TFAIL, "Expected 3 " 256 "got %d ", 257 WEXITSTATUS(status)); 258 flag = FAILED; 259 } 260 } 261 wait_kid_pid[kid_count++] = ret_val; 262 } 263 264 /* 265 * Check that for every entry in the fork_kid_pid array, 266 * there is a matching pid in the wait_kid_pid array. If 267 * not, it's an error. 268 */ 269 for (i = 0; i < kid_count; i++) { 270 found = 0; 271 for (j = 0; j < MAXKIDS; j++) { 272 if (fork_kid_pid[j] == wait_kid_pid[i]){ 273 found = 1; 274 break; 275 } 276 } 277 278 if (!found) { 279 tst_resm(TFAIL, "Did not find a " 280 "wait_kid_pid for the " 281 "fork_kid_pid of %d", 282 wait_kid_pid[i]); 283 for (k = 0; k < MAXKIDS; k++) { 284 tst_resm(TFAIL, 285 "fork_kid_pid[%d] = " 286 "%d", k, 287 fork_kid_pid[k]); 288 } 289 for (k = 0; k < kid_count; k++) { 290 tst_resm(TFAIL, 291 "wait_kid_pid[%d] = " 292 "%d", k, 293 wait_kid_pid[k]); 294 } 295 flag = FAILED; 296 } 297 } 298 299 if (flag) { 300 exit(1); 301 } else { 302 exit(0); 303 } 304} 305 306#ifdef UCLINUX 307/* 308 * do_child_2_uclinux() 309 * sets up sigint handler again, then calls the normal child 2 function 310 */ 311void 312do_child_2_uclinux(void) 313{ 314 setup_sigint(); 315 do_exit(); 316} 317#endif 318 319/* 320 * setup() 321 * performs all ONE TIME setup for this test 322 */ 323void 324setup(void) 325{ 326 /* Pause if that option was specified 327 * TEST_PAUSE contains the code to fork the test with the -c option. 328 */ 329 TEST_PAUSE; 330} 331 332/* 333 * cleanup() 334 * performs all ONE TIME cleanup for this test at 335 * completion or premature exit 336 */ 337void 338cleanup(void) 339{ 340 /* 341 * print timing stats if that option was specified. 342 * print errno log if that option was specified. 343 */ 344 TEST_CLEANUP; 345 346 /* exit with return code appropriate for results */ 347 tst_exit(); 348 /*NOTREACHED*/ 349} 350 351void 352inthandlr() 353{ 354 intintr++; 355} 356 357void 358wait_for_parent() 359{ 360 int testvar; 361 362 while (!intintr) { 363 testvar = 0; 364 } 365} 366 367void 368do_exit() 369{ 370 wait_for_parent(); 371 exit(3); 372} 373