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 */
29 * semctl(2) semget(2) semop(2)
32 * Get and manipulate a set of semaphores.
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.
45 #define _GNU_SOURCE /* for asprintf */
49 #include <sys/types.h> /* needed for test */
50 #include <sys/ipc.h> /* needed for test */
51 #include <sys/sem.h> /* needed for test */
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
];
83 static unsigned short semvals
[NSEMS
];
86 * * These globals must be defined in the test.
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
);
105 static int id_uclinux
;
106 static char *maxsemstring
;
109 /*--------------------------------------------------------------*/
112 main(int argc
, char **argv
)
114 register int i
, j
, ok
, pid
;
115 int count
, child
, status
, nwait
;
119 if ((msg
= parse_opts(argc
, argv
, (option_t
*)NULL
, NULL
)) != (char *)NULL
){
120 tst_brkm(TBROK
, cleanup
, "OPTION PARSING ERROR - %s", msg
);
124 maybe_run_child(&do_child
, "dS", &id_uclinux
, &maxsemstring
);
130 /*--------------------------------------------------------------*/
135 for (i
= 0; i
< NPROCS
; i
++) {
137 keyarray
[i
] = (key_t
)rand();
138 if (keyarray
[i
] == IPC_PRIVATE
) {
143 for (j
= 0; j
< i
; j
++) {
144 if (keyarray
[j
] == keyarray
[i
]) {
152 if ((signal(SIGTERM
, term
)) == SIG_ERR
) {
153 tst_resm(TFAIL
, "\tsignal failed. errno = %d", errno
);
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)");
172 * Wait for children to finish.
176 while((child
= wait(&status
)) > 0) {
178 tst_resm(TFAIL
, "%s[%d] Test failed. exit=0x%x", prog
, child
, status
);
185 * Should have collected all children.
188 if (count
!= nwait
) {
189 tst_resm(TFAIL
, "\tWrong # children waited on, count = %d", count
);
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. */
202 return (0); /* shut lint up */
204 /*--------------------------------------------------------------*/
211 int count
, child
, nwait
;
217 if ((id
= semget(key
, NSEMS
, IPC_CREAT
)) < 0) {
218 tst_resm(TFAIL
, "\tsemget() failed errno %d", errno
);
222 for (i
= 0; i
< NSEMS
; i
++) {
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
);
235 for (i
= 0; i
< NKIDS
; i
++) {
236 if ((pid
= FORK_OR_VFORK()) < 0) {
237 tst_resm(TFAIL
, "\tfork failed");
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 "
252 if (self_exec(argv0
, "dS", id
, maxsemstring
) < 0) {
253 tst_resm(TFAIL
, "\tself_exec failed");
268 * Wait for children to finish.
272 while((child
= wait(&status
)) > 0) {
274 tst_resm(TFAIL
, "\t%s:dotest[%d] exited status = 0x%x", prog
, child
, status
);
281 * Should have collected all children.
284 if (count
!= nwait
) {
285 tst_resm(TFAIL
, "\tWrong # children waited on, count = %d", count
);
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
);
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
],
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.
311 if (semctl(id
, 0, IPC_RMID
, get_arr
) < 0) {
312 tst_resm(TFAIL
, "\tsemctl(IPC_RMID) failed errno %d", errno
);
315 if (local_flag
== FAILED
)
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");
334 maxsemvals
[i
] = strtol(tok
, &endptr
, 10);
335 if (*endptr
!= '\0') {
336 tst_resm(TBROK
, "Invalid argument to -C option");
339 tok
= strtok(NULL
, ":");
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
;
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
);
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
);
384 if ((signal(SIGTERM
, term
)) == SIG_ERR
) {
385 tst_resm(TFAIL
, "\tsignal failed. errno %d", errno
);
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]);
397 tst_resm(TINFO
, "\ttest kids killed");
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.
407 (void)semctl(tid
, 0, IPC_RMID
, arg
);
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 *****************************************************************/
427 /* You will want to enable some signal handling so you can capture
428 * unexpected signals like SIGSEGV.
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.
442 /***************************************************************
443 * cleanup() - performs all ONE TIME cleanup for this test at
444 * completion or premature exit.
445 ****************************************************************/
450 * print timing stats if that option was specified.
451 * print errno log if that option was specified.
455 /* exit with return code appropriate for results */