semctl06.c revision 4bb656a129f7507823e9e6d6b98b1a02fd80ef89
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/* 21 * NAME 22 * semctl06 23 * 24 * CALLS 25 * semctl(2) semget(2) semop(2) 26 * 27 * ALGORITHM 28 * Get and manipulate a set of semaphores. 29 * 30 * RESTRICTIONS 31 * 32 * WARNING 33 * If this test fail, it may be necessary to use the ipcs and ipcrm 34 * commands to remove any semaphores left in the system due to a 35 * premature exit of this test. 36 * 37 * HISTORY 38 * 06/30/2001 Port to Linux nsharoff@us.ibm.com 39 * 10/30/2002 Port to LTP dbarrera@us.ibm.com 40 * 12/03/2008 Matthieu Fertré (Matthieu.Fertre@irisa.fr) 41 * - Fix concurrency issue. The IPC keys used for this test could 42 * conflict with keys from another task. 43 */ 44 45#define DEBUG 0 46 47#ifdef UCLINUX 48#define _GNU_SOURCE /* for asprintf */ 49#include <stdio.h> 50#endif 51 52#include <sys/types.h> /* needed for test */ 53#include <sys/ipc.h> /* needed for test */ 54#include <sys/sem.h> /* needed for test */ 55#include <unistd.h> 56#include <errno.h> 57#include <stdlib.h> 58#include <signal.h> 59#include "test.h" 60#include "usctest.h" 61#include <wait.h> 62#include "ipcsem.h" 63 64int local_flag=1; 65 66 67#define NREPS 500 68#define NPROCS 3 69#define NKIDS 5 70#define NSEMS 5 71#define HVAL 1000 72#define LVAL 100 73#define FAILED 0 74 75void setup (); 76void cleanup(); 77 78static key_t keyarray[NPROCS]; 79static struct sembuf semops[NSEMS]; 80static short maxsemvals[NSEMS]; 81static int pidarray[NPROCS]; 82static int kidarray[NKIDS]; 83static int tid; 84static int procstat; 85static char *prog; 86static unsigned short semvals[NSEMS]; 87 88/* 89 * * These globals must be defined in the test. 90 * * */ 91 92 93char *TCID="semctl06"; /* Test program identifier. */ 94int TST_TOTAL=1; /* Total number of test cases. */ 95extern int Tst_count; /* Test Case counter for tst_* routines */ 96 97int exp_enos[]={0}; /* List must end with 0 */ 98 99 100static void term(int sig); 101static void dosemas(int id); 102static void dotest(key_t key); 103 104#ifdef UCLINUX 105static char *argv0; 106 107void do_child(); 108static int id_uclinux; 109static char *maxsemstring; 110#endif 111 112/*--------------------------------------------------------------*/ 113/*ARGSUSED*/ 114int 115main(int argc, char **argv) 116{ 117 register int i, pid; 118 int count, child, status, nwait; 119 120#ifdef UCLINUX 121 char *msg; 122 if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != (char *)NULL){ 123 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg); 124 } 125 126 argv0 = argv[0]; 127 maybe_run_child(&do_child, "dS", &id_uclinux, &maxsemstring); 128#endif 129 130 prog = argv[0]; 131 nwait = 0; 132 setup(); 133/*--------------------------------------------------------------*/ 134 tid = -1; 135 136 for (i = 0; i < NPROCS; i++) 137 keyarray[i] = getipckey(); 138 139 if ((signal(SIGTERM, term)) == SIG_ERR) { 140 tst_resm(TFAIL, "\tsignal failed. errno = %d", errno); 141 tst_exit(); 142 } 143 144 for (i = 0; i < NPROCS; i++) { 145 if ((pid = FORK_OR_VFORK()) < 0) { 146 tst_resm(TFAIL, "\tFork failed (may be OK if under stress)"); 147 tst_exit(); 148 } 149 if (pid == 0) { 150 procstat = 1; 151 dotest(keyarray[i]); 152 exit(0); 153 } 154 pidarray[i] = pid; 155 nwait++; 156 } 157 158 /* 159 * Wait for children to finish. 160 */ 161 162 count = 0; 163 while((child = wait(&status)) > 0) { 164 if (status) { 165 tst_resm(TFAIL, "%s[%d] Test failed. exit=0x%x", prog, child, status); 166 local_flag = FAILED; 167 } 168 ++count; 169 } 170 171 /* 172 * Should have collected all children. 173 */ 174 175 if (count != nwait) { 176 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", count); 177 local_flag = FAILED; 178 } 179 180 if (local_flag != FAILED) 181 tst_resm(TPASS, "semctl06 ran successfully!"); 182 else tst_resm(TFAIL, "semctl06 failed"); 183 184/*--------------------------------------------------------------*/ 185/* Clean up any files created by test before call to anyfail. */ 186 187 cleanup (); 188 189 return (0); /* shut lint up */ 190} 191/*--------------------------------------------------------------*/ 192 193 194static void 195dotest(key_t key) 196{ 197 int id, pid, status; 198 int count, child, nwait; 199 short i; 200 union semun get_arr; 201 202 nwait = 0; 203 srand(getpid()); 204 if ((id = semget(key, NSEMS, IPC_CREAT|IPC_EXCL)) < 0) { 205 tst_resm(TFAIL, "\tsemget() failed errno %d", errno); 206 exit(1); 207 } 208 tid = id; 209 for (i = 0; i < NSEMS; i++) { 210 do { 211 maxsemvals[i] = /*CASTOK*/(short)(rand() % HVAL); 212 } while (maxsemvals[i] < LVAL); 213 semops[i].sem_num = i; 214 semops[i].sem_op = maxsemvals[i]; 215 semops[i].sem_flg = SEM_UNDO; 216 } 217 if (semop(id, semops, NSEMS) < 0) { 218 tst_resm(TFAIL, "\tfirst semop() failed errno %d", errno); 219 exit(1); 220 } 221 222 for (i = 0; i < NKIDS; i++) { 223 if ((pid = FORK_OR_VFORK()) < 0) { 224 tst_resm(TFAIL, "\tfork failed"); 225 } 226 if (pid == 0) { 227#ifdef UCLINUX 228 int j; 229 maxsemstring = ""; 230 for (j = 0; j < NSEMS; j++) { 231 if (asprintf(&maxsemstring, "%s%s%d", 232 maxsemstring, (j ? ":" : ""), 233 maxsemvals[j]) < 0) { 234 tst_resm(TBROK, "Could not serialize " 235 "maxsemvals"); 236 tst_exit(); 237 } 238 } 239 if (self_exec(argv0, "dS", id, maxsemstring) < 0) { 240 tst_resm(TFAIL, "\tself_exec failed"); 241 } 242#else 243 dosemas(id); 244#endif 245 } 246 if (pid > 0) { 247 kidarray[i] = pid; 248 nwait++; 249 } 250 } 251 252 253 procstat = 2; 254 /* 255 * Wait for children to finish. 256 */ 257 258 count = 0; 259 while((child = wait(&status)) > 0) { 260 if (status) { 261 tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x", prog, child, status); 262 local_flag = FAILED; 263 } 264 ++count; 265 } 266 267 /* 268 * Should have collected all children. 269 */ 270 271 if (count != nwait) { 272 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", count); 273 local_flag = FAILED; 274 } 275 276 get_arr.array = semvals; 277 if (semctl(id, 0, GETALL, get_arr) < 0) { 278 tst_resm(TFAIL, "\terror on GETALL"); 279 tst_resm(TFAIL, "\tsemctl() failed errno %d", errno); 280 } 281 282 if (DEBUG) 283 tst_resm(TINFO, "\tchecking maxvals"); 284 for (i = 0; i < NSEMS; i++) { 285 if (semvals[i] != maxsemvals[i]) { 286 tst_resm(TFAIL, "\terror on i %d orig %d final %d", i, semvals[i], 287 maxsemvals[i]); 288 local_flag = FAILED; 289 } 290 } 291 if (DEBUG) 292 tst_resm(TINFO, "\tmaxvals checked"); 293 294 /* 4th arg must either be missing, or must be of type 'union semun'. 295 * CANNOT just be an int, else it crashes on ppc. 296 */ 297 get_arr.val = 0; 298 if (semctl(id, 0, IPC_RMID, get_arr) < 0) { 299 tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d", errno); 300 local_flag = FAILED; 301 } 302 if (local_flag == FAILED) 303 exit(1); 304} 305 306#ifdef UCLINUX 307void 308do_child() 309{ 310 int i; 311 char *tok; 312 char *endptr; 313 314 tok = strtok(maxsemstring, ":"); 315 for (i = 0; i < NSEMS; i++) { 316 if (strlen(tok) == 0) { 317 tst_resm(TBROK, "Invalid argument to -C option"); 318 tst_exit(); 319 } 320 321 maxsemvals[i] = strtol(tok, &endptr, 10); 322 if (*endptr != '\0') { 323 tst_resm(TBROK, "Invalid argument to -C option"); 324 tst_exit(); 325 } 326 tok = strtok(NULL, ":"); 327 } 328 329 dosemas(id_uclinux); 330} 331#endif 332 333static void 334dosemas(int id) 335{ 336 int i, j; 337 338 srand(getpid()); 339 for (i = 0; i < NREPS; i++) { 340 for (j = 0; j < NSEMS; j++) { 341 semops[j].sem_num = j; 342 semops[j].sem_flg = SEM_UNDO; 343 344 do { 345 semops[j].sem_op = 346 ( - /*CASTOK*/(short)(rand() % (maxsemvals[j]/2))); 347 } while (semops[j].sem_op == 0); 348 } 349 if (semop(id, semops, NSEMS) < 0) { 350 tst_resm(TFAIL, "\tsemop1 failed errno %d", errno); 351 exit(1); 352 } 353 for (j = 0; j < NSEMS; j++) { 354 semops[j].sem_op = ( - semops[j].sem_op); 355 } 356 if (semop(id, semops, NSEMS) < 0) { 357 tst_resm(TFAIL, "\tsemop2 failed errno %d", errno); 358 exit(1); 359 } 360 } 361 exit(0); 362} 363 364 365/*ARGSUSED*/ 366static void 367term(int sig) 368{ 369 int i; 370 371 if ((signal(SIGTERM, term)) == SIG_ERR) { 372 tst_resm(TFAIL, "\tsignal failed. errno %d", errno); 373 exit(1); 374 } 375 if (procstat == 0) { 376 if (DEBUG) 377 tst_resm(TINFO, "\ttest killing kids"); 378 for (i = 0; i < NPROCS; i++) { 379 if (kill(pidarray[i], SIGTERM) != 0) { 380 tst_resm(TFAIL, "Kill error pid = %d :",pidarray[1]); 381 } 382 } 383 if (DEBUG) 384 tst_resm(TINFO, "\ttest kids killed"); 385 return; 386 } 387 388 if (procstat == 1) { 389 /* 4th arg must either be missing, or must be of type 'union semun'. 390 * CANNOT just be an int, else it crashes on ppc. 391 */ 392 union semun arg; 393 arg.val = 0; 394 (void)semctl(tid, 0, IPC_RMID, arg); 395 exit(1); 396 } 397 398 if (tid == -1) { 399 exit(1); 400 } 401 for (i = 0; i < NKIDS; i++) { 402 if (kill(kidarray[i], SIGTERM) != 0) { 403 tst_resm(TFAIL, "Kill error kid id = %d :",kidarray[1]); 404 } 405 } 406} 407 408/*************************************************************** 409 * setup() - performs all ONE TIME setup for this test. 410 *****************************************************************/ 411void 412setup() 413{ 414 /* You will want to enable some signal handling so you can capture 415 * unexpected signals like SIGSEGV. 416 * */ 417 tst_sig(FORK, DEF_HANDLER, cleanup); 418 419 420 /* Pause if that option was specified */ 421 /* One cavet that hasn't been fixed yet. TEST_PAUSE contains the code to 422 * fork the test with the -c option. You want to make sure you do this 423 * before you create your temporary directory. 424 */ 425 TEST_PAUSE; 426 427 /* 428 * Create a temporary directory and cd into it. 429 * This helps to ensure that a unique msgkey is created. 430 * See ../lib/libipc.c for more information. 431 */ 432 tst_tmpdir(); 433} 434 435 436/*************************************************************** 437 * cleanup() - performs all ONE TIME cleanup for this test at 438 * completion or premature exit. 439 ****************************************************************/ 440void 441cleanup() 442{ 443 /* Remove the temporary directory */ 444 tst_rmdir(); 445 446 /* 447 * print timing stats if that option was specified. 448 * print errno log if that option was specified. 449 */ 450 TEST_CLEANUP; 451 452 /* exit with return code appropriate for results */ 453 tst_exit(); 454} 455 456