1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci *
3f08c3bdfSopenharmony_ci *   Copyright (c) International Business Machines  Corp., 2002
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci *   This program is free software;  you can redistribute it and/or modify
6f08c3bdfSopenharmony_ci *   it under the terms of the GNU General Public License as published by
7f08c3bdfSopenharmony_ci *   the Free Software Foundation; either version 2 of the License, or
8f08c3bdfSopenharmony_ci *   (at your option) any later version.
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci *   This program is distributed in the hope that it will be useful,
11f08c3bdfSopenharmony_ci *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12f08c3bdfSopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13f08c3bdfSopenharmony_ci *   the GNU General Public License for more details.
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci *   You should have received a copy of the GNU General Public License
16f08c3bdfSopenharmony_ci *   along with this program;  if not, write to the Free Software
17f08c3bdfSopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci/*
21f08c3bdfSopenharmony_ci * NAME
22f08c3bdfSopenharmony_ci *	semctl06
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci * CALLS
25f08c3bdfSopenharmony_ci *	semctl(2) semget(2) semop(2)
26f08c3bdfSopenharmony_ci *
27f08c3bdfSopenharmony_ci * ALGORITHM
28f08c3bdfSopenharmony_ci *	Get and manipulate a set of semaphores.
29f08c3bdfSopenharmony_ci *
30f08c3bdfSopenharmony_ci * RESTRICTIONS
31f08c3bdfSopenharmony_ci *
32f08c3bdfSopenharmony_ci * WARNING
33f08c3bdfSopenharmony_ci *	If this test fail, it may be necessary to use the ipcs and ipcrm
34f08c3bdfSopenharmony_ci *	commands to remove any semaphores left in the system due to a
35f08c3bdfSopenharmony_ci *	premature exit of this test.
36f08c3bdfSopenharmony_ci *
37f08c3bdfSopenharmony_ci * HISTORY
38f08c3bdfSopenharmony_ci *      06/30/2001	Port to Linux	nsharoff@us.ibm.com
39f08c3bdfSopenharmony_ci *      10/30/2002	Port to LTP	dbarrera@us.ibm.com
40f08c3bdfSopenharmony_ci *      12/03/2008 Matthieu Fertré (Matthieu.Fertre@irisa.fr)
41f08c3bdfSopenharmony_ci *      - Fix concurrency issue. The IPC keys used for this test could
42f08c3bdfSopenharmony_ci *        conflict with keys from another task.
43f08c3bdfSopenharmony_ci */
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci#define DEBUG 0
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_ci#ifdef UCLINUX
48f08c3bdfSopenharmony_ci#define _GNU_SOURCE
49f08c3bdfSopenharmony_ci#include <stdio.h>
50f08c3bdfSopenharmony_ci#endif
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci#include <sys/types.h>
53f08c3bdfSopenharmony_ci#include <sys/ipc.h>
54f08c3bdfSopenharmony_ci#include <sys/sem.h>
55f08c3bdfSopenharmony_ci#include <unistd.h>
56f08c3bdfSopenharmony_ci#include <errno.h>
57f08c3bdfSopenharmony_ci#include <stdlib.h>
58f08c3bdfSopenharmony_ci#include <signal.h>
59f08c3bdfSopenharmony_ci#include "test.h"
60f08c3bdfSopenharmony_ci#include <sys/wait.h>
61f08c3bdfSopenharmony_ci#include "ipcsem.h"
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ciint local_flag = 1;
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci#define NREPS	500
66f08c3bdfSopenharmony_ci#define NPROCS	3
67f08c3bdfSopenharmony_ci#define NKIDS	5
68f08c3bdfSopenharmony_ci#define NSEMS	5
69f08c3bdfSopenharmony_ci#define HVAL	1000
70f08c3bdfSopenharmony_ci#define LVAL	100
71f08c3bdfSopenharmony_ci#define FAILED	0
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_civoid setup();
74f08c3bdfSopenharmony_civoid cleanup();
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_cistatic key_t keyarray[NPROCS];
77f08c3bdfSopenharmony_cistatic struct sembuf semops[NSEMS];
78f08c3bdfSopenharmony_cistatic short maxsemvals[NSEMS];
79f08c3bdfSopenharmony_cistatic int pidarray[NPROCS];
80f08c3bdfSopenharmony_cistatic int kidarray[NKIDS];
81f08c3bdfSopenharmony_cistatic int tid;
82f08c3bdfSopenharmony_cistatic int procstat;
83f08c3bdfSopenharmony_cistatic char *prog;
84f08c3bdfSopenharmony_cistatic unsigned short semvals[NSEMS];
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_cichar *TCID = "semctl06";
87f08c3bdfSopenharmony_ciint TST_TOTAL = 1;
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_cistatic void term(int sig);
90f08c3bdfSopenharmony_cistatic void dosemas(int id);
91f08c3bdfSopenharmony_cistatic void dotest(key_t key);
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ciint main(int argc, char **argv)
94f08c3bdfSopenharmony_ci{
95f08c3bdfSopenharmony_ci	register int i, pid;
96f08c3bdfSopenharmony_ci	int count, child, status, nwait;
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	tst_parse_opts(argc, argv, NULL, NULL);
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci	prog = argv[0];
101f08c3bdfSopenharmony_ci	nwait = 0;
102f08c3bdfSopenharmony_ci	setup();
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	tid = -1;
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci	for (i = 0; i < NPROCS; i++)
107f08c3bdfSopenharmony_ci		keyarray[i] = getipckey();
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci	if ((signal(SIGTERM, term)) == SIG_ERR) {
110f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tsignal failed. errno = %d", errno);
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	}
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci	for (i = 0; i < NPROCS; i++) {
115f08c3bdfSopenharmony_ci		if ((pid = FORK_OR_VFORK()) < 0) {
116f08c3bdfSopenharmony_ci			tst_resm(TFAIL,
117f08c3bdfSopenharmony_ci				 "\tFork failed (may be OK if under stress)");
118f08c3bdfSopenharmony_ci
119f08c3bdfSopenharmony_ci		}
120f08c3bdfSopenharmony_ci		if (pid == 0) {
121f08c3bdfSopenharmony_ci			procstat = 1;
122f08c3bdfSopenharmony_ci			dotest(keyarray[i]);
123f08c3bdfSopenharmony_ci			exit(0);
124f08c3bdfSopenharmony_ci		}
125f08c3bdfSopenharmony_ci		pidarray[i] = pid;
126f08c3bdfSopenharmony_ci		nwait++;
127f08c3bdfSopenharmony_ci	}
128f08c3bdfSopenharmony_ci
129f08c3bdfSopenharmony_ci	/*
130f08c3bdfSopenharmony_ci	 * Wait for children to finish.
131f08c3bdfSopenharmony_ci	 */
132f08c3bdfSopenharmony_ci
133f08c3bdfSopenharmony_ci	count = 0;
134f08c3bdfSopenharmony_ci	while ((child = wait(&status)) > 0) {
135f08c3bdfSopenharmony_ci		if (status) {
136f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "%s[%d] Test failed.  exit=0x%x", prog,
137f08c3bdfSopenharmony_ci				 child, status);
138f08c3bdfSopenharmony_ci			local_flag = FAILED;
139f08c3bdfSopenharmony_ci		}
140f08c3bdfSopenharmony_ci		++count;
141f08c3bdfSopenharmony_ci	}
142f08c3bdfSopenharmony_ci
143f08c3bdfSopenharmony_ci	/*
144f08c3bdfSopenharmony_ci	 * Should have collected all children.
145f08c3bdfSopenharmony_ci	 */
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	if (count != nwait) {
148f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tWrong # children waited on, count = %d",
149f08c3bdfSopenharmony_ci			 count);
150f08c3bdfSopenharmony_ci		local_flag = FAILED;
151f08c3bdfSopenharmony_ci	}
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_ci	if (local_flag != FAILED)
154f08c3bdfSopenharmony_ci		tst_resm(TPASS, "semctl06 ran successfully!");
155f08c3bdfSopenharmony_ci	else
156f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "semctl06 failed");
157f08c3bdfSopenharmony_ci
158f08c3bdfSopenharmony_ci
159f08c3bdfSopenharmony_ci	cleanup();
160f08c3bdfSopenharmony_ci	tst_exit();
161f08c3bdfSopenharmony_ci}
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_cistatic void dotest(key_t key)
164f08c3bdfSopenharmony_ci{
165f08c3bdfSopenharmony_ci	int id, pid, status;
166f08c3bdfSopenharmony_ci	int count, child, nwait;
167f08c3bdfSopenharmony_ci	short i;
168f08c3bdfSopenharmony_ci	union semun get_arr;
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_ci	nwait = 0;
171f08c3bdfSopenharmony_ci	srand(getpid());
172f08c3bdfSopenharmony_ci	if ((id = semget(key, NSEMS, IPC_CREAT | IPC_EXCL)) < 0) {
173f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tsemget() failed errno %d", errno);
174f08c3bdfSopenharmony_ci		exit(1);
175f08c3bdfSopenharmony_ci	}
176f08c3bdfSopenharmony_ci	tid = id;
177f08c3bdfSopenharmony_ci	for (i = 0; i < NSEMS; i++) {
178f08c3bdfSopenharmony_ci		do {
179f08c3bdfSopenharmony_ci			maxsemvals[i] = (short) (rand() % HVAL);
180f08c3bdfSopenharmony_ci		} while (maxsemvals[i] < LVAL);
181f08c3bdfSopenharmony_ci		semops[i].sem_num = i;
182f08c3bdfSopenharmony_ci		semops[i].sem_op = maxsemvals[i];
183f08c3bdfSopenharmony_ci		semops[i].sem_flg = SEM_UNDO;
184f08c3bdfSopenharmony_ci	}
185f08c3bdfSopenharmony_ci	if (semop(id, semops, NSEMS) < 0) {
186f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tfirst semop() failed errno %d", errno);
187f08c3bdfSopenharmony_ci		exit(1);
188f08c3bdfSopenharmony_ci	}
189f08c3bdfSopenharmony_ci
190f08c3bdfSopenharmony_ci	for (i = 0; i < NKIDS; i++) {
191f08c3bdfSopenharmony_ci		if ((pid = FORK_OR_VFORK()) < 0) {
192f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "\tfork failed");
193f08c3bdfSopenharmony_ci		}
194f08c3bdfSopenharmony_ci		if (pid == 0)
195f08c3bdfSopenharmony_ci			dosemas(id);
196f08c3bdfSopenharmony_ci		if (pid > 0) {
197f08c3bdfSopenharmony_ci			kidarray[i] = pid;
198f08c3bdfSopenharmony_ci			nwait++;
199f08c3bdfSopenharmony_ci		}
200f08c3bdfSopenharmony_ci	}
201f08c3bdfSopenharmony_ci
202f08c3bdfSopenharmony_ci	procstat = 2;
203f08c3bdfSopenharmony_ci	/*
204f08c3bdfSopenharmony_ci	 * Wait for children to finish.
205f08c3bdfSopenharmony_ci	 */
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_ci	count = 0;
208f08c3bdfSopenharmony_ci	while ((child = wait(&status)) > 0) {
209f08c3bdfSopenharmony_ci		if (status) {
210f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x",
211f08c3bdfSopenharmony_ci				 prog, child, status);
212f08c3bdfSopenharmony_ci			local_flag = FAILED;
213f08c3bdfSopenharmony_ci		}
214f08c3bdfSopenharmony_ci		++count;
215f08c3bdfSopenharmony_ci	}
216f08c3bdfSopenharmony_ci
217f08c3bdfSopenharmony_ci	/*
218f08c3bdfSopenharmony_ci	 * Should have collected all children.
219f08c3bdfSopenharmony_ci	 */
220f08c3bdfSopenharmony_ci
221f08c3bdfSopenharmony_ci	if (count != nwait) {
222f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tWrong # children waited on, count = %d",
223f08c3bdfSopenharmony_ci			 count);
224f08c3bdfSopenharmony_ci		local_flag = FAILED;
225f08c3bdfSopenharmony_ci	}
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_ci	get_arr.array = semvals;
228f08c3bdfSopenharmony_ci	if (semctl(id, 0, GETALL, get_arr) < 0) {
229f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\terror on GETALL");
230f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tsemctl() failed errno %d", errno);
231f08c3bdfSopenharmony_ci	}
232f08c3bdfSopenharmony_ci
233f08c3bdfSopenharmony_ci	if (DEBUG)
234f08c3bdfSopenharmony_ci		tst_resm(TINFO, "\tchecking maxvals");
235f08c3bdfSopenharmony_ci	for (i = 0; i < NSEMS; i++) {
236f08c3bdfSopenharmony_ci		if (semvals[i] != maxsemvals[i]) {
237f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "\terror on i %d orig %d final %d", i,
238f08c3bdfSopenharmony_ci				 semvals[i], maxsemvals[i]);
239f08c3bdfSopenharmony_ci			local_flag = FAILED;
240f08c3bdfSopenharmony_ci		}
241f08c3bdfSopenharmony_ci	}
242f08c3bdfSopenharmony_ci	if (DEBUG)
243f08c3bdfSopenharmony_ci		tst_resm(TINFO, "\tmaxvals checked");
244f08c3bdfSopenharmony_ci
245f08c3bdfSopenharmony_ci	/* 4th arg must either be missing, or must be of type 'union semun'.
246f08c3bdfSopenharmony_ci	 * CANNOT just be an int, else it crashes on ppc.
247f08c3bdfSopenharmony_ci	 */
248f08c3bdfSopenharmony_ci	get_arr.val = 0;
249f08c3bdfSopenharmony_ci	if (semctl(id, 0, IPC_RMID, get_arr) < 0) {
250f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d", errno);
251f08c3bdfSopenharmony_ci		local_flag = FAILED;
252f08c3bdfSopenharmony_ci	}
253f08c3bdfSopenharmony_ci	if (local_flag == FAILED)
254f08c3bdfSopenharmony_ci		exit(1);
255f08c3bdfSopenharmony_ci}
256f08c3bdfSopenharmony_ci
257f08c3bdfSopenharmony_cistatic void dosemas(int id)
258f08c3bdfSopenharmony_ci{
259f08c3bdfSopenharmony_ci	int i, j;
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_ci	srand(getpid());
262f08c3bdfSopenharmony_ci	for (i = 0; i < NREPS; i++) {
263f08c3bdfSopenharmony_ci		for (j = 0; j < NSEMS; j++) {
264f08c3bdfSopenharmony_ci			semops[j].sem_num = j;
265f08c3bdfSopenharmony_ci			semops[j].sem_flg = SEM_UNDO;
266f08c3bdfSopenharmony_ci
267f08c3bdfSopenharmony_ci			do {
268f08c3bdfSopenharmony_ci				semops[j].sem_op =
269f08c3bdfSopenharmony_ci				    (-(short) (rand() %
270f08c3bdfSopenharmony_ci							(maxsemvals[j] / 2)));
271f08c3bdfSopenharmony_ci			} while (semops[j].sem_op == 0);
272f08c3bdfSopenharmony_ci		}
273f08c3bdfSopenharmony_ci		if (semop(id, semops, NSEMS) < 0) {
274f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "\tsemop1 failed errno %d", errno);
275f08c3bdfSopenharmony_ci			exit(1);
276f08c3bdfSopenharmony_ci		}
277f08c3bdfSopenharmony_ci		for (j = 0; j < NSEMS; j++) {
278f08c3bdfSopenharmony_ci			semops[j].sem_op = (-semops[j].sem_op);
279f08c3bdfSopenharmony_ci		}
280f08c3bdfSopenharmony_ci		if (semop(id, semops, NSEMS) < 0) {
281f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "\tsemop2 failed errno %d", errno);
282f08c3bdfSopenharmony_ci			exit(1);
283f08c3bdfSopenharmony_ci		}
284f08c3bdfSopenharmony_ci	}
285f08c3bdfSopenharmony_ci	exit(0);
286f08c3bdfSopenharmony_ci}
287f08c3bdfSopenharmony_ci
288f08c3bdfSopenharmony_cistatic void term(int sig)
289f08c3bdfSopenharmony_ci{
290f08c3bdfSopenharmony_ci	int i;
291f08c3bdfSopenharmony_ci
292f08c3bdfSopenharmony_ci	if ((signal(SIGTERM, term)) == SIG_ERR) {
293f08c3bdfSopenharmony_ci		tst_resm(TFAIL, "\tsignal failed. errno %d", errno);
294f08c3bdfSopenharmony_ci		exit(1);
295f08c3bdfSopenharmony_ci	}
296f08c3bdfSopenharmony_ci	if (procstat == 0) {
297f08c3bdfSopenharmony_ci		if (DEBUG)
298f08c3bdfSopenharmony_ci			tst_resm(TINFO, "\ttest killing kids");
299f08c3bdfSopenharmony_ci		for (i = 0; i < NPROCS; i++) {
300f08c3bdfSopenharmony_ci			if (kill(pidarray[i], SIGTERM) != 0) {
301f08c3bdfSopenharmony_ci				tst_resm(TFAIL, "Kill error pid = %d :",
302f08c3bdfSopenharmony_ci					 pidarray[1]);
303f08c3bdfSopenharmony_ci			}
304f08c3bdfSopenharmony_ci		}
305f08c3bdfSopenharmony_ci		if (DEBUG)
306f08c3bdfSopenharmony_ci			tst_resm(TINFO, "\ttest kids killed");
307f08c3bdfSopenharmony_ci		return;
308f08c3bdfSopenharmony_ci	}
309f08c3bdfSopenharmony_ci
310f08c3bdfSopenharmony_ci	if (procstat == 1) {
311f08c3bdfSopenharmony_ci		/* 4th arg must either be missing, or must be of type 'union semun'.
312f08c3bdfSopenharmony_ci		 * CANNOT just be an int, else it crashes on ppc.
313f08c3bdfSopenharmony_ci		 */
314f08c3bdfSopenharmony_ci		union semun arg;
315f08c3bdfSopenharmony_ci		arg.val = 0;
316f08c3bdfSopenharmony_ci		(void)semctl(tid, 0, IPC_RMID, arg);
317f08c3bdfSopenharmony_ci		exit(1);
318f08c3bdfSopenharmony_ci	}
319f08c3bdfSopenharmony_ci
320f08c3bdfSopenharmony_ci	if (tid == -1) {
321f08c3bdfSopenharmony_ci		exit(1);
322f08c3bdfSopenharmony_ci	}
323f08c3bdfSopenharmony_ci	for (i = 0; i < NKIDS; i++) {
324f08c3bdfSopenharmony_ci		if (kill(kidarray[i], SIGTERM) != 0) {
325f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "Kill error kid id = %d :",
326f08c3bdfSopenharmony_ci				 kidarray[1]);
327f08c3bdfSopenharmony_ci		}
328f08c3bdfSopenharmony_ci	}
329f08c3bdfSopenharmony_ci}
330f08c3bdfSopenharmony_ci
331f08c3bdfSopenharmony_civoid setup(void)
332f08c3bdfSopenharmony_ci{
333f08c3bdfSopenharmony_ci	tst_sig(FORK, DEF_HANDLER, cleanup);
334f08c3bdfSopenharmony_ci
335f08c3bdfSopenharmony_ci	TEST_PAUSE;
336f08c3bdfSopenharmony_ci
337f08c3bdfSopenharmony_ci	tst_tmpdir();
338f08c3bdfSopenharmony_ci}
339f08c3bdfSopenharmony_ci
340f08c3bdfSopenharmony_civoid cleanup(void)
341f08c3bdfSopenharmony_ci{
342f08c3bdfSopenharmony_ci	tst_rmdir();
343f08c3bdfSopenharmony_ci}
344