xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/ipc/semctl/semctl06.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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	[email protected]
39  *      10/30/2002	Port to LTP	[email protected]
40  *      12/03/2008 Matthieu Fertré ([email protected])
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 #include <sys/types.h>
48 #include <sys/ipc.h>
49 #include <sys/sem.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <stdlib.h>
53 #include <signal.h>
54 #include "test.h"
55 #include <sys/wait.h>
56 #include "ipcsem.h"
57 
58 int local_flag = 1;
59 
60 #define NREPS	500
61 #define NPROCS	3
62 #define NKIDS	5
63 #define NSEMS	5
64 #define HVAL	1000
65 #define LVAL	100
66 #define FAILED	0
67 
68 void setup();
69 void cleanup();
70 
71 static key_t keyarray[NPROCS];
72 static struct sembuf semops[NSEMS];
73 static short maxsemvals[NSEMS];
74 static int pidarray[NPROCS];
75 static int kidarray[NKIDS];
76 static int tid;
77 static int procstat;
78 static char *prog;
79 static unsigned short semvals[NSEMS];
80 
81 char *TCID = "semctl06";
82 int TST_TOTAL = 1;
83 
84 static void term(int sig);
85 static void dosemas(int id);
86 static void dotest(key_t key);
87 
main(int argc,char ** argv)88 int main(int argc, char **argv)
89 {
90 	register int i, pid;
91 	int count, child, status, nwait;
92 
93 	tst_parse_opts(argc, argv, NULL, NULL);
94 
95 	prog = argv[0];
96 	nwait = 0;
97 	setup();
98 
99 	tid = -1;
100 
101 	for (i = 0; i < NPROCS; i++)
102 		keyarray[i] = getipckey();
103 
104 	if ((signal(SIGTERM, term)) == SIG_ERR) {
105 		tst_resm(TFAIL, "\tsignal failed. errno = %d", errno);
106 
107 	}
108 
109 	for (i = 0; i < NPROCS; i++) {
110 		if ((pid = tst_fork()) < 0) {
111 			tst_resm(TFAIL,
112 				 "\tFork failed (may be OK if under stress)");
113 
114 		}
115 		if (pid == 0) {
116 			procstat = 1;
117 			dotest(keyarray[i]);
118 			exit(0);
119 		}
120 		pidarray[i] = pid;
121 		nwait++;
122 	}
123 
124 	/*
125 	 * Wait for children to finish.
126 	 */
127 
128 	count = 0;
129 	while ((child = wait(&status)) > 0) {
130 		if (status) {
131 			tst_resm(TFAIL, "%s[%d] Test failed.  exit=0x%x", prog,
132 				 child, status);
133 			local_flag = FAILED;
134 		}
135 		++count;
136 	}
137 
138 	/*
139 	 * Should have collected all children.
140 	 */
141 
142 	if (count != nwait) {
143 		tst_resm(TFAIL, "\tWrong # children waited on, count = %d",
144 			 count);
145 		local_flag = FAILED;
146 	}
147 
148 	if (local_flag != FAILED)
149 		tst_resm(TPASS, "semctl06 ran successfully!");
150 	else
151 		tst_resm(TFAIL, "semctl06 failed");
152 
153 
154 	cleanup();
155 	tst_exit();
156 }
157 
dotest(key_t key)158 static void dotest(key_t key)
159 {
160 	int id, pid, status;
161 	int count, child, nwait;
162 	short i;
163 	union semun get_arr;
164 
165 	nwait = 0;
166 	srand(getpid());
167 	if ((id = semget(key, NSEMS, IPC_CREAT | IPC_EXCL)) < 0) {
168 		tst_resm(TFAIL, "\tsemget() failed errno %d", errno);
169 		exit(1);
170 	}
171 	tid = id;
172 	for (i = 0; i < NSEMS; i++) {
173 		do {
174 			maxsemvals[i] = (short) (rand() % HVAL);
175 		} while (maxsemvals[i] < LVAL);
176 		semops[i].sem_num = i;
177 		semops[i].sem_op = maxsemvals[i];
178 		semops[i].sem_flg = SEM_UNDO;
179 	}
180 	if (semop(id, semops, NSEMS) < 0) {
181 		tst_resm(TFAIL, "\tfirst semop() failed errno %d", errno);
182 		exit(1);
183 	}
184 
185 	for (i = 0; i < NKIDS; i++) {
186 		if ((pid = tst_fork()) < 0) {
187 			tst_resm(TFAIL, "\tfork failed");
188 		}
189 		if (pid == 0)
190 			dosemas(id);
191 		if (pid > 0) {
192 			kidarray[i] = pid;
193 			nwait++;
194 		}
195 	}
196 
197 	procstat = 2;
198 	/*
199 	 * Wait for children to finish.
200 	 */
201 
202 	count = 0;
203 	while ((child = wait(&status)) > 0) {
204 		if (status) {
205 			tst_resm(TFAIL, "\t%s:dotest[%d] exited status = 0x%x",
206 				 prog, child, status);
207 			local_flag = FAILED;
208 		}
209 		++count;
210 	}
211 
212 	/*
213 	 * Should have collected all children.
214 	 */
215 
216 	if (count != nwait) {
217 		tst_resm(TFAIL, "\tWrong # children waited on, count = %d",
218 			 count);
219 		local_flag = FAILED;
220 	}
221 
222 	get_arr.array = semvals;
223 	if (semctl(id, 0, GETALL, get_arr) < 0) {
224 		tst_resm(TFAIL, "\terror on GETALL");
225 		tst_resm(TFAIL, "\tsemctl() failed errno %d", errno);
226 	}
227 
228 	if (DEBUG)
229 		tst_resm(TINFO, "\tchecking maxvals");
230 	for (i = 0; i < NSEMS; i++) {
231 		if (semvals[i] != maxsemvals[i]) {
232 			tst_resm(TFAIL, "\terror on i %d orig %d final %d", i,
233 				 semvals[i], maxsemvals[i]);
234 			local_flag = FAILED;
235 		}
236 	}
237 	if (DEBUG)
238 		tst_resm(TINFO, "\tmaxvals checked");
239 
240 	/* 4th arg must either be missing, or must be of type 'union semun'.
241 	 * CANNOT just be an int, else it crashes on ppc.
242 	 */
243 	get_arr.val = 0;
244 	if (semctl(id, 0, IPC_RMID, get_arr) < 0) {
245 		tst_resm(TFAIL, "\tsemctl(IPC_RMID) failed errno %d", errno);
246 		local_flag = FAILED;
247 	}
248 	if (local_flag == FAILED)
249 		exit(1);
250 }
251 
dosemas(int id)252 static void dosemas(int id)
253 {
254 	int i, j;
255 
256 	srand(getpid());
257 	for (i = 0; i < NREPS; i++) {
258 		for (j = 0; j < NSEMS; j++) {
259 			semops[j].sem_num = j;
260 			semops[j].sem_flg = SEM_UNDO;
261 
262 			do {
263 				semops[j].sem_op =
264 				    (-(short) (rand() %
265 							(maxsemvals[j] / 2)));
266 			} while (semops[j].sem_op == 0);
267 		}
268 		if (semop(id, semops, NSEMS) < 0) {
269 			tst_resm(TFAIL, "\tsemop1 failed errno %d", errno);
270 			exit(1);
271 		}
272 		for (j = 0; j < NSEMS; j++) {
273 			semops[j].sem_op = (-semops[j].sem_op);
274 		}
275 		if (semop(id, semops, NSEMS) < 0) {
276 			tst_resm(TFAIL, "\tsemop2 failed errno %d", errno);
277 			exit(1);
278 		}
279 	}
280 	exit(0);
281 }
282 
term(int sig)283 static void term(int sig)
284 {
285 	int i;
286 
287 	if ((signal(SIGTERM, term)) == SIG_ERR) {
288 		tst_resm(TFAIL, "\tsignal failed. errno %d", errno);
289 		exit(1);
290 	}
291 	if (procstat == 0) {
292 		if (DEBUG)
293 			tst_resm(TINFO, "\ttest killing kids");
294 		for (i = 0; i < NPROCS; i++) {
295 			if (kill(pidarray[i], SIGTERM) != 0) {
296 				tst_resm(TFAIL, "Kill error pid = %d :",
297 					 pidarray[1]);
298 			}
299 		}
300 		if (DEBUG)
301 			tst_resm(TINFO, "\ttest kids killed");
302 		return;
303 	}
304 
305 	if (procstat == 1) {
306 		/* 4th arg must either be missing, or must be of type 'union semun'.
307 		 * CANNOT just be an int, else it crashes on ppc.
308 		 */
309 		union semun arg;
310 		arg.val = 0;
311 		(void)semctl(tid, 0, IPC_RMID, arg);
312 		exit(1);
313 	}
314 
315 	if (tid == -1) {
316 		exit(1);
317 	}
318 	for (i = 0; i < NKIDS; i++) {
319 		if (kill(kidarray[i], SIGTERM) != 0) {
320 			tst_resm(TFAIL, "Kill error kid id = %d :",
321 				 kidarray[1]);
322 		}
323 	}
324 }
325 
setup(void)326 void setup(void)
327 {
328 	tst_sig(FORK, DEF_HANDLER, cleanup);
329 
330 	TEST_PAUSE;
331 
332 	tst_tmpdir();
333 }
334 
cleanup(void)335 void cleanup(void)
336 {
337 	tst_rmdir();
338 }
339