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