semctl06.c revision 345990d7443c8249c8fc20e45bf98195cab6e7a5
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/* 06/30/2001	Port to Linux	nsharoff@us.ibm.com */
21/* 10/30/2002	Port to LTP	dbarrera@us.ibm.com */
22
23
24/*
25 * NAME
26 *	semctl06
27 *
28 * CALLS
29 *	semctl(2) semget(2) semop(2)
30 *
31 * ALGORITHM
32 *	Get and manipulate a set of semaphores.
33 *
34 * RESTRICTIONS
35 *
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.
40 */
41
42
43#include <sys/types.h>		/* needed for test		*/
44#include <sys/ipc.h>		/* needed for test		*/
45#include <sys/sem.h>		/* needed for test		*/
46#include <unistd.h>
47#include <errno.h>
48#include <stdlib.h>
49#include <signal.h>
50#include "test.h"
51#include "usctest.h"
52#include <wait.h>
53#include "ipcsem.h"
54
55int local_flag=1;
56
57
58#define NREPS	500
59#define NPROCS	3
60#define NKIDS	5
61#define NSEMS	5
62#define HVAL	1000
63#define LVAL	100
64#define FAILED	0
65
66void setup ();
67void cleanup();
68
69static key_t		keyarray[NPROCS];
70static struct sembuf	semops[NSEMS];
71static short		maxsemvals[NSEMS];
72static int		pidarray[NPROCS];
73static int		kidarray[NKIDS];
74static int		tid;
75static int		procstat;
76static char	       *prog;
77static short		semvals[NSEMS];
78
79/*
80 *  * These globals must be defined in the test.
81 *   * */
82
83
84char *TCID="semctl06";           /* Test program identifier.    */
85int TST_TOTAL=1;                /* Total number of test cases. */
86extern int Tst_count;           /* Test Case counter for tst_* routines */
87
88int exp_enos[]={0};     /* List must end with 0 */
89
90
91static void term(int sig);
92static void dosemas(int id);
93static void dotest(key_t key);
94
95
96/*--------------------------------------------------------------*/
97/*ARGSUSED*/
98int
99main(int argc, char **argv)
100{
101	register int i, j, ok, pid;
102	int count, child, status, nwait;
103
104	prog = argv[0];
105	nwait = 0;
106	setup();
107/*--------------------------------------------------------------*/
108	srand(getpid());
109
110	tid = -1;
111
112	for (i = 0; i < NPROCS; i++) {
113		do {
114			keyarray[i] = (key_t)rand();
115			if (keyarray[i] == IPC_PRIVATE) {
116				ok = 0;
117				continue;
118			}
119			ok = 1;
120			for (j = 0; j < i; j++) {
121				if (keyarray[j] == keyarray[i]) {
122					ok = 0;
123					break;
124				}
125			}
126		} while (ok == 0);
127	}
128
129	if ((signal(SIGTERM, term)) == SIG_ERR) {
130                tst_resm(TFAIL, "\tsignal failed. errno = %d\n", errno);
131		tst_exit();
132	}
133
134	for (i = 0; i <  NPROCS; i++) {
135		if ((pid = fork()) < 0) {
136                        tst_resm(TFAIL, "\tFork failed (may be OK if under stress)");
137                        tst_exit();
138		}
139		if (pid == 0) {
140			procstat = 1;
141			dotest(keyarray[i]);
142			exit(0);
143		}
144		pidarray[i] = pid;
145		nwait++;
146	}
147
148	/*
149	 * Wait for children to finish.
150	 */
151
152	count = 0;
153	while((child = wait(&status)) > 0) {
154		if (status) {
155	                tst_resm(TFAIL, "%s[%d] Test failed.  exit=0x%x\n", prog, child, status);
156			local_flag = FAILED;
157		}
158		++count;
159	}
160
161	/*
162	 * Should have collected all children.
163	 */
164
165	if (count != nwait) {
166                tst_resm(TFAIL, "\tWrong # children waited on, count = %d\n", count);
167		local_flag = FAILED;
168	}
169
170	if (local_flag != FAILED)
171		tst_resm(TPASS, "semctl06 ran successfully!");
172	else tst_resm(TFAIL, "semctl06 failed");
173
174/*--------------------------------------------------------------*/
175/* Clean up any files created by test before call to anyfail.	*/
176
177	cleanup ();
178
179	return (0); /* shut lint up */
180}
181/*--------------------------------------------------------------*/
182
183
184static void
185dotest(key_t key)
186{
187	int id, pid, status;
188	int count, child, nwait;
189	short i;
190		 union semun get_arr;
191
192	nwait = 0;
193	srand(getpid());
194	if ((id = semget(key, NSEMS, IPC_CREAT)) < 0) {
195		tst_resm(TFAIL, "\tsemget() failed errno %d\n", errno);
196		exit(1);
197	}
198	tid = id;
199	for (i = 0; i < NSEMS; i++) {
200		do {
201			maxsemvals[i] = /*CASTOK*/(short)(rand() % HVAL);
202		} while (maxsemvals[i] < LVAL);
203		semops[i].sem_num = i;
204		semops[i].sem_op = maxsemvals[i];
205		semops[i].sem_flg = SEM_UNDO;
206	}
207	if (semop(id, semops, NSEMS) < 0) {
208		tst_resm(TFAIL, "\tfirst semop() failed errno %d\n", errno);
209		exit(1);
210	}
211
212	for (i = 0; i < NKIDS; i++) {
213		if ((pid = fork()) < 0) {
214		tst_resm(TFAIL, "\tfork failed\n");
215		}
216		if (pid == 0) {
217			dosemas(id);
218		}
219		if (pid > 0) {
220			kidarray[i] = pid;
221			nwait++;
222		}
223	}
224
225
226	procstat = 2;
227	/*
228	 * Wait for children to finish.
229	 */
230
231	count = 0;
232	while((child = wait(&status)) > 0) {
233		if (status) {
234	                tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x\n", prog, child, status);
235			local_flag = FAILED;
236		}
237		++count;
238	}
239
240	/*
241	 * Should have collected all children.
242	 */
243
244	if (count != nwait) {
245                tst_resm(TFAIL, "\tWrong # children waited on, count = %d\n", count);
246		local_flag = FAILED;
247	}
248
249		 get_arr.array = semvals;
250		 if (semctl(id, 0, GETALL, get_arr) < 0) {
251                tst_resm(TFAIL, "\terror on GETALL\n");
252		tst_resm(TFAIL, "\tsemctl() failed errno %d\n", errno);
253	}
254
255	tst_resm(TINFO, "\tchecking maxvals\n");
256	for (i = 0; i < NSEMS; i++) {
257		if (semvals[i] !=  maxsemvals[i]) {
258			tst_resm(TFAIL, "\terror on i %d orig %d final %d\n", i, semvals[i],
259					maxsemvals[i]);
260			local_flag = FAILED;
261		}
262	}
263	tst_resm(TINFO, "\tmaxvals checked\n");
264
265	if (semctl(id, 0, IPC_RMID, 0) < 0) {
266		tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d\n", errno);
267		local_flag = FAILED;
268	}
269	if (local_flag == FAILED)
270		exit(1);
271}
272
273
274static void
275dosemas(int id)
276{
277	int i, j;
278
279	srand(getpid());
280	for (i = 0; i < NREPS; i++) {
281		for (j = 0; j < NSEMS; j++) {
282			do {
283				semops[j].sem_op =
284					( - /*CASTOK*/(short)(rand() % (maxsemvals[j]/2)));
285			} while (semops[j].sem_op == 0);
286		}
287		if (semop(id, semops, NSEMS) < 0) {
288			tst_resm(TFAIL, "\tsemop1 failed errno %d\n", errno);
289			exit(1);
290		}
291		for (j = 0; j < NSEMS; j++) {
292			semops[j].sem_op = ( - semops[j].sem_op);
293		}
294		if (semop(id, semops, NSEMS) < 0) {
295			tst_resm(TFAIL, "\tsemop2 failed errno %d\n", errno);
296			exit(1);
297		}
298	}
299	exit(0);
300}
301
302
303/*ARGSUSED*/
304static void
305term(int sig)
306{
307	int i;
308
309	if ((signal(SIGTERM, term)) == SIG_ERR) {
310		tst_resm(TFAIL, "\tsignal failed. errno %d\n", errno);
311		exit(1);
312	}
313	if (procstat == 0) {
314		tst_resm(TINFO, "\ttest killing kids\n");
315		for (i = 0; i < NPROCS; i++) {
316			if (kill(pidarray[i], SIGTERM) != 0) {
317				tst_resm(TFAIL, "Kill error pid = %d :",pidarray[1]);
318			}
319		}
320		tst_resm(TINFO, "\ttest kids killed\n");
321		return;
322	}
323
324	if (procstat == 1) {
325		(void)semctl(tid, 0, IPC_RMID, 0);
326		exit(1);
327	}
328
329	if (tid == -1) {
330		exit(1);
331	}
332	for (i = 0; i < NKIDS; i++) {
333		if (kill(kidarray[i], SIGTERM) != 0) {
334			tst_resm(TFAIL, "Kill error kid id = %d :",kidarray[1]);
335		}
336	}
337}
338
339/***************************************************************
340 * setup() - performs all ONE TIME setup for this test.
341 *****************************************************************/
342void
343setup()
344{
345        /* You will want to enable some signal handling so you can capture
346	 * unexpected signals like SIGSEGV.
347	 *                   */
348        tst_sig(FORK, DEF_HANDLER, cleanup);
349
350
351        /* Pause if that option was specified */
352        /* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
353	 * fork the test with the -c option.  You want to make sure you do this
354	 * before you create your temporary directory.
355	 */
356        TEST_PAUSE;
357}
358
359
360/***************************************************************
361 * cleanup() - performs all ONE TIME cleanup for this test at
362 * completion or premature exit.
363 ****************************************************************/
364void
365cleanup()
366{
367        /*
368	 * print timing stats if that option was specified.
369	 * print errno log if that option was specified.
370	 */
371        TEST_CLEANUP;
372
373        /* exit with return code appropriate for results */
374        tst_exit();
375}
376
377