Home | History | Annotate | Download | only in msgrcv
      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  *	msgrcv05.c
     23  *
     24  * DESCRIPTION
     25  *	msgrcv05 - test for EINTR error
     26  *
     27  * ALGORITHM
     28  *	create a message queue with read/write permissions
     29  *	loop if that option was specified
     30  *	fork a child who attempts to read a non-existent message with msgrcv()
     31  *	parent sends a SIGHUP to the child, then waits for the child to complete
     32  *	check the errno value
     33  *	  issue a PASS message if we get EINTR
     34  *	otherwise, the tests fails
     35  *	  issue a FAIL message
     36  *	child exits, parent calls cleanup
     37  *
     38  * USAGE:  <for command-line>
     39  *  msgrcv05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
     40  *     where,  -c n : Run n copies concurrently.
     41  *             -e   : Turn on errno logging.
     42  *	       -i n : Execute test n times.
     43  *	       -I x : Execute test for x seconds.
     44  *	       -P x : Pause for x seconds between iterations.
     45  *	       -t   : Turn on syscall timing.
     46  *
     47  * HISTORY
     48  *	03/2001 - Written by Wayne Boyer
     49  *      14/03/2008 Matthieu Fertr (Matthieu.Fertre (at) irisa.fr)
     50  *      - Fix concurrency issue. Due to the use of usleep function to
     51  *        synchronize processes, synchronization issues can occur on a loaded
     52  *        system. Fix this by using pipes to synchronize processes.
     53  *
     54  * RESTRICTIONS
     55  *	none
     56  */
     57 
     58 #include "test.h"
     59 #include "safe_macros.h"
     60 
     61 #include "ipcmsg.h"
     62 
     63 #include <sys/types.h>
     64 #include <sys/wait.h>
     65 
     66 void do_child(void);
     67 void cleanup(void);
     68 void setup(void);
     69 #ifdef UCLINUX
     70 #define PIPE_NAME	"msgrcv05"
     71 void do_child_uclinux(void);
     72 #endif
     73 
     74 char *TCID = "msgrcv05";
     75 int TST_TOTAL = 1;
     76 
     77 int msg_q_1 = -1;		/* The message queue id created in setup */
     78 
     79 MSGBUF rcv_buf;
     80 pid_t c_pid;
     81 
     82 int main(int ac, char **av)
     83 {
     84 	int lc;
     85 
     86 	tst_parse_opts(ac, av, NULL, NULL);
     87 
     88 #ifdef UCLINUX
     89 	maybe_run_child(&do_child_uclinux, "d", &msg_q_1);
     90 #endif
     91 
     92 	setup();		/* global setup */
     93 
     94 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     95 		tst_count = 0;
     96 
     97 		/*
     98 		 * fork a child that will attempt to read a non-existent
     99 		 * message from the queue
    100 		 */
    101 		if ((c_pid = FORK_OR_VFORK()) == -1)
    102 			tst_brkm(TBROK, cleanup, "could not fork");
    103 
    104 		if (c_pid == 0) {
    105 			/*
    106 			 * Attempt to read a message without IPC_NOWAIT.
    107 			 * With no message to read, the child sleeps.
    108 			 */
    109 
    110 #ifdef UCLINUX
    111 			if (self_exec(av[0], "d", msg_q_1) < 0)
    112 				tst_brkm(TBROK, cleanup, "could not self_exec");
    113 #else
    114 			do_child();
    115 #endif
    116 		} else {
    117 			TST_PROCESS_STATE_WAIT(cleanup, c_pid, 'S');
    118 
    119 			/* send a signal that must be caught to the child */
    120 			SAFE_KILL(cleanup, c_pid, SIGHUP);
    121 
    122 			waitpid(c_pid, NULL, 0);
    123 		}
    124 	}
    125 
    126 	cleanup();
    127 
    128 	tst_exit();
    129 }
    130 
    131 void do_child(void)
    132 {
    133 	TEST(msgrcv(msg_q_1, &rcv_buf, MSGSIZE, 1, 0));
    134 
    135 	if (TEST_RETURN != -1)
    136 		tst_brkm(TFAIL, NULL, "call succeeded unexpectedly");
    137 
    138 	switch (TEST_ERRNO) {
    139 	case EINTR:
    140 		tst_resm(TPASS, "got EINTR as expected");
    141 		break;
    142 	default:
    143 		tst_resm(TFAIL | TTERRNO,
    144 			 "call failed with an unexpected error");
    145 		break;
    146 	}
    147 
    148 	exit(0);
    149 }
    150 
    151 void sighandler(int sig)
    152 {
    153 	if (sig == SIGHUP)
    154 		return;
    155 	else
    156 		tst_brkm(TBROK, NULL, "unexpected signal %d received", sig);
    157 }
    158 
    159 #ifdef UCLINUX
    160 /*
    161  * do_child_uclinux() - capture signals again, then run do_child()
    162  */
    163 void do_child_uclinux(void)
    164 {
    165 	tst_sig(FORK, sighandler, cleanup);
    166 
    167 	do_child();
    168 }
    169 #endif
    170 
    171 /*
    172  * setup() - performs all the ONE TIME setup for this test.
    173  */
    174 void setup(void)
    175 {
    176 
    177 	tst_sig(FORK, sighandler, cleanup);
    178 
    179 	TEST_PAUSE;
    180 
    181 	/*
    182 	 * Create a temporary directory and cd into it.
    183 	 * This helps to ensure that a unique msgkey is created.
    184 	 * See ../lib/libipc.c for more information.
    185 	 */
    186 	tst_tmpdir();
    187 
    188 	msgkey = getipckey();
    189 
    190 	/* create a message queue with read/write permission */
    191 	if ((msg_q_1 = msgget(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW)) == -1)
    192 		tst_brkm(TBROK, cleanup, "Can't create message queue");
    193 }
    194 
    195 /*
    196  * cleanup() - performs all the ONE TIME cleanup for this test at completion
    197  * 	       or premature exit.
    198  */
    199 void cleanup(void)
    200 {
    201 	/* if it exists, remove the message queue that was created */
    202 	rm_queue(msg_q_1);
    203 
    204 	tst_rmdir();
    205 
    206 }
    207