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