unstack, sort: cleanup and improvement
[minix.git] / test / ipc / semctl / semctl06.c
blobc3957be1ea24eee102cec0b534e14f29c71a77c4
1 /*
3 * Copyright (c) International Business Machines Corp., 2002
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.
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.
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
20 /* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
21 /* 10/30/2002 Port to LTP dbarrera@us.ibm.com */
25 * NAME
26 * semctl06
28 * CALLS
29 * semctl(2) semget(2) semop(2)
31 * ALGORITHM
32 * Get and manipulate a set of semaphores.
34 * RESTRICTIONS
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.
42 #define DEBUG 0
44 #ifdef UCLINUX
45 #define _GNU_SOURCE /* for asprintf */
46 #include <stdio.h>
47 #endif
49 #include <sys/types.h> /* needed for test */
50 #include <sys/ipc.h> /* needed for test */
51 #include <sys/sem.h> /* needed for test */
52 #include <unistd.h>
53 #include <errno.h>
54 #include <stdlib.h>
55 #include <signal.h>
56 #include "test.h"
57 #include "usctest.h"
58 #include <sys/wait.h>
59 #include "ipcsem.h"
61 int local_flag=1;
64 #define NREPS 10
65 #define NPROCS 3
66 #define NKIDS 5
67 #define NSEMS 5
68 #define HVAL 1000
69 #define LVAL 100
70 #define FAILED 0
72 void setup (void);
73 void cleanup(void);
75 static key_t keyarray[NPROCS];
76 static struct sembuf semops[NSEMS];
77 static short maxsemvals[NSEMS];
78 static int pidarray[NPROCS];
79 static int kidarray[NKIDS];
80 static int tid;
81 static int procstat;
82 static char *prog;
83 static unsigned short semvals[NSEMS];
86 * * These globals must be defined in the test.
87 * * */
90 char *TCID="semctl06"; /* Test program identifier. */
91 int TST_TOTAL=1; /* Total number of test cases. */
92 extern int Tst_count; /* Test Case counter for tst_* routines */
94 int exp_enos[]={0}; /* List must end with 0 */
97 static void term(int sig);
98 static void dosemas(int id);
99 static void dotest(key_t key);
101 #ifdef UCLINUX
102 static char *argv0;
104 void do_child();
105 static int id_uclinux;
106 static char *maxsemstring;
107 #endif
109 /*--------------------------------------------------------------*/
110 /*ARGSUSED*/
112 main(int argc, char **argv)
114 register int i, j, ok, pid;
115 int count, child, status, nwait;
117 #ifdef UCLINUX
118 char *msg;
119 if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != (char *)NULL){
120 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
123 argv0 = argv[0];
124 maybe_run_child(&do_child, "dS", &id_uclinux, &maxsemstring);
125 #endif
127 prog = argv[0];
128 nwait = 0;
129 setup();
130 /*--------------------------------------------------------------*/
131 srand(getpid());
133 tid = -1;
135 for (i = 0; i < NPROCS; i++) {
136 do {
137 keyarray[i] = (key_t)rand();
138 if (keyarray[i] == IPC_PRIVATE) {
139 ok = 0;
140 continue;
142 ok = 1;
143 for (j = 0; j < i; j++) {
144 if (keyarray[j] == keyarray[i]) {
145 ok = 0;
146 break;
149 } while (ok == 0);
152 if ((signal(SIGTERM, term)) == SIG_ERR) {
153 tst_resm(TFAIL, "\tsignal failed. errno = %d", errno);
154 tst_exit();
157 for (i = 0; i < NPROCS; i++) {
158 if ((pid = FORK_OR_VFORK()) < 0) {
159 tst_resm(TFAIL, "\tFork failed (may be OK if under stress)");
160 tst_exit();
162 if (pid == 0) {
163 procstat = 1;
164 dotest(keyarray[i]);
165 exit(0);
167 pidarray[i] = pid;
168 nwait++;
172 * Wait for children to finish.
175 count = 0;
176 while((child = wait(&status)) > 0) {
177 if (status) {
178 tst_resm(TFAIL, "%s[%d] Test failed. exit=0x%x", prog, child, status);
179 local_flag = FAILED;
181 ++count;
185 * Should have collected all children.
188 if (count != nwait) {
189 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", count);
190 local_flag = FAILED;
193 if (local_flag != FAILED)
194 tst_resm(TPASS, "semctl06 ran successfully!");
195 else tst_resm(TFAIL, "semctl06 failed");
197 /*--------------------------------------------------------------*/
198 /* Clean up any files created by test before call to anyfail. */
200 cleanup ();
202 return (0); /* shut lint up */
204 /*--------------------------------------------------------------*/
207 static void
208 dotest(key_t key)
210 int id, pid, status;
211 int count, child, nwait;
212 short i;
213 union semun get_arr;
215 nwait = 0;
216 srand(getpid());
217 if ((id = semget(key, NSEMS, IPC_CREAT)) < 0) {
218 tst_resm(TFAIL, "\tsemget() failed errno %d", errno);
219 exit(1);
221 tid = id;
222 for (i = 0; i < NSEMS; i++) {
223 do {
224 maxsemvals[i] = /*CASTOK*/(short)(rand() % HVAL);
225 } while (maxsemvals[i] < LVAL);
226 semops[i].sem_num = i;
227 semops[i].sem_op = maxsemvals[i];
228 semops[i].sem_flg = SEM_UNDO;
230 if (semop(id, semops, NSEMS) < 0) {
231 tst_resm(TFAIL, "\tfirst semop() failed errno %d", errno);
232 exit(1);
235 for (i = 0; i < NKIDS; i++) {
236 if ((pid = FORK_OR_VFORK()) < 0) {
237 tst_resm(TFAIL, "\tfork failed");
239 if (pid == 0) {
240 #ifdef UCLINUX
241 int j;
242 maxsemstring = "";
243 for (j = 0; j < NSEMS; j++) {
244 if (asprintf(&maxsemstring, "%s%s%d",
245 maxsemstring, (j ? ":" : ""),
246 maxsemvals[j]) < 0) {
247 tst_resm(TBROK, "Could not serialize "
248 "maxsemvals");
249 tst_exit();
252 if (self_exec(argv0, "dS", id, maxsemstring) < 0) {
253 tst_resm(TFAIL, "\tself_exec failed");
255 #else
256 dosemas(id);
257 #endif
259 if (pid > 0) {
260 kidarray[i] = pid;
261 nwait++;
266 procstat = 2;
268 * Wait for children to finish.
271 count = 0;
272 while((child = wait(&status)) > 0) {
273 if (status) {
274 tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x", prog, child, status);
275 local_flag = FAILED;
277 ++count;
281 * Should have collected all children.
284 if (count != nwait) {
285 tst_resm(TFAIL, "\tWrong # children waited on, count = %d", count);
286 local_flag = FAILED;
289 get_arr.array = semvals;
290 if (semctl(id, 0, GETALL, get_arr) < 0) {
291 tst_resm(TFAIL, "\terror on GETALL");
292 tst_resm(TFAIL, "\tsemctl() failed errno %d", errno);
295 if (DEBUG)
296 tst_resm(TINFO, "\tchecking maxvals");
297 for (i = 0; i < NSEMS; i++) {
298 if (semvals[i] != maxsemvals[i]) {
299 tst_resm(TFAIL, "\terror on i %d orig %d final %d", i, semvals[i],
300 maxsemvals[i]);
301 local_flag = FAILED;
304 if (DEBUG)
305 tst_resm(TINFO, "\tmaxvals checked");
307 /* 4th arg must either be missing, or must be of type 'union semun'.
308 * CANNOT just be an int, else it crashes on ppc.
310 get_arr.val = 0;
311 if (semctl(id, 0, IPC_RMID, get_arr) < 0) {
312 tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d", errno);
313 local_flag = FAILED;
315 if (local_flag == FAILED)
316 exit(1);
319 #ifdef UCLINUX
320 void
321 do_child()
323 int i;
324 char *tok;
325 char *endptr;
327 tok = strtok(maxsemstring, ":");
328 for (i = 0; i < NSEMS; i++) {
329 if (strlen(tok) == 0) {
330 tst_resm(TBROK, "Invalid argument to -C option");
331 tst_exit();
334 maxsemvals[i] = strtol(tok, &endptr, 10);
335 if (*endptr != '\0') {
336 tst_resm(TBROK, "Invalid argument to -C option");
337 tst_exit();
339 tok = strtok(NULL, ":");
342 dosemas(id_uclinux);
344 #endif
346 static void
347 dosemas(int id)
349 int i, j;
351 srand(getpid());
352 for (i = 0; i < NREPS; i++) {
353 for (j = 0; j < NSEMS; j++) {
354 semops[j].sem_num = j;
355 semops[j].sem_flg = SEM_UNDO;
357 do {
358 semops[j].sem_op =
359 ( - /*CASTOK*/(short)(rand() % (maxsemvals[j]/2)));
360 } while (semops[j].sem_op == 0);
362 if (semop(id, semops, NSEMS) < 0) {
363 tst_resm(TFAIL, "\tsemop1 failed errno %d", errno);
364 exit(1);
366 for (j = 0; j < NSEMS; j++) {
367 semops[j].sem_op = ( - semops[j].sem_op);
369 if (semop(id, semops, NSEMS) < 0) {
370 tst_resm(TFAIL, "\tsemop2 failed errno %d", errno);
371 exit(1);
374 exit(0);
378 /*ARGSUSED*/
379 static void
380 term(int sig)
382 int i;
384 if ((signal(SIGTERM, term)) == SIG_ERR) {
385 tst_resm(TFAIL, "\tsignal failed. errno %d", errno);
386 exit(1);
388 if (procstat == 0) {
389 if (DEBUG)
390 tst_resm(TINFO, "\ttest killing kids");
391 for (i = 0; i < NPROCS; i++) {
392 if (kill(pidarray[i], SIGTERM) != 0) {
393 tst_resm(TFAIL, "Kill error pid = %d :",pidarray[1]);
396 if (DEBUG)
397 tst_resm(TINFO, "\ttest kids killed");
398 return;
401 if (procstat == 1) {
402 /* 4th arg must either be missing, or must be of type 'union semun'.
403 * CANNOT just be an int, else it crashes on ppc.
405 union semun arg;
406 arg.val = 0;
407 (void)semctl(tid, 0, IPC_RMID, arg);
408 exit(1);
411 if (tid == -1) {
412 exit(1);
414 for (i = 0; i < NKIDS; i++) {
415 if (kill(kidarray[i], SIGTERM) != 0) {
416 tst_resm(TFAIL, "Kill error kid id = %d :",kidarray[1]);
421 /***************************************************************
422 * setup() - performs all ONE TIME setup for this test.
423 *****************************************************************/
424 void
425 setup()
427 /* You will want to enable some signal handling so you can capture
428 * unexpected signals like SIGSEGV.
429 * */
430 tst_sig(FORK, DEF_HANDLER, cleanup);
433 /* Pause if that option was specified */
434 /* One cavet that hasn't been fixed yet. TEST_PAUSE contains the code to
435 * fork the test with the -c option. You want to make sure you do this
436 * before you create your temporary directory.
438 TEST_PAUSE;
442 /***************************************************************
443 * cleanup() - performs all ONE TIME cleanup for this test at
444 * completion or premature exit.
445 ****************************************************************/
446 void
447 cleanup()
450 * print timing stats if that option was specified.
451 * print errno log if that option was specified.
453 TEST_CLEANUP;
455 /* exit with return code appropriate for results */
456 tst_exit();