semctl06.c revision 345990d7443c8249c8fc20e45bf98195cab6e7a5
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/* 10/30/2002 Port to LTP dbarrera@us.ibm.com */ 22 23 24/* 25 * NAME 26 * semctl06 27 * 28 * CALLS 29 * semctl(2) semget(2) semop(2) 30 * 31 * ALGORITHM 32 * Get and manipulate a set of semaphores. 33 * 34 * RESTRICTIONS 35 * 36 * WARNING 37 * If this test fail, it may be necessary to use the ipcs and ipcrm 38 * commands to remove any semaphores left in the system due to a 39 * premature exit of this test. 40 */ 41 42 43#include <sys/types.h> /* needed for test */ 44#include <sys/ipc.h> /* needed for test */ 45#include <sys/sem.h> /* needed for test */ 46#include <unistd.h> 47#include <errno.h> 48#include <stdlib.h> 49#include <signal.h> 50#include "test.h" 51#include "usctest.h" 52#include <wait.h> 53#include "ipcsem.h" 54 55int local_flag=1; 56 57 58#define NREPS 500 59#define NPROCS 3 60#define NKIDS 5 61#define NSEMS 5 62#define HVAL 1000 63#define LVAL 100 64#define FAILED 0 65 66void setup (); 67void cleanup(); 68 69static key_t keyarray[NPROCS]; 70static struct sembuf semops[NSEMS]; 71static short maxsemvals[NSEMS]; 72static int pidarray[NPROCS]; 73static int kidarray[NKIDS]; 74static int tid; 75static int procstat; 76static char *prog; 77static short semvals[NSEMS]; 78 79/* 80 * * These globals must be defined in the test. 81 * * */ 82 83 84char *TCID="semctl06"; /* Test program identifier. */ 85int TST_TOTAL=1; /* Total number of test cases. */ 86extern int Tst_count; /* Test Case counter for tst_* routines */ 87 88int exp_enos[]={0}; /* List must end with 0 */ 89 90 91static void term(int sig); 92static void dosemas(int id); 93static void dotest(key_t key); 94 95 96/*--------------------------------------------------------------*/ 97/*ARGSUSED*/ 98int 99main(int argc, char **argv) 100{ 101 register int i, j, ok, pid; 102 int count, child, status, nwait; 103 104 prog = argv[0]; 105 nwait = 0; 106 setup(); 107/*--------------------------------------------------------------*/ 108 srand(getpid()); 109 110 tid = -1; 111 112 for (i = 0; i < NPROCS; i++) { 113 do { 114 keyarray[i] = (key_t)rand(); 115 if (keyarray[i] == IPC_PRIVATE) { 116 ok = 0; 117 continue; 118 } 119 ok = 1; 120 for (j = 0; j < i; j++) { 121 if (keyarray[j] == keyarray[i]) { 122 ok = 0; 123 break; 124 } 125 } 126 } while (ok == 0); 127 } 128 129 if ((signal(SIGTERM, term)) == SIG_ERR) { 130 tst_resm(TFAIL, "\tsignal failed. errno = %d\n", errno); 131 tst_exit(); 132 } 133 134 for (i = 0; i < NPROCS; i++) { 135 if ((pid = fork()) < 0) { 136 tst_resm(TFAIL, "\tFork failed (may be OK if under stress)"); 137 tst_exit(); 138 } 139 if (pid == 0) { 140 procstat = 1; 141 dotest(keyarray[i]); 142 exit(0); 143 } 144 pidarray[i] = pid; 145 nwait++; 146 } 147 148 /* 149 * Wait for children to finish. 150 */ 151 152 count = 0; 153 while((child = wait(&status)) > 0) { 154 if (status) { 155 tst_resm(TFAIL, "%s[%d] Test failed. exit=0x%x\n", prog, child, status); 156 local_flag = FAILED; 157 } 158 ++count; 159 } 160 161 /* 162 * Should have collected all children. 163 */ 164 165 if (count != nwait) { 166 tst_resm(TFAIL, "\tWrong # children waited on, count = %d\n", count); 167 local_flag = FAILED; 168 } 169 170 if (local_flag != FAILED) 171 tst_resm(TPASS, "semctl06 ran successfully!"); 172 else tst_resm(TFAIL, "semctl06 failed"); 173 174/*--------------------------------------------------------------*/ 175/* Clean up any files created by test before call to anyfail. */ 176 177 cleanup (); 178 179 return (0); /* shut lint up */ 180} 181/*--------------------------------------------------------------*/ 182 183 184static void 185dotest(key_t key) 186{ 187 int id, pid, status; 188 int count, child, nwait; 189 short i; 190 union semun get_arr; 191 192 nwait = 0; 193 srand(getpid()); 194 if ((id = semget(key, NSEMS, IPC_CREAT)) < 0) { 195 tst_resm(TFAIL, "\tsemget() failed errno %d\n", errno); 196 exit(1); 197 } 198 tid = id; 199 for (i = 0; i < NSEMS; i++) { 200 do { 201 maxsemvals[i] = /*CASTOK*/(short)(rand() % HVAL); 202 } while (maxsemvals[i] < LVAL); 203 semops[i].sem_num = i; 204 semops[i].sem_op = maxsemvals[i]; 205 semops[i].sem_flg = SEM_UNDO; 206 } 207 if (semop(id, semops, NSEMS) < 0) { 208 tst_resm(TFAIL, "\tfirst semop() failed errno %d\n", errno); 209 exit(1); 210 } 211 212 for (i = 0; i < NKIDS; i++) { 213 if ((pid = fork()) < 0) { 214 tst_resm(TFAIL, "\tfork failed\n"); 215 } 216 if (pid == 0) { 217 dosemas(id); 218 } 219 if (pid > 0) { 220 kidarray[i] = pid; 221 nwait++; 222 } 223 } 224 225 226 procstat = 2; 227 /* 228 * Wait for children to finish. 229 */ 230 231 count = 0; 232 while((child = wait(&status)) > 0) { 233 if (status) { 234 tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x\n", prog, child, status); 235 local_flag = FAILED; 236 } 237 ++count; 238 } 239 240 /* 241 * Should have collected all children. 242 */ 243 244 if (count != nwait) { 245 tst_resm(TFAIL, "\tWrong # children waited on, count = %d\n", count); 246 local_flag = FAILED; 247 } 248 249 get_arr.array = semvals; 250 if (semctl(id, 0, GETALL, get_arr) < 0) { 251 tst_resm(TFAIL, "\terror on GETALL\n"); 252 tst_resm(TFAIL, "\tsemctl() failed errno %d\n", errno); 253 } 254 255 tst_resm(TINFO, "\tchecking maxvals\n"); 256 for (i = 0; i < NSEMS; i++) { 257 if (semvals[i] != maxsemvals[i]) { 258 tst_resm(TFAIL, "\terror on i %d orig %d final %d\n", i, semvals[i], 259 maxsemvals[i]); 260 local_flag = FAILED; 261 } 262 } 263 tst_resm(TINFO, "\tmaxvals checked\n"); 264 265 if (semctl(id, 0, IPC_RMID, 0) < 0) { 266 tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d\n", errno); 267 local_flag = FAILED; 268 } 269 if (local_flag == FAILED) 270 exit(1); 271} 272 273 274static void 275dosemas(int id) 276{ 277 int i, j; 278 279 srand(getpid()); 280 for (i = 0; i < NREPS; i++) { 281 for (j = 0; j < NSEMS; j++) { 282 do { 283 semops[j].sem_op = 284 ( - /*CASTOK*/(short)(rand() % (maxsemvals[j]/2))); 285 } while (semops[j].sem_op == 0); 286 } 287 if (semop(id, semops, NSEMS) < 0) { 288 tst_resm(TFAIL, "\tsemop1 failed errno %d\n", errno); 289 exit(1); 290 } 291 for (j = 0; j < NSEMS; j++) { 292 semops[j].sem_op = ( - semops[j].sem_op); 293 } 294 if (semop(id, semops, NSEMS) < 0) { 295 tst_resm(TFAIL, "\tsemop2 failed errno %d\n", errno); 296 exit(1); 297 } 298 } 299 exit(0); 300} 301 302 303/*ARGSUSED*/ 304static void 305term(int sig) 306{ 307 int i; 308 309 if ((signal(SIGTERM, term)) == SIG_ERR) { 310 tst_resm(TFAIL, "\tsignal failed. errno %d\n", errno); 311 exit(1); 312 } 313 if (procstat == 0) { 314 tst_resm(TINFO, "\ttest killing kids\n"); 315 for (i = 0; i < NPROCS; i++) { 316 if (kill(pidarray[i], SIGTERM) != 0) { 317 tst_resm(TFAIL, "Kill error pid = %d :",pidarray[1]); 318 } 319 } 320 tst_resm(TINFO, "\ttest kids killed\n"); 321 return; 322 } 323 324 if (procstat == 1) { 325 (void)semctl(tid, 0, IPC_RMID, 0); 326 exit(1); 327 } 328 329 if (tid == -1) { 330 exit(1); 331 } 332 for (i = 0; i < NKIDS; i++) { 333 if (kill(kidarray[i], SIGTERM) != 0) { 334 tst_resm(TFAIL, "Kill error kid id = %d :",kidarray[1]); 335 } 336 } 337} 338 339/*************************************************************** 340 * setup() - performs all ONE TIME setup for this test. 341 *****************************************************************/ 342void 343setup() 344{ 345 /* You will want to enable some signal handling so you can capture 346 * unexpected signals like SIGSEGV. 347 * */ 348 tst_sig(FORK, DEF_HANDLER, cleanup); 349 350 351 /* Pause if that option was specified */ 352 /* One cavet that hasn't been fixed yet. TEST_PAUSE contains the code to 353 * fork the test with the -c option. You want to make sure you do this 354 * before you create your temporary directory. 355 */ 356 TEST_PAUSE; 357} 358 359 360/*************************************************************** 361 * cleanup() - performs all ONE TIME cleanup for this test at 362 * completion or premature exit. 363 ****************************************************************/ 364void 365cleanup() 366{ 367 /* 368 * print timing stats if that option was specified. 369 * print errno log if that option was specified. 370 */ 371 TEST_CLEANUP; 372 373 /* exit with return code appropriate for results */ 374 tst_exit(); 375} 376 377