1 /* 2 * Copyright (c) International Business Machines Corp., 2002 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 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 * 18 * 06/30/2001 Port to Linux nsharoff (at) us.ibm.com 19 * 11/06/2002 Port to LTP dbarrera (at) us.ibm.com 20 */ 21 22 /* 23 * Get and manipulate a message queue. 24 * Same as msgctl08 but gets the actual msgmni value under procfs. 25 */ 26 27 #define _XOPEN_SOURCE 500 28 #include <signal.h> 29 #include <errno.h> 30 #include <string.h> 31 #include <fcntl.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <unistd.h> 35 #include <values.h> 36 #include <sys/types.h> 37 #include <sys/wait.h> 38 #include <sys/stat.h> 39 #include <sys/ipc.h> 40 #include <sys/msg.h> 41 #include "test.h" 42 #include "ipcmsg.h" 43 #include "../lib/libmsgctl.h" 44 45 char *TCID = "msgctl10"; 46 int TST_TOTAL = 1; 47 48 #define MAXNPROCS 10000 /*These should be sufficient */ 49 #define MAXNREPS 10000 /*Else they srewup the system un-necessarily */ 50 51 static key_t keyarray[MAXNPROCS]; 52 static int pidarray[MAXNPROCS]; 53 static int tid; 54 static int MSGMNI, nprocs, nreps; 55 static int procstat; 56 static int mykid; 57 58 void setup(void); 59 void cleanup(void); 60 61 static int dotest(key_t key, int child_process); 62 static void sig_handler(int signo); 63 64 static char *opt_nprocs; 65 static char *opt_nreps; 66 67 static option_t options[] = { 68 {"n:", NULL, &opt_nprocs}, 69 {"l:", NULL, &opt_nreps}, 70 {NULL, NULL, NULL}, 71 }; 72 73 static void usage(void) 74 { 75 printf(" -n Number of processes\n"); 76 printf(" -l Number of iterations\n"); 77 } 78 79 int main(int argc, char **argv) 80 { 81 int i, j, ok, pid; 82 int count, status; 83 struct sigaction act; 84 85 tst_parse_opts(argc, argv, options, usage); 86 87 setup(); 88 89 nreps = MAXNREPS; 90 nprocs = MSGMNI; 91 92 if (opt_nreps) { 93 nreps = atoi(opt_nreps); 94 if (nreps > MAXNREPS) { 95 tst_resm(TINFO, 96 "Requested number of iterations too large, " 97 "setting to Max. of %d", MAXNREPS); 98 nreps = MAXNREPS; 99 } 100 } 101 102 if (opt_nprocs) { 103 nprocs = atoi(opt_nprocs); 104 if (nprocs > MSGMNI) { 105 tst_resm(TINFO, 106 "Requested number of processes too large, " 107 "setting to Max. of %d", MSGMNI); 108 nprocs = MSGMNI; 109 } 110 } 111 112 srand(getpid()); 113 tid = -1; 114 115 /* Setup signal handling routine */ 116 memset(&act, 0, sizeof(act)); 117 act.sa_handler = sig_handler; 118 sigemptyset(&act.sa_mask); 119 sigaddset(&act.sa_mask, SIGTERM); 120 if (sigaction(SIGTERM, &act, NULL) < 0) { 121 tst_brkm(TFAIL, NULL, "Sigset SIGTERM failed"); 122 } 123 /* Set up array of unique keys for use in allocating message 124 * queues 125 */ 126 for (i = 0; i < nprocs; i++) { 127 ok = 1; 128 do { 129 /* Get random key */ 130 keyarray[i] = (key_t) rand(); 131 /* Make sure key is unique and not private */ 132 if (keyarray[i] == IPC_PRIVATE) { 133 ok = 0; 134 continue; 135 } 136 for (j = 0; j < i; j++) { 137 if (keyarray[j] == keyarray[i]) { 138 ok = 0; 139 break; 140 } 141 ok = 1; 142 } 143 } while (ok == 0); 144 } 145 146 /* Fork a number of processes, each of which will 147 * create a message queue with one reader/writer 148 * pair which will read and write a number (iterations) 149 * of random length messages with specific values. 150 */ 151 152 for (i = 0; i < nprocs; i++) { 153 fflush(stdout); 154 if ((pid = FORK_OR_VFORK()) < 0) { 155 tst_brkm(TFAIL, 156 NULL, 157 "\tFork failed (may be OK if under stress)"); 158 } 159 /* Child does this */ 160 if (pid == 0) { 161 procstat = 1; 162 exit(dotest(keyarray[i], i)); 163 } 164 pidarray[i] = pid; 165 } 166 167 count = 0; 168 while (1) { 169 if ((wait(&status)) > 0) { 170 if (status >> 8 != 0) { 171 tst_brkm(TFAIL, NULL, 172 "Child exit status = %d", 173 status >> 8); 174 } 175 count++; 176 } else { 177 if (errno != EINTR) { 178 break; 179 } 180 #ifdef DEBUG 181 tst_resm(TINFO, "Signal detected during wait"); 182 #endif 183 } 184 } 185 /* Make sure proper number of children exited */ 186 if (count != nprocs) { 187 tst_brkm(TFAIL, 188 NULL, 189 "Wrong number of children exited, Saw %d, Expected %d", 190 count, nprocs); 191 } 192 193 tst_resm(TPASS, "msgctl10 ran successfully!"); 194 195 cleanup(); 196 tst_exit(); 197 } 198 199 static int dotest(key_t key, int child_process) 200 { 201 int id, pid; 202 int ret, status; 203 204 sighold(SIGTERM); 205 TEST(msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR)); 206 if (TEST_RETURN < 0) { 207 printf("msgget() error in child %d: %s\n", 208 child_process, strerror(TEST_ERRNO)); 209 return FAIL; 210 } 211 tid = id = TEST_RETURN; 212 sigrelse(SIGTERM); 213 214 fflush(stdout); 215 if ((pid = FORK_OR_VFORK()) < 0) { 216 printf("Fork failed (may be OK if under stress)\n"); 217 TEST(msgctl(tid, IPC_RMID, 0)); 218 if (TEST_RETURN < 0) { 219 printf("msgctl() error in cleanup: %s\n", 220 strerror(TEST_ERRNO)); 221 } 222 return FAIL; 223 } 224 if (pid == 0) 225 exit(doreader(key, id, 1, child_process, nreps)); 226 227 mykid = pid; 228 procstat = 2; 229 ret = dowriter(key, id, 1, child_process, nreps); 230 wait(&status); 231 232 if (ret != PASS) 233 exit(FAIL); 234 235 if ((!WIFEXITED(status) || (WEXITSTATUS(status) != PASS))) 236 exit(FAIL); 237 238 TEST(msgctl(id, IPC_RMID, 0)); 239 if (TEST_RETURN < 0) { 240 printf("msgctl() failed: %s\n", 241 strerror(TEST_ERRNO)); 242 return FAIL; 243 } 244 return PASS; 245 } 246 247 static void sig_handler(int signo LTP_ATTRIBUTE_UNUSED) 248 { 249 } 250 251 void setup(void) 252 { 253 int nr_msgqs; 254 255 tst_tmpdir(); 256 257 tst_sig(FORK, DEF_HANDLER, cleanup); 258 259 TEST_PAUSE; 260 261 nr_msgqs = get_max_msgqueues(); 262 if (nr_msgqs < 0) 263 cleanup(); 264 265 MSGMNI = nr_msgqs - get_used_msgqueues(); 266 if (MSGMNI > MAXNPROCS) 267 MSGMNI = MAXNPROCS; 268 if (MSGMNI <= 0) { 269 tst_resm(TBROK, 270 "Max number of message queues already used, cannot create more."); 271 cleanup(); 272 } 273 } 274 275 void cleanup(void) 276 { 277 int status; 278 279 #ifdef DEBUG 280 tst_resm(TINFO, "Removing the message queue"); 281 #endif 282 (void)msgctl(tid, IPC_RMID, NULL); 283 if ((status = msgctl(tid, IPC_STAT, NULL)) != -1) { 284 (void)msgctl(tid, IPC_RMID, NULL); 285 tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed"); 286 287 } 288 289 tst_rmdir(); 290 } 291