semctl01.c revision bffa8865e3ec438fe437163f95f0686f8c17c5f3
1/* 2 * Copyright (c) International Business Machines Corp., 2001 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 19/* 20 * NAME 21 * semctl01.c 22 * 23 * DESCRIPTION 24 * semctl01 - test the 13 possible semctl() commands 25 * 26 * ALGORITHM 27 * create a semaphore set with read and alter permissions 28 * loop if that option was specified 29 * loop through the test cases 30 * do any setup required for the test case 31 * make the semctl() call using the TEST() macro 32 * check the return code 33 * if failure, issue a FAIL message. 34 * otherwise, 35 * if doing functionality testing 36 * call the appropriate test function 37 * if correct, 38 * issue a PASS message 39 * otherwise 40 * issue a FAIL message 41 * call cleanup 42 */ 43 44#include "ipcsem.h" 45#include "libtestsuite.h" 46 47char *TCID = "semctl01"; 48int TST_TOTAL = 10; 49 50static int sem_id_1 = -1; 51 52static int sync_pipes[2]; 53 54/* 55 * These are the various setup and check functions for the 10 different 56 * commands that are available for the semctl() call. 57 */ 58static void func_stat(void); 59static void set_setup(void), func_set(void); 60static void func_gall(void); 61static void cnt_setup(int), func_cnt(int); 62static void pid_setup(void), func_pid(int); 63static void func_gval(int); 64static void sall_setup(void), func_sall(void); 65static void func_sval(void); 66static void func_rmid(void); 67static void child_cnt(void); 68static void child_pid(void); 69 70static struct semid_ds buf; 71static unsigned short array[PSEMS]; 72static struct sembuf sops; 73 74#define INCVAL 2 75#define NEWMODE 066 76#define NCHILD 5 77#define SEM2 2 78#define SEM4 4 79#define ONE 1 80#ifdef _XLC_COMPILER 81#define SEMUN_CAST 82#else 83#define SEMUN_CAST (union semun) 84#endif 85 86static int pid_arr[NCHILD]; 87 88#ifdef UCLINUX 89#define PIPE_NAME "semctl01" 90static char *argv0; 91static int sem_op; 92#endif 93 94static struct test_case_t { 95 int semnum; 96 int cmd; 97 void (*func_test) (); 98 union semun arg; 99 void (*func_setup) (); 100} TC[] = { 101 {0, IPC_STAT, func_stat, SEMUN_CAST & buf, NULL}, 102 {0, IPC_SET, func_set, SEMUN_CAST & buf, set_setup}, 103 {0, GETALL, func_gall, SEMUN_CAST array, NULL}, 104 {SEM4, GETNCNT, func_cnt, SEMUN_CAST & buf, cnt_setup}, 105 {SEM2, GETPID, func_pid, SEMUN_CAST & buf, pid_setup}, 106 {SEM2, GETVAL, func_gval, SEMUN_CAST & buf, NULL}, 107 {SEM4, GETZCNT, func_cnt, SEMUN_CAST & buf, cnt_setup}, 108 {0, SETALL, func_sall, SEMUN_CAST array, sall_setup}, 109 {SEM4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL}, 110 {0, IPC_RMID, func_rmid, SEMUN_CAST & buf, NULL}, 111}; 112 113int main(int argc, char *argv[]) 114{ 115 int lc; 116 char *msg; 117 int i, j; 118 119 msg = parse_opts(argc, argv, NULL, NULL); 120 if (msg != NULL) 121 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 122 123#ifdef UCLINUX 124 argv0 = argv[0]; 125 maybe_run_child(&child_pid, "nd", 1, &sem_id_1); 126 maybe_run_child(&child_cnt, "ndd", 2, &sem_id_1, &sem_op); 127#endif 128 129 setup(); 130 131 for (lc = 0; TEST_LOOPING(lc); lc++) { 132 tst_count = 0; 133 134 for (i = 0; i < TST_TOTAL; i++) { 135 136 /* 137 * Set up any conditions if needed 138 */ 139 if (TC[i].func_setup != NULL) { 140 /* call the setup function */ 141 switch (TC[i].cmd) { 142 case GETNCNT: 143 (*TC[i].func_setup) (-ONE); 144 break; 145 case GETZCNT: 146 (*TC[i].func_setup) (0); 147 break; 148 default: 149 (*TC[i].func_setup) (); 150 break; 151 } 152 } 153 154 TEST(semctl(sem_id_1, TC[i].semnum, TC[i].cmd, 155 TC[i].arg)); 156 157 if (TEST_RETURN == -1) { 158 tst_resm(TFAIL, "%s call failed - errno = %d " 159 ": %s", TCID, TEST_ERRNO, 160 strerror(TEST_ERRNO)); 161 } else { 162 if (STD_FUNCTIONAL_TEST) { 163 /* 164 * call the appropriate test function 165 * and pass the return value where it 166 * is needed to perform certain tests. 167 */ 168 switch (TC[i].cmd) { 169 case GETNCNT: 170 case GETZCNT: 171 case GETPID: 172 case GETVAL: 173 (*TC[i].func_test) 174 (TEST_RETURN); 175 break; 176 default: 177 (*TC[i].func_test) (); 178 break; 179 } 180 } else { 181 tst_resm(TPASS, "call succeeded"); 182 } 183 } 184 185 /* 186 * If testing GETNCNT or GETZCNT, clean up the children. 187 */ 188 switch (TC[i].cmd) { 189 case GETNCNT: 190 case GETZCNT: 191 for (j = 0; j < NCHILD; j++) { 192 if (kill(pid_arr[j], SIGKILL) == -1) 193 tst_brkm(TBROK, cleanup, 194 "child kill failed"); 195 } 196 break; 197 } 198 } 199 /* 200 * recreate the semaphore resource if looping 201 */ 202 if (TEST_LOOPING(lc)) { 203 sem_id_1 = semget(semkey, PSEMS, 204 IPC_CREAT | IPC_EXCL | SEM_RA); 205 if (sem_id_1 == -1) 206 tst_brkm(TBROK, cleanup, 207 "couldn't recreate " "semaphore"); 208 } 209 } 210 211 cleanup(); 212 213 tst_exit(); 214} 215 216/* 217 * func_stat() - check the functionality of the IPC_STAT command with semctl() 218 */ 219static void func_stat(void) 220{ 221 /* check the number of semaphores and the ipc_perm.mode value */ 222 if (buf.sem_nsems == PSEMS && buf.sem_perm.mode == (SEM_RA)) 223 tst_resm(TPASS, "buf.sem_nsems and buf.sem_perm.mode" 224 " are correct"); 225 else 226 tst_resm(TFAIL, "semaphore STAT info is incorrect"); 227} 228 229/* 230 * set_setup() - set up for the IPC_SET command with semctl() 231 */ 232static void set_setup(void) 233{ 234 /* set up a new mode for the semaphore set */ 235 buf.sem_perm.mode = SEM_RA | NEWMODE; 236} 237 238/* 239 * func_set() - check the functionality of the IPC_SET command with semctl() 240 */ 241static void func_set(void) 242{ 243 /* first stat the semaphore to get the new data */ 244 if (semctl(sem_id_1, 0, IPC_STAT, (union semun)&buf) == -1) { 245 tst_resm(TBROK, "stat failed in func_set()"); 246 return; 247 } 248 249 /* check that the new mode is what we set */ 250 if (buf.sem_perm.mode == (SEM_RA | NEWMODE)) 251 tst_resm(TPASS, "buf.sem_perm.mode is correct"); 252 else 253 tst_resm(TFAIL, "semaphore mode info is incorrect"); 254} 255 256/* 257 * func_gall() - check the functionality of the GETALL command with semctl() 258 */ 259static void func_gall(void) 260{ 261 int i; 262 263 /* the initial value of the primitive semaphores should be zero */ 264 for (i = 0; i < PSEMS; i++) { 265 if (array[i] != 0) { 266 tst_resm(TFAIL, "semaphore %d has unexpected value", i); 267 return; 268 } 269 } 270 tst_resm(TPASS, "semaphores have expected values"); 271} 272 273/* 274 * cnt_setup() - set up for the GETNCNT and GETZCNT commands with semctl() 275 */ 276static void cnt_setup(int opval) 277{ 278 int pid, i; 279 280 sops.sem_num = SEM4; 281 sops.sem_flg = 0; 282 283 /* 284 * if seting up for GETZCNT, the semaphore value needs to be positive 285 */ 286 if (opval == 0) { 287 /* initialize the semaphore value to ONE */ 288 sops.sem_op = ONE; 289 if (semop(sem_id_1, &sops, 1) == -1) 290 tst_brkm(TBROK, cleanup, "semop #1 failed - cnt_setup"); 291 } 292 293 /* set the correct operation */ 294 sops.sem_op = opval; 295 for (i = 0; i < NCHILD; i++) { 296 if (sync_pipe_create(sync_pipes, PIPE_NAME) == -1) 297 tst_brkm(TBROK, cleanup, "sync_pipe_create failed"); 298 299 /* fork five children to wait */ 300 pid = FORK_OR_VFORK(); 301 if (pid == -1) 302 tst_brkm(TBROK, cleanup, "fork failed in cnt_setup"); 303 304 if (pid == 0) { 305#ifdef UCLINUX 306 sem_op = sops.sem_op; 307 if (self_exec(argv0, "ndd", 2, sem_id_1, sem_op) < 0) 308 tst_brkm(TBROK, cleanup, "self_exec failed " 309 "in cnt_setup"); 310#else 311 child_cnt(); 312#endif 313 } else { 314 if (sync_pipe_wait(sync_pipes) == -1) 315 tst_brkm(TBROK, cleanup, 316 "sync_pipe_wait failed"); 317 318 if (sync_pipe_close(sync_pipes, PIPE_NAME) == -1) 319 tst_brkm(TBROK, cleanup, 320 "sync_pipe_close failed"); 321 322 /* save the pid so we can kill it later */ 323 pid_arr[i] = pid; 324 } 325 } 326 /* After last son has been created, give it a chance to execute the 327 * semop command before we continue. Without this sleep, on SMP machine 328 * the father semctl could be executed before the son semop. 329 */ 330 sleep(1); 331} 332 333static void child_cnt(void) 334{ 335#ifdef UCLINUX 336 sops.sem_op = (short int)sem_op; 337 if (sync_pipe_create(sync_pipes, PIPE_NAME) == -1) 338 tst_brkm(TBROK, cleanup, "sync_pipe_create failed"); 339#endif 340 341 if (sync_pipe_notify(sync_pipes) == -1) 342 tst_brkm(TBROK, cleanup, "sync_pipe_notify failed"); 343 344#ifdef UCLINUX 345 if (sync_pipe_close(sync_pipes, NULL) == -1) 346#else 347 if (sync_pipe_close(sync_pipes, PIPE_NAME) == -1) 348#endif 349 tst_brkm(TBROK, cleanup, "sync_pipe_close failed"); 350 351 sops.sem_num = SEM4; 352 sops.sem_flg = 0; 353 354 /* 355 * Do a semop that will cause the child to sleep. 356 * The child process will be killed in the func_ncnt 357 * routine which should cause an error to be return 358 * by the semop() call. 359 */ 360 if (semop(sem_id_1, &sops, 1) != -1) 361 tst_resm(TBROK, "semop succeeded - cnt_setup"); 362 363 exit(0); 364} 365 366/* 367 * func_cnt() - check the functionality of the GETNCNT and GETZCNT commands 368 * with semctl() 369 */ 370static void func_cnt(int rval) 371{ 372 373 if (rval == NCHILD) 374 tst_resm(TPASS, "number of sleeping processes is correct"); 375 else 376 tst_resm(TFAIL, "number of sleeping processes is not correct"); 377} 378 379/* 380 * pid_setup() - set up for the GETPID command with semctl() 381 */ 382static void pid_setup(void) 383{ 384 int pid; 385 386 if (sync_pipe_create(sync_pipes, PIPE_NAME) == -1) 387 tst_brkm(TBROK, cleanup, "sync_pipe_create failed"); 388 389 /* 390 * Fork a child to do a semop that will pass. 391 */ 392 pid = FORK_OR_VFORK(); 393 if (pid == -1) 394 tst_brkm(TBROK, cleanup, "fork failed in pid_setup()"); 395 396 if (pid == 0) { /* child */ 397#ifdef UCLINUX 398 if (self_exec(argv0, "nd", 1, sem_id_1) < 0) 399 tst_brkm(TBROK, cleanup, "self_exec failed " 400 "in pid_setup()"); 401#else 402 child_pid(); 403#endif 404 } else { /* parent */ 405 if (sync_pipe_wait(sync_pipes) == -1) 406 tst_brkm(TBROK, cleanup, "sync_pipe_wait failed"); 407 408 if (sync_pipe_close(sync_pipes, PIPE_NAME) == -1) 409 tst_brkm(TBROK, cleanup, "sync_pipe_close failed"); 410 sleep(1); 411 pid_arr[SEM2] = pid; 412 } 413} 414 415static void child_pid(void) 416{ 417#ifdef UCLINUX 418 if (sync_pipe_create(sync_pipes, PIPE_NAME) == -1) 419 tst_brkm(TBROK, cleanup, "sync_pipe_create failed"); 420#endif 421 422 if (sync_pipe_notify(sync_pipes) == -1) 423 tst_brkm(TBROK, cleanup, "sync_pipe_notify failed"); 424 425 if (sync_pipe_close(sync_pipes, PIPE_NAME) == -1) 426 tst_brkm(TBROK, cleanup, "sync_pipe_close failed"); 427 428 sops.sem_num = SEM2; 429 sops.sem_op = ONE; 430 sops.sem_flg = 0; 431 432 /* 433 * Do a semop that will increment the semaphore. 434 */ 435 if (semop(sem_id_1, &sops, 1) == -1) 436 tst_resm(TBROK, "semop failed - pid_setup"); 437 438 exit(0); 439} 440 441/* 442 * func_pid() - check the functionality of the GETPID command with semctl() 443 */ 444static void func_pid(int rval) 445{ 446 /* compare the rval (pid) to the saved pid from the setup */ 447 if (rval == pid_arr[SEM2]) 448 tst_resm(TPASS, "last pid value is correct"); 449 else 450 tst_resm(TFAIL, "last pid value is not correct"); 451} 452 453/* 454 * func_gval() - check the functionality of the GETVAL command with semctl() 455 */ 456static void func_gval(int rval) 457{ 458 /* 459 * This is a simple test. The semaphore value should be equal 460 * to ONE as it was set in the last test (GETPID). 461 */ 462 if (rval == 1) 463 tst_resm(TPASS, "semaphore value is correct"); 464 else 465 tst_resm(TFAIL, "semaphore value is not correct"); 466} 467 468/* 469 * all_setup() - set up for the SETALL command with semctl() 470 */ 471static void sall_setup(void) 472{ 473 int i; 474 475 for (i = 0; i < PSEMS; i++) { 476 /* initialize the array values to 3 */ 477 array[i] = 3; 478 } 479} 480 481/* 482 * func_sall() - check the functionality of the SETALL command with semctl() 483 */ 484static void func_sall(void) 485{ 486 int i; 487 unsigned short rarray[PSEMS]; 488 489 /* 490 * do a GETALL and compare the values to those set above 491 */ 492 493 if (semctl(sem_id_1, 0, GETALL, (union semun)rarray) == -1) 494 tst_brkm(TBROK, cleanup, "semctl failed in func_sall"); 495 496 for (i = 0; i < PSEMS; i++) { 497 if (array[i] != rarray[i]) { 498 tst_resm(TFAIL, "semaphore values are not correct"); 499 return; 500 } 501 } 502 503 tst_resm(TPASS, "semaphore values are correct"); 504} 505 506/* 507 * func_sval() - check the functionality of the SETVAL command with semctl() 508 */ 509static void func_sval(void) 510{ 511 int semv; 512 union semun arr; 513 514 /* 515 * do a GETVAL and compare it to the value set above 516 */ 517 518 semv = semctl(sem_id_1, SEM4, GETVAL, arr); 519 if (semv == -1) 520 tst_brkm(TBROK, cleanup, "semctl failed in func_sval"); 521 522 if (semv != INCVAL) 523 tst_resm(TFAIL, "semaphore value is not what was set"); 524 else 525 tst_resm(TPASS, "semaphore value is correct"); 526} 527 528/* 529 * func_rmid() - check the functionality of the IPC_RMID command with semctl() 530 */ 531static void func_rmid(void) 532{ 533 534 /* 535 * do a semop() - we should get EINVAL 536 */ 537 if (semop(sem_id_1, &sops, 1) != -1) 538 tst_resm(TFAIL, "semop succeeded on expected fail"); 539 540 if (errno != EINVAL) 541 tst_resm(TFAIL, "returned errno - %d - is not expected", errno); 542 else 543 tst_resm(TPASS, "semaphore appears to be removed"); 544 545 sem_id_1 = -1; 546} 547 548void setup(void) 549{ 550 551 tst_sig(FORK, DEF_HANDLER, cleanup); 552 553 TEST_PAUSE; 554 555 tst_tmpdir(); 556 557 /* get an IPC resource key */ 558 semkey = getipckey(); 559 560 /* create a semaphore set with read and alter permissions */ 561 sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA); 562 if (sem_id_1 == -1) 563 tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup"); 564} 565 566void cleanup(void) 567{ 568 /* if it exists, remove the semaphore resource */ 569 rm_sema(sem_id_1); 570 571 tst_rmdir(); 572 573 TEST_CLEANUP; 574} 575