semctl06.c revision 526fdf8d8ea3b43b73de7cc25eb754f12702c8d2
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 49#include <stdio.h> 50#endif 51 52#include <sys/types.h> 53#include <sys/ipc.h> 54#include <sys/sem.h> 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#define NREPS 500 67#define NPROCS 3 68#define NKIDS 5 69#define NSEMS 5 70#define HVAL 1000 71#define LVAL 100 72#define FAILED 0 73 74void setup(); 75void cleanup(); 76 77static key_t keyarray[NPROCS]; 78static struct sembuf semops[NSEMS]; 79static short maxsemvals[NSEMS]; 80static int pidarray[NPROCS]; 81static int kidarray[NKIDS]; 82static int tid; 83static int procstat; 84static char *prog; 85static unsigned short semvals[NSEMS]; 86 87char *TCID = "semctl06"; 88int TST_TOTAL = 1; 89 90static void term(int sig); 91static void dosemas(int id); 92static void dotest(key_t key); 93 94#ifdef UCLINUX 95static char *argv0; 96 97void do_child(); 98static int id_uclinux; 99static char *maxsemstring; 100#endif 101 102int main(int argc, char **argv) 103{ 104 register int i, pid; 105 int count, child, status, nwait; 106 107#ifdef UCLINUX 108 const char *msg; 109 if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL) 110 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 111 112 argv0 = argv[0]; 113 maybe_run_child(&do_child, "dS", &id_uclinux, &maxsemstring); 114#endif 115 116 prog = argv[0]; 117 nwait = 0; 118 setup(); 119 120 tid = -1; 121 122 for (i = 0; i < NPROCS; i++) 123 keyarray[i] = getipckey(); 124 125 if ((signal(SIGTERM, term)) == SIG_ERR) { 126 tst_resm(TFAIL, "\tsignal failed. errno = %d", errno); 127 128 } 129 130 for (i = 0; i < NPROCS; i++) { 131 if ((pid = FORK_OR_VFORK()) < 0) { 132 tst_resm(TFAIL, 133 "\tFork failed (may be OK if under stress)"); 134 135 } 136 if (pid == 0) { 137 procstat = 1; 138 dotest(keyarray[i]); 139 exit(0); 140 } 141 pidarray[i] = pid; 142 nwait++; 143 } 144 145 /* 146 * Wait for children to finish. 147 */ 148 149 count = 0; 150 while ((child = wait(&status)) > 0) { 151 if (status) { 152 tst_resm(TFAIL, "%s[%d] Test failed. exit=0x%x", prog, 153 child, status); 154 local_flag = FAILED; 155 } 156 ++count; 157 } 158 159 /* 160 * Should have collected all children. 161 */ 162 163 if (count != nwait) { 164 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", 165 count); 166 local_flag = FAILED; 167 } 168 169 if (local_flag != FAILED) 170 tst_resm(TPASS, "semctl06 ran successfully!"); 171 else 172 tst_resm(TFAIL, "semctl06 failed"); 173 174 175 cleanup(); 176 tst_exit(); 177} 178 179static void dotest(key_t key) 180{ 181 int id, pid, status; 182 int count, child, nwait; 183 short i; 184 union semun get_arr; 185 186 nwait = 0; 187 srand(getpid()); 188 if ((id = semget(key, NSEMS, IPC_CREAT | IPC_EXCL)) < 0) { 189 tst_resm(TFAIL, "\tsemget() failed errno %d", errno); 190 exit(1); 191 } 192 tid = id; 193 for (i = 0; i < NSEMS; i++) { 194 do { 195 maxsemvals[i] = (short) (rand() % HVAL); 196 } while (maxsemvals[i] < LVAL); 197 semops[i].sem_num = i; 198 semops[i].sem_op = maxsemvals[i]; 199 semops[i].sem_flg = SEM_UNDO; 200 } 201 if (semop(id, semops, NSEMS) < 0) { 202 tst_resm(TFAIL, "\tfirst semop() failed errno %d", errno); 203 exit(1); 204 } 205 206 for (i = 0; i < NKIDS; i++) { 207 if ((pid = FORK_OR_VFORK()) < 0) { 208 tst_resm(TFAIL, "\tfork failed"); 209 } 210 if (pid == 0) { 211#ifdef UCLINUX 212 int j; 213 maxsemstring = ""; 214 for (j = 0; j < NSEMS; j++) { 215 if (asprintf(&maxsemstring, "%s%s%d", 216 maxsemstring, (j ? ":" : ""), 217 maxsemvals[j]) < 0) { 218 tst_brkm(TBROK, NULL, "Could not serialize " 219 "maxsemvals"); 220 } 221 } 222 if (self_exec(argv0, "dS", id, maxsemstring) < 0) { 223 tst_resm(TFAIL, "\tself_exec failed"); 224 } 225#else 226 dosemas(id); 227#endif 228 } 229 if (pid > 0) { 230 kidarray[i] = pid; 231 nwait++; 232 } 233 } 234 235 procstat = 2; 236 /* 237 * Wait for children to finish. 238 */ 239 240 count = 0; 241 while ((child = wait(&status)) > 0) { 242 if (status) { 243 tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x", 244 prog, child, status); 245 local_flag = FAILED; 246 } 247 ++count; 248 } 249 250 /* 251 * Should have collected all children. 252 */ 253 254 if (count != nwait) { 255 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", 256 count); 257 local_flag = FAILED; 258 } 259 260 get_arr.array = semvals; 261 if (semctl(id, 0, GETALL, get_arr) < 0) { 262 tst_resm(TFAIL, "\terror on GETALL"); 263 tst_resm(TFAIL, "\tsemctl() failed errno %d", errno); 264 } 265 266 if (DEBUG) 267 tst_resm(TINFO, "\tchecking maxvals"); 268 for (i = 0; i < NSEMS; i++) { 269 if (semvals[i] != maxsemvals[i]) { 270 tst_resm(TFAIL, "\terror on i %d orig %d final %d", i, 271 semvals[i], maxsemvals[i]); 272 local_flag = FAILED; 273 } 274 } 275 if (DEBUG) 276 tst_resm(TINFO, "\tmaxvals checked"); 277 278 /* 4th arg must either be missing, or must be of type 'union semun'. 279 * CANNOT just be an int, else it crashes on ppc. 280 */ 281 get_arr.val = 0; 282 if (semctl(id, 0, IPC_RMID, get_arr) < 0) { 283 tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d", errno); 284 local_flag = FAILED; 285 } 286 if (local_flag == FAILED) 287 exit(1); 288} 289 290#ifdef UCLINUX 291void do_child(void) 292{ 293 int i; 294 char *tok; 295 char *endptr; 296 297 tok = strtok(maxsemstring, ":"); 298 for (i = 0; i < NSEMS; i++) { 299 if (strlen(tok) == 0) { 300 tst_brkm(TBROK, NULL, "Invalid argument to -C option"); 301 } 302 303 maxsemvals[i] = strtol(tok, &endptr, 10); 304 if (*endptr != '\0') { 305 tst_brkm(TBROK, NULL, "Invalid argument to -C option"); 306 } 307 tok = strtok(NULL, ":"); 308 } 309 310 dosemas(id_uclinux); 311} 312#endif 313 314static void dosemas(int id) 315{ 316 int i, j; 317 318 srand(getpid()); 319 for (i = 0; i < NREPS; i++) { 320 for (j = 0; j < NSEMS; j++) { 321 semops[j].sem_num = j; 322 semops[j].sem_flg = SEM_UNDO; 323 324 do { 325 semops[j].sem_op = 326 (-(short) (rand() % 327 (maxsemvals[j] / 2))); 328 } while (semops[j].sem_op == 0); 329 } 330 if (semop(id, semops, NSEMS) < 0) { 331 tst_resm(TFAIL, "\tsemop1 failed errno %d", errno); 332 exit(1); 333 } 334 for (j = 0; j < NSEMS; j++) { 335 semops[j].sem_op = (-semops[j].sem_op); 336 } 337 if (semop(id, semops, NSEMS) < 0) { 338 tst_resm(TFAIL, "\tsemop2 failed errno %d", errno); 339 exit(1); 340 } 341 } 342 exit(0); 343} 344 345static void term(int sig) 346{ 347 int i; 348 349 if ((signal(SIGTERM, term)) == SIG_ERR) { 350 tst_resm(TFAIL, "\tsignal failed. errno %d", errno); 351 exit(1); 352 } 353 if (procstat == 0) { 354 if (DEBUG) 355 tst_resm(TINFO, "\ttest killing kids"); 356 for (i = 0; i < NPROCS; i++) { 357 if (kill(pidarray[i], SIGTERM) != 0) { 358 tst_resm(TFAIL, "Kill error pid = %d :", 359 pidarray[1]); 360 } 361 } 362 if (DEBUG) 363 tst_resm(TINFO, "\ttest kids killed"); 364 return; 365 } 366 367 if (procstat == 1) { 368 /* 4th arg must either be missing, or must be of type 'union semun'. 369 * CANNOT just be an int, else it crashes on ppc. 370 */ 371 union semun arg; 372 arg.val = 0; 373 (void)semctl(tid, 0, IPC_RMID, arg); 374 exit(1); 375 } 376 377 if (tid == -1) { 378 exit(1); 379 } 380 for (i = 0; i < NKIDS; i++) { 381 if (kill(kidarray[i], SIGTERM) != 0) { 382 tst_resm(TFAIL, "Kill error kid id = %d :", 383 kidarray[1]); 384 } 385 } 386} 387 388void setup(void) 389{ 390 tst_sig(FORK, DEF_HANDLER, cleanup); 391 392 TEST_PAUSE; 393 394 tst_tmpdir(); 395} 396 397void cleanup(void) 398{ 399 tst_rmdir(); 400 TEST_CLEANUP; 401} 402