msgctl08.c revision 53740500924f6439623a8ac256b5be2d6c59ed1f
1/* 2 * 3 * Copyright (c) International Business Machines Corp., 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ 21/* 11/06/2002 Port to LTP dbarrera@us.ibm.com */ 22 23/* 24 * NAME 25 * msgctl08 26 * 27 * CALLS 28 * msgget(2) msgctl(2) 29 * 30 * ALGORITHM 31 * Get and manipulate a message queue. 32 * 33 * RESTRICTIONS 34 * 35 */ 36 37#define _XOPEN_SOURCE 500 38#include <signal.h> 39#include <errno.h> 40#include <string.h> 41#include <fcntl.h> 42#include <stdlib.h> 43#include <stdio.h> 44#include <unistd.h> 45#include <values.h> 46#include <sys/types.h> 47#include <sys/wait.h> 48#include <sys/stat.h> 49#include <sys/ipc.h> 50#include <sys/msg.h> 51#include "test.h" 52#include "usctest.h" 53#include "ipcmsg.h" 54 55void setup(); 56void cleanup(); 57/* 58 * * * * These globals must be defined in the test. 59 * * * */ 60 61char *TCID = "msgctl08"; /* Test program identifier. */ 62int TST_TOTAL = 1; /* Total number of test cases. */ 63extern int Tst_count; /* Test Case counter for tst_* routines */ 64 65int exp_enos[] = { 0 }; /* List must end with 0 */ 66 67#ifndef CONFIG_COLDFIRE 68#define MAXNPROCS 1000000 /* This value is set to an arbitrary high limit. */ 69#else 70#define MAXNPROCS 100000 /* Coldfire can't deal with 1000000 */ 71#endif 72#define MAXNREPS 100000 73#define FAIL 1 74#define PASS 0 75 76key_t keyarray[MAXNPROCS]; 77 78struct { 79 long type; 80 struct { 81 char len; 82 char pbytes[99]; 83 } data; 84} buffer; 85 86int pidarray[MAXNPROCS]; 87int tid; 88int MSGMNI, nprocs, nreps; 89int procstat; 90int dotest(key_t key, int child_process); 91int doreader(int id, long key, int child); 92int dowriter(int id, long key, int child); 93int fill_buffer(register char *buf, char val, register int size); 94int verify(register char *buf, char val, register int size, int child); 95void sig_handler(); /* signal catching function */ 96int mykid; 97#ifdef UCLINUX 98static char *argv0; 99 100void do_child_1_uclinux(); 101static key_t key_uclinux; 102static int i_uclinux; 103 104void do_child_2_uclinux(); 105static int id_uclinux; 106static int child_process_uclinux; 107#endif 108 109/*-----------------------------------------------------------------*/ 110int main(argc, argv) 111int argc; 112char *argv[]; 113{ 114 register int i, j, ok, pid; 115 int count, status; 116 struct sigaction act; 117 118#ifdef UCLINUX 119 char *msg; /* message returned from parse_opts */ 120 121 argv0 = argv[0]; 122 123 /* parse standard options */ 124 if ((msg = 125 parse_opts(argc, argv, NULL, NULL)) != NULL) { 126<<<<<<< HEAD 127 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 128======= 129 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg); 130>>>>>>> master 131 } 132 133 maybe_run_child(&do_child_1_uclinux, "ndd", 1, &key_uclinux, 134 &i_uclinux); 135 maybe_run_child(&do_child_2_uclinux, "nddd", 2, &id_uclinux, 136 &key_uclinux, &child_process_uclinux); 137#endif 138 139 setup(); 140 141 if (argc == 1) { 142 /* Set default parameters */ 143 nreps = MAXNREPS; 144 nprocs = MSGMNI; 145 } else if (argc == 3) { 146 if (atoi(argv[1]) > MAXNREPS) { 147 tst_resm(TCONF, 148 "Requested number of iterations too large, setting to Max. of %d", 149 MAXNREPS); 150 nreps = MAXNREPS; 151 } else { 152 nreps = atoi(argv[1]); 153 } 154 if (atoi(argv[2]) > MSGMNI) { 155 tst_resm(TCONF, 156 "Requested number of processes too large, setting to Max. of %d", 157 MSGMNI); 158 nprocs = MSGMNI; 159 } else { 160 nprocs = atoi(argv[2]); 161 } 162 } else { 163 tst_resm(TCONF, 164 " Usage: %s [ number of iterations number of processes ]", 165 argv[0]); 166 tst_exit(); 167 } 168 169 srand(getpid()); 170 tid = -1; 171 172 /* Setup signal handleing routine */ 173 memset(&act, 0, sizeof(act)); 174 act.sa_handler = sig_handler; 175 sigemptyset(&act.sa_mask); 176 sigaddset(&act.sa_mask, SIGTERM); 177 if (sigaction(SIGTERM, &act, NULL) < 0) { 178 tst_resm(TFAIL, "Sigset SIGTERM failed"); 179 tst_exit(); 180 } 181 /* Set up array of unique keys for use in allocating message 182 * queues 183 */ 184 for (i = 0; i < nprocs; i++) { 185 ok = 1; 186 do { 187 /* Get random key */ 188 keyarray[i] = (key_t) rand(); 189 /* Make sure key is unique and not private */ 190 if (keyarray[i] == IPC_PRIVATE) { 191 ok = 0; 192 continue; 193 } 194 for (j = 0; j < i; j++) { 195 if (keyarray[j] == keyarray[i]) { 196 ok = 0; 197 break; 198 } 199 ok = 1; 200 } 201 } while (ok == 0); 202 } 203 204 /* Fork a number of processes, each of which will 205 * create a message queue with one reader/writer 206 * pair which will read and write a number (iterations) 207 * of random length messages with specific values. 208 */ 209 210 for (i = 0; i < nprocs; i++) { 211 fflush(stdout); 212 if ((pid = FORK_OR_VFORK()) < 0) { 213 tst_resm(TFAIL, 214 "\tFork failed (may be OK if under stress)"); 215 tst_exit(); 216 } 217 /* Child does this */ 218 if (pid == 0) { 219#ifdef UCLINUX 220 if (self_exec(argv[0], "ndd", 1, keyarray[i], i) < 0) { 221 tst_resm(TFAIL, "\tself_exec failed"); 222 tst_exit(); 223 } 224#else 225 procstat = 1; 226 exit(dotest(keyarray[i], i)); 227#endif 228 } 229 pidarray[i] = pid; 230 } 231 232 count = 0; 233 while (1) { 234 if ((wait(&status)) > 0) { 235 if (status >> 8 != 0) { 236 tst_resm(TFAIL, "Child exit status = %d", 237 status >> 8); 238 tst_exit(); 239 } 240 count++; 241 } else { 242 if (errno != EINTR) { 243 break; 244 } 245#ifdef DEBUG 246 tst_resm(TINFO, "Signal detected during wait"); 247#endif 248 } 249 } 250 /* Make sure proper number of children exited */ 251 if (count != nprocs) { 252 tst_resm(TFAIL, 253 "Wrong number of children exited, Saw %d, Expected %d", 254 count, nprocs); 255 tst_exit(); 256 } 257 258 tst_resm(TPASS, "msgctl08 ran successfully!"); 259 260 cleanup(); 261 return (0); 262 263} 264 265/*--------------------------------------------------------------------*/ 266 267#ifdef UCLINUX 268void do_child_1_uclinux() 269{ 270 procstat = 1; 271 exit(dotest(key_uclinux, i_uclinux)); 272} 273 274void do_child_2_uclinux() 275{ 276 exit(doreader(id_uclinux, key_uclinux % 255, child_process_uclinux)); 277} 278#endif 279 280int dotest(key, child_process) 281key_t key; 282int child_process; 283{ 284 int id, pid; 285 286 sighold(SIGTERM); 287 TEST(msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR)); 288 if (TEST_RETURN < 0) { 289 tst_resm(TFAIL|TTERRNO, "Msgget error in child %d", 290 child_process); 291 tst_exit(); 292 } 293 tid = id = TEST_RETURN; 294 sigrelse(SIGTERM); 295 296 fflush(stdout); 297 if ((pid = FORK_OR_VFORK()) < 0) { 298 tst_resm(TWARN, "\tFork failed (may be OK if under stress)"); 299 TEST(msgctl(tid, IPC_RMID, 0)); 300 if (TEST_RETURN < 0) { 301 tst_resm(TFAIL|TTERRNO, "Msgctl error in cleanup"); 302 } 303 tst_exit(); 304 } 305 /* Child does this */ 306 if (pid == 0) { 307#ifdef UCLINUX 308 if (self_exec(argv0, "nddd", 2, id, key, child_process) < 0) { 309 tst_resm(TWARN, "self_exec failed"); 310 TEST(msgctl(tid, IPC_RMID, 0)); 311 if (TEST_RETURN < 0) { 312 tst_resm(TFAIL|TTERRNO, "Msgctl error in cleanup"); 313 } 314 tst_exit(); 315 } 316#else 317 exit(doreader(id, key % 255, child_process)); 318#endif 319 } 320 /* Parent does this */ 321 mykid = pid; 322 procstat = 2; 323 dowriter(id, key % 255, child_process); 324 wait(0); 325 TEST(msgctl(id, IPC_RMID, 0)); 326 if (TEST_RETURN < 0) { 327 tst_resm(TFAIL, "msgctl errno %d", TEST_ERRNO); 328 tst_exit(); 329 } 330 exit(PASS); 331} 332 333int doreader(id, key, child) 334int id, child; 335long key; 336{ 337 int i, size; 338 339 for (i = 0; i < nreps; i++) { 340 if ((size = msgrcv(id, &buffer, 100, 0, 0)) < 0) { 341 tst_brkm(TBROK|TERRNO, cleanup, 342 "Msgrcv error in child %d, read # = %d", 343 (i + 1), child); 344 tst_exit(); 345 } 346 if (buffer.data.len + 1 != size) { 347 tst_resm(TFAIL, 348 "Size mismatch in child %d, read # = %d", 349 child, (i + 1)); 350 tst_resm(TFAIL, 351 "for message size got %d expected %d", 352 size, buffer.data.len); 353 tst_exit(); 354 } 355 if (verify(buffer.data.pbytes, key, size - 1, child)) { 356 tst_resm(TFAIL, "in child %d read # = %d,key = %lx", 357 child, (i + 1), key); 358 tst_exit(); 359 } 360 key++; 361 } 362 return (0); 363} 364 365int dowriter(id, key, child) 366int id, child; 367long key; 368{ 369 int i, size; 370 371 for (i = 0; i < nreps; i++) { 372 do { 373 size = (rand() % 99); 374 } while (size == 0); 375 fill_buffer(buffer.data.pbytes, key, size); 376 buffer.data.len = size; 377 buffer.type = 1; 378 TEST(msgsnd(id, &buffer, size + 1, 0)); 379 if (TEST_RETURN < 0) { 380 tst_brkm(TBROK|TTERRNO, cleanup, 381 "Msgsnd error in child %d, key = %lx", 382 child, key); 383 } 384 key++; 385 } 386 return (0); 387} 388 389int fill_buffer(buf, val, size) 390register char *buf; 391char val; 392register int size; 393{ 394 register int i; 395 396 for (i = 0; i < size; i++) { 397 buf[i] = val; 398 } 399 400 return (0); 401} 402 403/* 404 * verify() 405 * Check a buffer for correct values. 406 */ 407 408int verify(buf, val, size, child) 409register char *buf; 410char val; 411register int size; 412int child; 413{ 414 while (size-- > 0) { 415 if (*buf++ != val) { 416 tst_resm(TWARN, 417 "Verify error in child %d, *buf = %x, val = %x, size = %d", 418 child, *buf, val, size); 419 return (FAIL); 420 } 421 } 422 return (PASS); 423} 424 425/* 426 * * void 427 * * sig_handler() - signal catching function for 'SIGUSR1' signal. 428 * * 429 * * This is a null function and used only to catch the above signal 430 * * generated in parent process. 431 * */ 432void sig_handler() 433{ 434} 435 436/*************************************************************** 437 * setup() - performs all ONE TIME setup for this test. 438 *****************************************************************/ 439void setup() 440{ 441 int nr_msgqs; 442 443 tst_tmpdir(); 444 445 /* You will want to enable some signal handling so you can capture 446 * unexpected signals like SIGSEGV. 447 */ 448 tst_sig(FORK, DEF_HANDLER, cleanup); 449 450 /* Pause if that option was specified */ 451 /* One cavet that hasn't been fixed yet. TEST_PAUSE contains the code to 452 * fork the test with the -c option. You want to make sure you do this 453 * before you create your temporary directory. 454 */ 455 TEST_PAUSE; 456 457 nr_msgqs = get_max_msgqueues(); 458 if (nr_msgqs < 0) 459 cleanup(); 460 461 nr_msgqs -= get_used_msgqueues(); 462 if (nr_msgqs <= 0) { 463 tst_resm(TBROK, 464 "Max number of message queues already used, cannot create more."); 465 cleanup(); 466 } 467 468 /* 469 * Since msgmni scales to the memory size, it may reach huge values 470 * that are not necessary for this test. 471 * That's why we define NR_MSGQUEUES as a high boundary for it. 472 */ 473 MSGMNI = min(nr_msgqs, NR_MSGQUEUES); 474} 475 476/*************************************************************** 477 * cleanup() - performs all ONE TIME cleanup for this test at 478 * completion or premature exit. 479 ****************************************************************/ 480void cleanup() 481{ 482 int status; 483 /* 484 * Remove the message queue from the system 485 */ 486#ifdef DEBUG 487 tst_resm(TINFO, "Removing the message queue"); 488#endif 489 fflush(stdout); 490 (void)msgctl(tid, IPC_RMID, NULL); 491 if ((status = msgctl(tid, IPC_STAT, NULL)) != -1) { 492 (void)msgctl(tid, IPC_RMID, NULL); 493 tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed"); 494 tst_exit(); 495 } 496 497 fflush(stdout); 498 /* 499 * print timing stats if that option was specified. 500 * print errno log if that option was specified. 501 */ 502 TEST_CLEANUP; 503 tst_rmdir(); 504 /* exit with return code appropriate for results */ 505 tst_exit(); 506} 507