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