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 66char *TCID = "waitpid09"; 67int TST_TOTAL = 1; 68volatile int intintr; 69 70static void setup(void); 71static void cleanup(void); 72static void inthandlr(); 73static void do_exit(void); 74static void setup_sigint(void); 75#ifdef UCLINUX 76static void do_exit_uclinux(void); 77#endif 78 79int 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 */ 257static 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 265static void setup(void) 266{ 267 TEST_PAUSE; 268} 269 270static void cleanup(void) 271{ 272} 273 274static void inthandlr(void) 275{ 276 intintr++; 277} 278 279static void wait_for_parent(void) 280{ 281 int testvar; 282 while (!intintr) 283 testvar = 0; 284} 285 286static 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 */ 297static void do_exit_uclinux(void) 298{ 299 setup_sigint(); 300 do_exit(); 301} 302#endif 303