Home | History | Annotate | Download | only in semctl
      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