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