Home | History | Annotate | Download | only in waitid
      1 /******************************************************************************/
      2 /* Copyright (c) Crackerjack Project., 2007                                   */
      3 /*                                                                            */
      4 /* This program is free software;  you can redistribute it and/or modify      */
      5 /* it under the terms of the GNU General Public License as published by       */
      6 /* the Free Software Foundation; either version 2 of the License, or          */
      7 /* (at your option) any later version.                                        */
      8 /*                                                                            */
      9 /* This program is distributed in the hope that it will be useful,            */
     10 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
     11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
     12 /* the GNU General Public License for more details.                           */
     13 /*                                                                            */
     14 /* You should have received a copy of the GNU General Public License along    */
     15 /* with this program; if not, write to the Free Software Foundation,  Inc.,   */
     16 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA                 */
     17 /*                                                                            */
     18 /******************************************************************************/
     19 /******************************************************************************/
     20 /*                                                                            */
     21 /* File:        waitid02.c                                           	      */
     22 /*                                                                            */
     23 /* Description: This tests the waitid() syscall                               */
     24 /*                                                                            */
     25 /* Usage:  <for command-line>                                                 */
     26 /* waitid02 [-c n] [-e][-i n] [-I x] [-p x] [-t]                              */
     27 /*      where,  -c n : Run n copies concurrently.                             */
     28 /*              -e   : Turn on errno logging.                                 */
     29 /*              -i n : Execute test n times.                                  */
     30 /*              -I x : Execute test for x seconds.                            */
     31 /*              -P x : Pause for x seconds between iterations.                */
     32 /*              -t   : Turn on syscall timing.                                */
     33 /*                                                                            */
     34 /* Total Tests: 1                                                             */
     35 /*                                                                            */
     36 /* Test Name:   waitid02                                                      */
     37 /* History:     Porting from Crackerjack to LTP is done by                    */
     38 /*              Manas Kumar Nayak maknayak (at) in.ibm.com>                        */
     39 /******************************************************************************/
     40 
     41 #define _XOPEN_SOURCE 500
     42 #include <stdio.h>
     43 #include <errno.h>
     44 #include <stdlib.h>
     45 #include <sys/wait.h>
     46 #include <sys/types.h>
     47 #include <unistd.h>
     48 #include <sys/stat.h>
     49 
     50 #include "test.h"
     51 #include "safe_macros.h"
     52 #include "lapi/syscalls.h"
     53 
     54 struct testcase_t {
     55 	const char *msg;
     56 	idtype_t idtype;
     57 	id_t id;
     58 	pid_t child;
     59 	int options;
     60 	int exp_ret;
     61 	int exp_errno;
     62 	void (*setup) (struct testcase_t *);
     63 	void (*cleanup) (struct testcase_t *);
     64 };
     65 
     66 static void setup(void);
     67 static void cleanup(void);
     68 
     69 static void setup2(struct testcase_t *);
     70 static void setup3(struct testcase_t *);
     71 static void setup4(struct testcase_t *);
     72 static void setup5(struct testcase_t *);
     73 static void setup6(struct testcase_t *);
     74 static void cleanup2(struct testcase_t *);
     75 static void cleanup5(struct testcase_t *);
     76 static void cleanup6(struct testcase_t *);
     77 
     78 struct testcase_t tdat[] = {
     79 	{
     80 		.msg = "WNOHANG",
     81 		.idtype = P_ALL,
     82 		.id = 0,
     83 		.options = WNOHANG,
     84 		.exp_ret = -1,
     85 		.exp_errno = EINVAL,
     86 	},
     87 	{
     88 		.msg = "WNOHANG | WEXITED no child",
     89 		.idtype = P_ALL,
     90 		.id = 0,
     91 		.options = WNOHANG | WEXITED,
     92 		.exp_ret = -1,
     93 		.exp_errno = ECHILD,
     94 	},
     95 	{
     96 		.msg = "WNOHANG | WEXITED with child",
     97 		.idtype = P_ALL,
     98 		.id = 0,
     99 		.options = WNOHANG | WEXITED,
    100 		.exp_ret = 0,
    101 		.setup = setup2,
    102 		.cleanup = cleanup2
    103 	},
    104 	{
    105 		.msg = "P_PGID, WEXITED wait for child",
    106 		.idtype = P_PGID,
    107 		.options = WEXITED,
    108 		.exp_ret = 0,
    109 		.setup = setup3,
    110 	},
    111 	{
    112 		.msg = "P_PID, WEXITED wait for child",
    113 		.idtype = P_PID,
    114 		.options = WEXITED,
    115 		.exp_ret = 0,
    116 		.setup = setup4,
    117 	},
    118 	{
    119 		.msg = "P_PID, WSTOPPED | WNOWAIT",
    120 		.idtype = P_PID,
    121 		.options = WSTOPPED | WNOWAIT,
    122 		.exp_ret = 0,
    123 		.setup = setup5,
    124 		.cleanup = cleanup5
    125 	},
    126 	{
    127 		.msg = "P_PID, WCONTINUED",
    128 		.idtype = P_PID,
    129 		.options = WCONTINUED,
    130 		.exp_ret = 0,
    131 		.setup = setup6,
    132 		.cleanup = cleanup6
    133 	},
    134 	{
    135 		.msg = "P_PID, WEXITED not a child of the calling process",
    136 		.idtype = P_PID,
    137 		.id = 1,
    138 		.options = WEXITED,
    139 		.exp_ret = -1,
    140 		.exp_errno = ECHILD,
    141 		.setup = setup2,
    142 		.cleanup = cleanup2
    143 	},
    144 
    145 };
    146 
    147 char *TCID = "waitid02";
    148 static int TST_TOTAL = ARRAY_SIZE(tdat);
    149 
    150 static void makechild(struct testcase_t *t, void (*childfn)(void))
    151 {
    152 	t->child = fork();
    153 	switch (t->child) {
    154 	case -1:
    155 		tst_brkm(TBROK | TERRNO, cleanup, "fork");
    156 		break;
    157 	case 0:
    158 		childfn();
    159 		exit(0);
    160 	}
    161 }
    162 
    163 static void wait4child(pid_t pid)
    164 {
    165 	int status;
    166 	SAFE_WAITPID(cleanup, pid, &status, 0);
    167 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
    168 		tst_resm(TFAIL, "child returns %d", status);
    169 }
    170 
    171 static void dummy_child(void)
    172 {
    173 }
    174 
    175 static void waiting_child(void)
    176 {
    177 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
    178 }
    179 
    180 static void stopped_child(void)
    181 {
    182 	kill(getpid(), SIGSTOP);
    183 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
    184 }
    185 
    186 static void setup2(struct testcase_t *t)
    187 {
    188 	makechild(t, waiting_child);
    189 }
    190 
    191 static void cleanup2(struct testcase_t *t)
    192 {
    193 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
    194 	wait4child(t->child);
    195 }
    196 
    197 static void setup3(struct testcase_t *t)
    198 {
    199 	t->id = getpgid(0);
    200 	makechild(t, dummy_child);
    201 }
    202 
    203 static void setup4(struct testcase_t *t)
    204 {
    205 	makechild(t, dummy_child);
    206 	t->id = t->child;
    207 }
    208 
    209 static void setup5(struct testcase_t *t)
    210 {
    211 	makechild(t, stopped_child);
    212 	t->id = t->child;
    213 }
    214 
    215 static void cleanup5(struct testcase_t *t)
    216 {
    217 	kill(t->child, SIGCONT);
    218 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
    219 	wait4child(t->child);
    220 }
    221 
    222 static void setup6(struct testcase_t *t)
    223 {
    224 	siginfo_t infop;
    225 	makechild(t, stopped_child);
    226 	t->id = t->child;
    227 	if (waitid(P_PID, t->child, &infop, WSTOPPED) != 0)
    228 		tst_brkm(TBROK | TERRNO, cleanup, "waitpid setup6");
    229 	kill(t->child, SIGCONT);
    230 }
    231 
    232 static void cleanup6(struct testcase_t *t)
    233 {
    234 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
    235 	wait4child(t->child);
    236 }
    237 
    238 static void setup(void)
    239 {
    240 	TEST_PAUSE;
    241 	tst_tmpdir();
    242 	TST_CHECKPOINT_INIT(tst_rmdir);
    243 }
    244 
    245 static void cleanup(void)
    246 {
    247 	tst_rmdir();
    248 	tst_exit();
    249 }
    250 
    251 static void test_waitid(struct testcase_t *t)
    252 {
    253 	siginfo_t infop;
    254 
    255 	if (t->setup)
    256 		t->setup(t);
    257 
    258 	tst_resm(TINFO, "%s", t->msg);
    259 	tst_resm(TINFO, "(%d) waitid(%d, %d, %p, %d)", getpid(), t->idtype,
    260 			t->id, &infop, t->options);
    261 	memset(&infop, 0, sizeof(infop));
    262 
    263 	TEST(waitid(t->idtype, t->id, &infop, t->options));
    264 	if (TEST_RETURN == t->exp_ret) {
    265 		if (TEST_RETURN == -1) {
    266 			if (TEST_ERRNO == t->exp_errno)
    267 				tst_resm(TPASS, "exp_errno=%d", t->exp_errno);
    268 			else
    269 				tst_resm(TFAIL|TTERRNO, "exp_errno=%d",
    270 					t->exp_errno);
    271 		} else {
    272 			tst_resm(TPASS, "ret: %d", t->exp_ret);
    273 		}
    274 	} else {
    275 		tst_resm(TFAIL|TTERRNO, "ret=%ld expected=%d",
    276 			TEST_RETURN, t->exp_ret);
    277 	}
    278 	tst_resm(TINFO, "si_pid = %d ; si_code = %d ; si_status = %d",
    279 			infop.si_pid, infop.si_code,
    280 			infop.si_status);
    281 
    282 	if (t->cleanup)
    283 		t->cleanup(t);
    284 }
    285 
    286 int main(int ac, char **av)
    287 {
    288 	int lc, testno;
    289 
    290 	tst_parse_opts(ac, av, NULL, NULL);
    291 
    292 	setup();
    293 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
    294 		tst_count = 0;
    295 		for (testno = 0; testno < TST_TOTAL; testno++)
    296 			test_waitid(&tdat[testno]);
    297 	}
    298 	cleanup();
    299 	tst_exit();
    300 }
    301