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 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 */ 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 265 static void setup(void) 266 { 267 TEST_PAUSE; 268 } 269 270 static void cleanup(void) 271 { 272 } 273 274 static void inthandlr(void) 275 { 276 intintr++; 277 } 278 279 static void wait_for_parent(void) 280 { 281 int testvar; 282 while (!intintr) 283 testvar = 0; 284 } 285 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 */ 297 static void do_exit_uclinux(void) 298 { 299 setup_sigint(); 300 do_exit(); 301 } 302 #endif 303