Home | History | Annotate | Download | only in waitpid
      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