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