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