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 (at) us.ibm.com 39 * 10/30/2002 Port to LTP dbarrera (at) us.ibm.com 40 * 12/03/2008 Matthieu Fertr (Matthieu.Fertre (at) 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 <sys/wait.h> 61 #include "ipcsem.h" 62 63 int local_flag = 1; 64 65 #define NREPS 500 66 #define NPROCS 3 67 #define NKIDS 5 68 #define NSEMS 5 69 #define HVAL 1000 70 #define LVAL 100 71 #define FAILED 0 72 73 void setup(); 74 void cleanup(); 75 76 static key_t keyarray[NPROCS]; 77 static struct sembuf semops[NSEMS]; 78 static short maxsemvals[NSEMS]; 79 static int pidarray[NPROCS]; 80 static int kidarray[NKIDS]; 81 static int tid; 82 static int procstat; 83 static char *prog; 84 static unsigned short semvals[NSEMS]; 85 86 char *TCID = "semctl06"; 87 int TST_TOTAL = 1; 88 89 static void term(int sig); 90 static void dosemas(int id); 91 static void dotest(key_t key); 92 93 int main(int argc, char **argv) 94 { 95 register int i, pid; 96 int count, child, status, nwait; 97 98 tst_parse_opts(argc, argv, NULL, NULL); 99 100 prog = argv[0]; 101 nwait = 0; 102 setup(); 103 104 tid = -1; 105 106 for (i = 0; i < NPROCS; i++) 107 keyarray[i] = getipckey(); 108 109 if ((signal(SIGTERM, term)) == SIG_ERR) { 110 tst_resm(TFAIL, "\tsignal failed. errno = %d", errno); 111 112 } 113 114 for (i = 0; i < NPROCS; i++) { 115 if ((pid = FORK_OR_VFORK()) < 0) { 116 tst_resm(TFAIL, 117 "\tFork failed (may be OK if under stress)"); 118 119 } 120 if (pid == 0) { 121 procstat = 1; 122 dotest(keyarray[i]); 123 exit(0); 124 } 125 pidarray[i] = pid; 126 nwait++; 127 } 128 129 /* 130 * Wait for children to finish. 131 */ 132 133 count = 0; 134 while ((child = wait(&status)) > 0) { 135 if (status) { 136 tst_resm(TFAIL, "%s[%d] Test failed. exit=0x%x", prog, 137 child, status); 138 local_flag = FAILED; 139 } 140 ++count; 141 } 142 143 /* 144 * Should have collected all children. 145 */ 146 147 if (count != nwait) { 148 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", 149 count); 150 local_flag = FAILED; 151 } 152 153 if (local_flag != FAILED) 154 tst_resm(TPASS, "semctl06 ran successfully!"); 155 else 156 tst_resm(TFAIL, "semctl06 failed"); 157 158 159 cleanup(); 160 tst_exit(); 161 } 162 163 static void dotest(key_t key) 164 { 165 int id, pid, status; 166 int count, child, nwait; 167 short i; 168 union semun get_arr; 169 170 nwait = 0; 171 srand(getpid()); 172 if ((id = semget(key, NSEMS, IPC_CREAT | IPC_EXCL)) < 0) { 173 tst_resm(TFAIL, "\tsemget() failed errno %d", errno); 174 exit(1); 175 } 176 tid = id; 177 for (i = 0; i < NSEMS; i++) { 178 do { 179 maxsemvals[i] = (short) (rand() % HVAL); 180 } while (maxsemvals[i] < LVAL); 181 semops[i].sem_num = i; 182 semops[i].sem_op = maxsemvals[i]; 183 semops[i].sem_flg = SEM_UNDO; 184 } 185 if (semop(id, semops, NSEMS) < 0) { 186 tst_resm(TFAIL, "\tfirst semop() failed errno %d", errno); 187 exit(1); 188 } 189 190 for (i = 0; i < NKIDS; i++) { 191 if ((pid = FORK_OR_VFORK()) < 0) { 192 tst_resm(TFAIL, "\tfork failed"); 193 } 194 if (pid == 0) 195 dosemas(id); 196 if (pid > 0) { 197 kidarray[i] = pid; 198 nwait++; 199 } 200 } 201 202 procstat = 2; 203 /* 204 * Wait for children to finish. 205 */ 206 207 count = 0; 208 while ((child = wait(&status)) > 0) { 209 if (status) { 210 tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x", 211 prog, child, status); 212 local_flag = FAILED; 213 } 214 ++count; 215 } 216 217 /* 218 * Should have collected all children. 219 */ 220 221 if (count != nwait) { 222 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", 223 count); 224 local_flag = FAILED; 225 } 226 227 get_arr.array = semvals; 228 if (semctl(id, 0, GETALL, get_arr) < 0) { 229 tst_resm(TFAIL, "\terror on GETALL"); 230 tst_resm(TFAIL, "\tsemctl() failed errno %d", errno); 231 } 232 233 if (DEBUG) 234 tst_resm(TINFO, "\tchecking maxvals"); 235 for (i = 0; i < NSEMS; i++) { 236 if (semvals[i] != maxsemvals[i]) { 237 tst_resm(TFAIL, "\terror on i %d orig %d final %d", i, 238 semvals[i], maxsemvals[i]); 239 local_flag = FAILED; 240 } 241 } 242 if (DEBUG) 243 tst_resm(TINFO, "\tmaxvals checked"); 244 245 /* 4th arg must either be missing, or must be of type 'union semun'. 246 * CANNOT just be an int, else it crashes on ppc. 247 */ 248 get_arr.val = 0; 249 if (semctl(id, 0, IPC_RMID, get_arr) < 0) { 250 tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d", errno); 251 local_flag = FAILED; 252 } 253 if (local_flag == FAILED) 254 exit(1); 255 } 256 257 static void dosemas(int id) 258 { 259 int i, j; 260 261 srand(getpid()); 262 for (i = 0; i < NREPS; i++) { 263 for (j = 0; j < NSEMS; j++) { 264 semops[j].sem_num = j; 265 semops[j].sem_flg = SEM_UNDO; 266 267 do { 268 semops[j].sem_op = 269 (-(short) (rand() % 270 (maxsemvals[j] / 2))); 271 } while (semops[j].sem_op == 0); 272 } 273 if (semop(id, semops, NSEMS) < 0) { 274 tst_resm(TFAIL, "\tsemop1 failed errno %d", errno); 275 exit(1); 276 } 277 for (j = 0; j < NSEMS; j++) { 278 semops[j].sem_op = (-semops[j].sem_op); 279 } 280 if (semop(id, semops, NSEMS) < 0) { 281 tst_resm(TFAIL, "\tsemop2 failed errno %d", errno); 282 exit(1); 283 } 284 } 285 exit(0); 286 } 287 288 static void term(int sig) 289 { 290 int i; 291 292 if ((signal(SIGTERM, term)) == SIG_ERR) { 293 tst_resm(TFAIL, "\tsignal failed. errno %d", errno); 294 exit(1); 295 } 296 if (procstat == 0) { 297 if (DEBUG) 298 tst_resm(TINFO, "\ttest killing kids"); 299 for (i = 0; i < NPROCS; i++) { 300 if (kill(pidarray[i], SIGTERM) != 0) { 301 tst_resm(TFAIL, "Kill error pid = %d :", 302 pidarray[1]); 303 } 304 } 305 if (DEBUG) 306 tst_resm(TINFO, "\ttest kids killed"); 307 return; 308 } 309 310 if (procstat == 1) { 311 /* 4th arg must either be missing, or must be of type 'union semun'. 312 * CANNOT just be an int, else it crashes on ppc. 313 */ 314 union semun arg; 315 arg.val = 0; 316 (void)semctl(tid, 0, IPC_RMID, arg); 317 exit(1); 318 } 319 320 if (tid == -1) { 321 exit(1); 322 } 323 for (i = 0; i < NKIDS; i++) { 324 if (kill(kidarray[i], SIGTERM) != 0) { 325 tst_resm(TFAIL, "Kill error kid id = %d :", 326 kidarray[1]); 327 } 328 } 329 } 330 331 void setup(void) 332 { 333 tst_sig(FORK, DEF_HANDLER, cleanup); 334 335 TEST_PAUSE; 336 337 tst_tmpdir(); 338 } 339 340 void cleanup(void) 341 { 342 tst_rmdir(); 343 } 344