1 /*
2 * Copyright (C) Bull S.A. 1996
3 * Copyright (c) International Business Machines Corp., 2001
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 | semaphore_test_03 |
21 | ==================================================================== |
22 | |
23 | Description: Verify semop () command options |
24 | |
25 | Algorithm: o Spawn N child processes |
26 | |
27 | o Obtain N semaphores with semget (IPC_PRIVATE) |
28 | |
29 | o Call semop () with variations of the following |
30 | parameters: |
31 | |
32 | sem_op: negative, 0, positive |
33 | sem_flg: IPC_NOWAIT, SEM_UNDO |
34 | |
35 | System calls: The following system calls are made |
36 | |
37 | semget () - Gets a set of semaphores |
38 | semctl () - Controls semaphore operations |
39 | semop () - Performs semaphore operations |
40 | |
41 | Usage: semaphore_test_03 [-p nprocs] [-s nsems] |
42 | |
43 | where: nprocs - number of child processes to spawn |
44 | nsems - number of semaphores (per process) |
45 | |
46 | To compile: cc -o semaphore_test_03 semaphore_test_03.c |
47 | |
48 | Last update: Ver. 1.6, 7/21/94 13:37:28 |
49 | |
50 | Change Activity |
51 | |
52 | Version Date Name Reason |
53 | 0.1 050689 CTU Initial version |
54 | 0.2 111993 DJK Modify for AIX version 4.1 |
55 | 1.2 021494 DJK Moved to "prod" directory |
56 | 1.3 Jan-28-02 Manoj Iyer, IBM Austin, TX.manjo@austin.ibm.com|
57 | Modified - Ported to work on PPC64. |
58 | |
59 +---------------------------------------------------------------------*/
60
61 #include <errno.h>
62 #include <stdio.h>
63 #include <sys/ipc.h>
64 #include <sys/param.h>
65 #include <sys/sem.h>
66 #include <sys/shm.h>
67 #include <sys/stat.h>
68 #include <sys/signal.h>
69 #include <sys/types.h>
70 #include <sys/wait.h>
71 #include <stdlib.h>
72 #include <unistd.h>
73 #include <string.h>
74 #include "lapi/semun.h"
75
76 /*
77 * Defines
78 *
79 * MAX_SEMAPHORES: maximum number of semaphores per id (limited by
80 * maximum number of semaphore operations per call by semop () function).
81 *
82 * MAX_CHILDREN: maximum number of child processes to spawn
83 *
84 * DEFAULT_NUM_SEMAPHORES: default number of semaphores to create unless
85 * specified with (-s nsems) command line option
86 *
87 * DEFAULT_NUM_CHILDREN: default number of child processes to spawn unless
88 * specified with (-p nprocs) command line option
89 *
90 * USAGE: usage statement macro
91 *
92 * SEMOP_TABLE: macro for printing attempted semop command combinations
93 */
94 #define MAX_SEMAPHORES 32
95 #define MAX_CHILDREN 200
96 #define DEFAULT_NUM_SEMAPHORES 16
97 #define DEFAULT_NUM_CHILDREN 0
98
99 #define USAGE "\nUsage: %s [-s nsems] [-p nproc]\n\n" \
100 "\t-s nsems number of semaphores (per process)\n\n" \
101 "\t-p nproc number of child processes to spawn\n\n"
102 #define SEMOP_TABLE(p1,p2,p3,p4) \
103 if (proc_pid == parent_pid) \
104 printf ("\t %3d %3d %-10s %-20s\n", p1, p2, p3, p4)
105
106 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
107
108 /*
109 * Function prototypes
110 *
111 * setup_signal_handler (): Sets up signal handler for SIGUSR1
112 * test_commands (): Tests semget () and semctl () commands
113 * handler (): Signal handler
114 * sys_error (): System error message function
115 * error (): Error message function
116 * parse_args (): Parse command line arguments
117 * catch: Signal catching function for SIGUSR1 signal
118 */
119 static void setup_signal_handler();
120 static void test_commands();
121 static void sys_error(const char *, int);
122 static void error(const char *, int);
123 static void parse_args(int, char **);
124 static void catch(int);
125
126 /*
127 * Structures and Global variables:
128 *
129 * nsems: number of semaphores to create (per process)
130 * nprocs: number of child processes to spawn
131 * childpid: array containing process id's of the child processes
132 * parent_pid: process id of parent process
133 */
134 int nsems = DEFAULT_NUM_SEMAPHORES;
135 int nprocs = DEFAULT_NUM_CHILDREN;
136 pid_t childpid[MAX_CHILDREN];
137 pid_t parent_pid;
138 pid_t errpid;
139
140 union semun arg;
141
142 /*---------------------------------------------------------------------+
143 | main |
144 | ==================================================================== |
145 | |
146 | Function: Main program (see prolog for more details) |
147 | |
148 | Returns: (0) Successful completion |
149 | (-1) Error occurred |
150 | |
151 +---------------------------------------------------------------------*/
main(int argc,char ** argv)152 int main(int argc, char **argv)
153 {
154 pid_t pid; /* Child's process id */
155 int proc; /* Fork loop index */
156 int status; /* Child's exit status */
157
158 /*
159 * Parse command line arguments, print out program header, setup
160 * signal handler (for SIGUSR1) and save parent process id.
161 */
162 parse_args(argc, argv);
163 printf("%s: IPC Semaphore TestSuite program\n", *argv);
164 fflush(stdout);
165 setup_signal_handler();
166 errpid = parent_pid = getpid();
167
168 if (nsems < 8)
169 nsems = 8;
170
171 /*
172 * Fork off the additional processes.
173 */
174 if (nprocs > 0) {
175 printf("\n\tParent: spawning %d child processes\n", nprocs);
176 fflush(stdout);
177 }
178 for (proc = 1; proc < nprocs; proc++) {
179 /*
180 * Child leaves loop, parent continues to fork.
181 */
182 if ((pid = fork()) < 0)
183 sys_error("fork failed", __LINE__);
184 else if (pid == (pid_t) 0) {
185 errpid = pid;
186 break;
187 } else
188 childpid[proc] = pid;
189 }
190 pid = getpid();
191
192 /*
193 * Test the semget () and semctl () commands
194 */
195 test_commands(pid);
196
197 /*
198 * Finished testing commands, only parent process needs to continue
199 */
200 if (pid != parent_pid)
201 exit(0);
202
203 /*
204 * Wait for all of the child processes to complete & check their
205 * exit status.
206 *
207 * Upon completion of the child proccesses, exit program with success.
208 */
209 for (proc = 1; proc < nprocs; proc++) {
210 waitpid(childpid[proc], &status, 0);
211
212 if (WEXITSTATUS(status))
213 sys_error("child process terminated abnormally",
214 __LINE__);
215 }
216 if (nprocs > 0)
217 printf
218 ("\n\tAll child processes verified commands successfully\n");
219 printf("\nsuccessful!\n");
220 return (0);
221 }
222
223 /*---------------------------------------------------------------------+
224 | test_commands () |
225 | ==================================================================== |
226 | |
227 | Function: Verifies options for semop () system function call. |
228 | |
229 +---------------------------------------------------------------------*/
test_commands(pid_t proc_pid)230 static void test_commands(pid_t proc_pid)
231 {
232 int i; /* Misc loop index */
233 int val; /* Value (semctl parameter) */
234 int semid; /* Unique semaphore id */
235 int status; /* Child's exit status */
236 int expected_value; /* Expected semaphore value */
237 pid_t pid; /* Misc process id */
238 gid_t gid = getgid(); /* Misc group id */
239 uid_t uid = getuid(); /* Misc user id */
240 mode_t mode = 0666; /* Misc mode bits */
241 // ushort array [MAX_SEMAPHORES]; /* Misc array of semaphore values */
242 struct sembuf semoparray[MAX_SEMAPHORES];
243
244 /*
245 * Create the semaphores...
246 */
247 if (proc_pid == parent_pid)
248 printf("\n\tCreating %d semaphores ...\n", nsems);
249 if ((semid = semget(IPC_PRIVATE, nsems, IPC_CREAT | mode)) < 0)
250 sys_error("semget (IPC_PRIVATE) failed", __LINE__);
251
252 /*
253 * Set the semaphore uid, gid and mode
254 */
255 if (proc_pid == parent_pid)
256 printf
257 ("\n\tSetting semaphore uid, gid and mode ... semid = %d\n",
258 semid);
259 arg.buf = (struct semid_ds *)calloc(1, sizeof(struct semid_ds));
260 if (!arg.buf)
261 error("calloc failed", __LINE__);
262 arg.buf->sem_perm.uid = uid;
263 arg.buf->sem_perm.gid = gid;
264 arg.buf->sem_perm.mode = mode;
265 if (semctl(semid, 0, IPC_SET, arg) < 0)
266 sys_error("semctl failed", __LINE__);
267
268 /*
269 * Verify that semaphore uid, gid and mode were set correctly
270 */
271 if (proc_pid == parent_pid)
272 printf("\n\tVerifying semaphore info ...\n");
273 if (semctl(semid, 0, IPC_STAT, arg) < 0)
274 sys_error("semctl (IPC_STAT) failed", __LINE__);
275 if (arg.buf->sem_perm.uid != uid)
276 error("semctl: uid was not set", __LINE__);
277 if (arg.buf->sem_perm.gid != gid)
278 error("semctl: gid was not set", __LINE__);
279 if ((arg.buf->sem_perm.mode & 0777) != mode)
280 error("semctl: mode was not set", __LINE__);
281 if (arg.buf->sem_nsems != nsems)
282 error("semctl: nsems (number of semaphores) was not set",
283 __LINE__);
284 SAFE_FREE(arg.buf);
285
286 /*
287 * Set the value of each semaphore in the set to 2.
288 */
289 arg.array = malloc(sizeof(int) * nsems);
290 if (!arg.array)
291 error("malloc failed", __LINE__);
292 for (i = 0; i < nsems; i++)
293 arg.array[i] = 2;
294 if (semctl(semid, 0, SETALL, arg) < 0)
295 sys_error("semctl (SETALL) failed", __LINE__);
296 SAFE_FREE(arg.array);
297
298 /* ------------------------------------------------------------------ */
299 /* possibilities for sem_flg are: */
300 /* 0 */
301 /* SEM_UN */
302 /* IPC_NOWAIT */
303 /* Return Immediately */
304 /* ------------------------------------------------------------------ */
305 if (proc_pid == parent_pid) {
306 printf
307 ("\n\tTesting semop() with all Semaphore values, options and flags\n");
308 printf("\n\t Semval Semop Semflag Description\n");
309 }
310
311 /* ------------------------------------------------------------------ */
312 /* TEST # 1 --- semval = 2, sem_op = -1, sem_flg = 0 */
313 /* --- semval > |sem_op| THEN (semval - |sem_op|) = 1 */
314 /* THE FOLLOWING SHOULD SHOW semval = 1. */
315 /* ------------------------------------------------------------------ */
316 SEMOP_TABLE(2, -1, "0", "Obtain resource");
317 for (i = 0; i < nsems; i++) {
318 semoparray[i].sem_num = i;
319 semoparray[i].sem_op = -1;
320 semoparray[i].sem_flg = 0;
321 }
322 if (semop(semid, semoparray, nsems) < 0)
323 sys_error("semop failed", __LINE__);
324
325 expected_value = 1;
326 for (i = 0; i < nsems; i++) {
327 arg.val = 0;
328 if ((val = semctl(semid, i, GETVAL, arg)) < 0)
329 sys_error("semctl (GETVAL) failed", __LINE__);
330 if (val != expected_value)
331 error("incorrect semaphore value", __LINE__);
332 }
333
334 /* ------------------------------------------------------------------ */
335 /* TEST # 2 --- semval = 1, sem_op = -1, sem_flg = 0 */
336 /* --- semval = |sem_op| THEN (semval - |sem_op|) = 0 */
337 /* THE FOLLOWING SHOULD SHOW semval = 0 */
338 /* ------------------------------------------------------------------ */
339 SEMOP_TABLE(1, -1, "0", "Obtain resource");
340 for (i = 0; i < nsems; i++) {
341 semoparray[i].sem_num = i;
342 semoparray[i].sem_op = -1;
343 semoparray[i].sem_flg = 0;
344 }
345 if (semop(semid, semoparray, nsems) < 0)
346 sys_error("semop failed", __LINE__);
347
348 expected_value = 0;
349 for (i = 0; i < nsems; i++) {
350 arg.val = 0;
351 if ((val = semctl(semid, i, GETVAL, arg)) < 0)
352 sys_error("semctl (GETVAL) failed", __LINE__);
353 if (val != expected_value)
354 error("incorrect semaphore value", __LINE__);
355 }
356
357 /* ------------------------------------------------------------------ */
358 /* TEST # 3 --- semval = 0, sem_op = 0, sem_flg = 0 */
359 /* --- semop = 0 AND semval = 0 returns immediately. */
360 /* THE FOLLOWING SHOULD SHOW semval = 0 */
361 /* ------------------------------------------------------------------ */
362 SEMOP_TABLE(0, 0, "0", "Semop function returns immediately");
363 for (i = 0; i < nsems; i++) {
364 semoparray[i].sem_num = i;
365 semoparray[i].sem_op = 0;
366 semoparray[i].sem_flg = 0;
367 }
368 if (semop(semid, semoparray, nsems) < 0)
369 sys_error("semop failed", __LINE__);
370
371 expected_value = 0;
372 for (i = 0; i < nsems; i++) {
373 arg.val = 0;
374 if ((val = semctl(semid, i, GETVAL, arg)) < 0)
375 sys_error("semctl (GETVAL) failed", __LINE__);
376 if (val != expected_value)
377 error("incorrect semaphore value", __LINE__);
378 }
379
380 /* ------------------------------------------------------------------ */
381 /* TEST # 4 --- semval = 5, sem_op = 1, sem_flg = 0 */
382 /* --- semop > 0 THEN (semval + sem_op) = 6 */
383 /* THE FOLLOWING SHOULD SHOW semval = 6 */
384 /* ------------------------------------------------------------------ */
385 SEMOP_TABLE(5, 1, "0", "Return resource");
386 arg.array = malloc(sizeof(int) * nsems);
387 if (!arg.array)
388 error("malloc failed", __LINE__);
389 for (i = 0; i < nsems; i++) {
390 arg.array[i] = 5;
391 }
392 if (semctl(semid, 0, SETALL, arg) < 0)
393 sys_error("semctl (SETALL) failed", __LINE__);
394 SAFE_FREE(arg.array);
395
396 for (i = 0; i < nsems; i++) {
397 semoparray[i].sem_num = i;
398 semoparray[i].sem_op = 1;
399 semoparray[i].sem_flg = 0;
400 }
401 if (semop(semid, semoparray, nsems) < 0)
402 sys_error("semop failed", __LINE__);
403
404 expected_value = 6;
405 for (i = 0; i < nsems; i++) {
406 arg.val = 0;
407 if ((val = semctl(semid, i, GETVAL, arg)) < 0)
408 sys_error("semctl (GETVAL) failed", __LINE__);
409 if (val != expected_value)
410 error("incorrect semaphore value", __LINE__);
411 }
412
413 /* ------------------------------------------------------------------ */
414 /* TEST # 5 --- semval = 6, sem_op = -7, sem_flg = IPC_NOWAIT */
415 /* --- semval < |sem_op| && IPC_NOWAIT, THEN return immed. */
416 /* THE FOLLOWING SHOULD SHOW semval = 6. */
417 /* ------------------------------------------------------------------ */
418 SEMOP_TABLE(6, -7, "IPC_NOWAIT", "Semop function returns immediately");
419 for (i = 0; i < nsems; i++) {
420 semoparray[i].sem_num = i;
421 semoparray[i].sem_op = -7;
422 semoparray[i].sem_flg = IPC_NOWAIT;
423 }
424 if (semop(semid, semoparray, nsems) >= 0)
425 error("semop did not return EAGAIN", __LINE__);
426 else if (errno != EAGAIN)
427 sys_error("semop failed", __LINE__);
428
429 expected_value = 6;
430 for (i = 0; i < nsems; i++) {
431 arg.val = 0;
432 if ((val = semctl(semid, i, GETVAL, arg)) < 0)
433 sys_error("semctl (GETVAL) failed", __LINE__);
434 if (val != expected_value)
435 error("incorrect semaphore value", __LINE__);
436 }
437
438 /* ------------------------------------------------------------------ */
439 /* TEST # 6 --- semval = 6, sem_op = 0, sem_flg = IPC_NOWAIT */
440 /* --- semop = 0 AND semval != 0 AND IPC_NOWAIT, */
441 /* --- THEN return immediately. */
442 /* THE FOLLOWING SHOULD SHOW semval = 6. */
443 /* ------------------------------------------------------------------ */
444 SEMOP_TABLE(6, 0, "IPC_NOWAIT", "Semop function returns immediately");
445 for (i = 0; i < nsems; i++) {
446 semoparray[i].sem_num = i;
447 semoparray[i].sem_op = 0;
448 semoparray[i].sem_flg = IPC_NOWAIT;
449 }
450 if (semop(semid, semoparray, nsems) >= 0)
451 error("semop did not return EAGAIN", __LINE__);
452 else if (errno != EAGAIN)
453 sys_error("semop failed", __LINE__);
454
455 expected_value = 6;
456 for (i = 0; i < nsems; i++) {
457 arg.val = 0;
458 if ((val = semctl(semid, i, GETVAL, arg)) < 0)
459 sys_error("semctl (GETVAL) failed", __LINE__);
460 if (val != expected_value)
461 error("incorrect semaphore value", __LINE__);
462 }
463
464 /* ------------------------------------------------------------------ */
465 /* TEST # 7 --- semval = 6, sem_op = 1, sem_flg = 0 */
466 /* --- semop > 0 THEN (semval + sem_op) = 7 */
467 /* THE FOLLOWING SHOULD SHOW semval = 7. */
468 /* ------------------------------------------------------------------ */
469 SEMOP_TABLE(6, 1, "0", "Return resource");
470 for (i = 0; i < nsems; i++) {
471 semoparray[i].sem_num = i;
472 semoparray[i].sem_op = 1;
473 semoparray[i].sem_flg = 0;
474 }
475 if (semop(semid, semoparray, nsems) < 0)
476 sys_error("semop failed", __LINE__);
477
478 expected_value = 7;
479 for (i = 0; i < nsems; i++) {
480 arg.val = 0;
481 if ((val = semctl(semid, i, GETVAL, arg)) < 0)
482 sys_error("semctl (GETVAL) failed", __LINE__);
483 if (val != expected_value)
484 error("incorrect semaphore value", __LINE__);
485 }
486
487 /* ------------------------------------------------------------------ */
488 /* TEST # 8 --- semval = 7, sem_op[0] = -8, sem_flg = 0 */
489 /* --- semval < |semop| && ! IPC_NOWAIT, caller sleeps */
490 /* call #1 --- semval = 7, sem_op[0] = 2, sem_flg = 0 */
491 /* --- semop > 0 THEN (semval + sem_op) = 9 */
492 /* --- "child" is awaken via call #1. */
493 /* THE FOLLOWING SHOULD SHOW semval = 1 */
494 /* ------------------------------------------------------------------ */
495 SEMOP_TABLE(7, -8, "0", "Sleep (until resource becomes available)");
496 /*
497 * Child process
498 */
499 if ((pid = fork()) == (pid_t) 0) {
500 semoparray[0].sem_num = 0;
501 semoparray[0].sem_op = -8;
502 semoparray[0].sem_flg = 0;
503 if (semop(semid, semoparray, 1) < 0)
504 sys_error("semop failed", __LINE__);
505 exit(0);
506 } else if (pid < 0) {
507 sys_error("fork failed", __LINE__);
508 }
509 semoparray[0].sem_num = 0;
510 semoparray[0].sem_op = 2;
511 semoparray[0].sem_flg = 0;
512
513 /*
514 * Wait for child process's semaphore request before proceeding...
515 */
516 while (!semctl(semid, 0, GETNCNT, arg))
517 sleep(1);
518
519 if (semop(semid, semoparray, 1) < 0)
520 sys_error("semop failed", __LINE__);
521
522 waitpid(pid, &status, 0); /* Wait for child to complete */
523 if (WEXITSTATUS(status))
524 sys_error("child process terminated abnormally", __LINE__);
525
526 expected_value = 1;
527 arg.val = 0;
528 if ((val = semctl(semid, 0, GETVAL, arg)) < 0)
529 sys_error("semctl (GETVAL) failed", __LINE__);
530 if (val != expected_value)
531 error("incorrect semaphore value", __LINE__);
532
533 /* ------------------------------------------------------------------ */
534 /* TEST # 9 --- semval = 7, sem_op[0] = -8, sem_flg = 0 */
535 /* --- semval < |semop| && ! IPC_NOWAIT, caller sleeps */
536 /* --- "child" is awaken via a signal. AFTER AWAKENING, */
537 /* --- semval > |sem_op| THEN (semval - |sem_op|) = 1 */
538 /* THE FOLLOWING SHOULD SHOW semval = 7 */
539 /* ------------------------------------------------------------------ */
540 SEMOP_TABLE(7, -8, "0", "Sleep (until signaled)");
541 /*
542 * Child process
543 */
544 if ((pid = fork()) == (pid_t) 0) {
545 semoparray[0].sem_num = 1;
546 semoparray[0].sem_op = -8;
547 semoparray[0].sem_flg = 0;
548
549 if (semop(semid, semoparray, 1) >= 0)
550 error("semop did not return EINTR", __LINE__);
551 else if (errno != EINTR) {
552 printf("semop returned: %d\n", errno);
553 sys_error("semop failed", __LINE__);
554 }
555 exit(0);
556 } else if (pid < (pid_t) 0) {
557 sys_error("fork failed", __LINE__);
558 }
559
560 /*
561 * Wait for child process's semaphore request before proceeding...
562 */
563 while (!semctl(semid, 1, GETNCNT, arg))
564 sleep(1);
565
566 kill(pid, SIGUSR1);
567
568 waitpid(pid, &status, 0); /* Wait for child to complete */
569 if (WEXITSTATUS(status))
570 sys_error("child process terminated abnormally", __LINE__);
571
572 expected_value = 7;
573 arg.val = 0;
574 if ((val = semctl(semid, 1, GETVAL, arg)) < 0)
575 sys_error("semctl (GETVAL) failed", __LINE__);
576 if (val != expected_value)
577 error("incorrect semaphore value", __LINE__);
578
579 /* ------------------------------------------------------------------ */
580 /* TEST # 10 --- semval = 1, sem_op[3] = -3, sem_flg = 0 */
581 /* --- semval < |semop| && ! IPC_NOWAIT, caller sleeps */
582 /* call #1 --- semval = 1, sem_op[3] = 5, sem_flg = 0 */
583 /* --- sem_op > 0 THEN (semval + sem_op) = 6 */
584 /* call #2 --- semval = 6, sem_op[3] = 5, sem_flg = SEM_UN */
585 /* --- sem_op > 0 && SEM_UN, THEN */
586 /* --- THEN (semval + sem_op) = 11 */
587 /* --- "child" is awaken via call #2. */
588 /* --- semval < |semop (-3)| THEN semval = 8 */
589 /* THE FOLLOWING SHOULD SHOW semval = 8 */
590 /* ------------------------------------------------------------------ */
591 SEMOP_TABLE(1, 5, "SEM_UNDO",
592 "Sleep (until resource becomes available)");
593 /*
594 * Child process
595 */
596 if ((pid = fork()) == (pid_t) 0) {
597 semoparray[0].sem_num = 0;
598 semoparray[0].sem_op = -3;
599 semoparray[0].sem_flg = 0;
600
601 if (semop(semid, semoparray, 1) < 0)
602 sys_error("semop failed", __LINE__);
603 exit(0);
604 } else if (pid < (pid_t) 0) {
605 sys_error("fork failed", __LINE__);
606 }
607
608 /*
609 * Wait for child process's semaphore request before proceeding...
610 */
611 while (!semctl(semid, 0, GETNCNT, arg))
612 sleep(1);
613
614 semoparray[0].sem_num = 0;
615 semoparray[0].sem_op = 5;
616 semoparray[0].sem_flg = 0;
617 if (semop(semid, semoparray, 1) < 0)
618 sys_error("semop failed", __LINE__);
619
620 semoparray[0].sem_num = 0;
621 semoparray[0].sem_op = 5;
622 semoparray[0].sem_flg = SEM_UNDO;
623 if (semop(semid, semoparray, 1) < 0)
624 sys_error("semop failed", __LINE__);
625
626 waitpid(pid, &status, 0); /* Wait for child to complete */
627 if (WEXITSTATUS(status))
628 sys_error("child process terminated abnormally", __LINE__);
629
630 expected_value = 8;
631 arg.val = 0;
632 if ((val = semctl(semid, 0, GETVAL, arg)) < 0)
633 sys_error("semctl (GETVAL) failed", __LINE__);
634 if (val != expected_value)
635 error("incorrect semaphore value", __LINE__);
636
637 /* ------------------------------------------------------------------ */
638 /* TEST # 11 --- semval = 7, sem_op[3] = -8, sem_flg = 0 */
639 /* --- semval < |semop| && ! IPC_NOWAIT, caller sleeps */
640 /* --- "child" is awaken via removal of semaphores */
641 /* THE FOLLOWING SHOULD SHOW now be destroyed */
642 /* ------------------------------------------------------------------ */
643 SEMOP_TABLE(7, -8, "0", "Sleep (until semaphores are removed)");
644 /*
645 * Child process
646 */
647 if ((pid = fork()) == (pid_t) 0) {
648 semoparray[0].sem_num = 2;
649 semoparray[0].sem_op = -8;
650 semoparray[0].sem_flg = 0;
651
652 if (semop(semid, semoparray, 1) >= 0)
653 error("semop did not return ERMID", __LINE__);
654 else if (errno != EIDRM) {
655 printf("semop returned: %d\n", errno);
656 sys_error("semop failed", __LINE__);
657 }
658 exit(0);
659 } else if (pid < (pid_t) 0) {
660 sys_error("fork failed", __LINE__);
661 }
662
663 /*
664 * Wait for child process's semaphore request before deleting the
665 * semaphores...
666 */
667 while (!semctl(semid, 2, GETNCNT, arg))
668 sleep(1);
669
670 arg.val = 0;
671 if (semctl(semid, 0, IPC_RMID, arg) < 0)
672 sys_error("semctl (IPC_RMID) failed", __LINE__);
673
674 waitpid(pid, &status, 0); /* Wait for child to complete */
675 if (WEXITSTATUS(status))
676 sys_error("child process terminated abnormally", __LINE__);
677
678 /* ------------------------------------------------------------------ */
679 /* IPC_RMID DESTROYED THE SEMAPHORE STRUCTURES. */
680 /* THEREFORE: REBUILD A SEMAPHORE STRUCTURE SET. */
681 /* ------------------------------------------------------------------ */
682 /*
683 * Create the semaphores...
684 */
685 if ((semid = semget(IPC_PRIVATE, nsems, IPC_CREAT | mode)) < 0)
686 sys_error("semget (IPC_PRIVATE) failed", __LINE__);
687
688 /*
689 * Set the semaphore uid, gid and mode
690 */
691 arg.buf = (struct semid_ds *)calloc(1, sizeof(struct semid_ds));
692 if (!arg.buf)
693 error("calloc failed", __LINE__);
694 arg.buf->sem_perm.uid = uid;
695 arg.buf->sem_perm.gid = gid;
696 arg.buf->sem_perm.mode = mode;
697 if (semctl(semid, 0, IPC_SET, arg) < 0)
698 sys_error("semctl failed", __LINE__);
699
700 /*
701 * Verify that semaphore uid, gid and mode were set correctly
702 */
703 if (semctl(semid, 0, IPC_STAT, arg) < 0)
704 sys_error("semctl (IPC_STAT) failed", __LINE__);
705 if (arg.buf->sem_perm.uid != uid)
706 error("semctl: uid was not set", __LINE__);
707 if (arg.buf->sem_perm.gid != gid)
708 error("semctl: gid was not set", __LINE__);
709 if ((arg.buf->sem_perm.mode & 0777) != mode)
710 error("semctl: mode was not set", __LINE__);
711 if (arg.buf->sem_nsems != nsems)
712 error("semctl: nsems (number of semaphores) was not set",
713 __LINE__);
714 SAFE_FREE(arg.buf);
715
716 arg.array = malloc(sizeof(int) * nsems);
717 if (!arg.array)
718 error("malloc failed", __LINE__);
719 for (i = 0; i < nsems; i++)
720 arg.array[i] = 9;
721 if (semctl(semid, 0, SETALL, arg) < 0)
722 sys_error("semctl (SETALL) failed", __LINE__);
723 SAFE_FREE(arg.array);
724
725 /* ------------------------------------------------------------------ */
726 /* TEST # 12 --- semval = 9, sem_op = -1, sem_flg = SEM_UN */
727 /* --- semval > |sem_op| THEN (semval - |sem_op|) = 8 */
728 /* --- ALSO (semadj = semadj + sem_op) */
729 /* THE FOLLOWING SHOULD SHOW semval = 8 */
730 /* ------------------------------------------------------------------ */
731 SEMOP_TABLE(9, -1, "SEM_UNDO", "Obtain resource");
732 for (i = 0; i < nsems; i++) {
733 semoparray[i].sem_num = i;
734 semoparray[i].sem_op = -1;
735 semoparray[i].sem_flg = SEM_UNDO;
736 }
737 if (semop(semid, semoparray, nsems) < 0)
738 sys_error("semop failed", __LINE__);
739
740 expected_value = 8;
741 for (i = 0; i < nsems; i++) {
742 arg.val = 0;
743 if ((val = semctl(semid, 0, GETVAL, arg)) < 0)
744 sys_error("semctl (GETVAL) failed", __LINE__);
745 if (val != expected_value)
746 error("incorrect semaphore value", __LINE__);
747 }
748
749 /* ------------------------------------------------------------------ */
750 /* TEST # 13 --- semval = 8, sem_op = -8, sem_flg = SEM_UN */
751 /* --- semval = |sem_op| THEN (semval - |sem_op|) = 0 */
752 /* --- ALSO (semadj = semadj + sem_op) */
753 /* ------------------------------------------------------------------ */
754 SEMOP_TABLE(8, -8, "SEM_UNDO", "Obtain resource");
755 for (i = 0; i < nsems; i++) {
756 semoparray[i].sem_num = i;
757 semoparray[i].sem_op = -8;
758 semoparray[i].sem_flg = SEM_UNDO;
759 }
760 if (semop(semid, semoparray, nsems) < 0)
761 sys_error("semop failed", __LINE__);
762
763 expected_value = 0;
764 for (i = 0; i < nsems; i++) {
765 arg.val = 0;
766 if ((val = semctl(semid, 0, GETVAL, arg)) < 0)
767 sys_error("semctl (GETVAL) failed", __LINE__);
768 if (val != expected_value)
769 error("incorrect semaphore value", __LINE__);
770 }
771
772 arg.array = malloc(sizeof(int) * nsems);
773 if (!arg.array)
774 error("malloc failed", __LINE__);
775 for (i = 0; i < nsems; i++)
776 arg.array[i] = 9;
777 if (semctl(semid, 0, SETALL, arg) < 0)
778 sys_error("semctl (SETALL) failed", __LINE__);
779 SAFE_FREE(arg.array);
780
781 /* ------------------------------------------------------------------ */
782 /* TEST # 14 --- semval = 9, sem_op[4] = 0, sem_flg = 0 */
783 /* --- semval != 0 && ! IPC_NOWAIT caller sleeps */
784 /* --- ALSO ++semzcnt */
785 /* --- "child" is awaken via a signal. */
786 /* ------------------------------------------------------------------ */
787 SEMOP_TABLE(9, 0, "0", "Sleep (until signaled)");
788 /*
789 * Child process
790 */
791 if ((pid = fork()) == 0) {
792 semoparray[0].sem_num = 0;
793 semoparray[0].sem_op = 0;
794 semoparray[0].sem_flg = 0;
795
796 if (semop(semid, semoparray, 1) >= 0)
797 error("semop did not return EINTR", __LINE__);
798 else if (errno != EINTR) {
799 printf("semop returned: %d\n", errno);
800 sys_error("semop failed", __LINE__);
801 }
802 exit(0);
803 } else if (pid < 0) {
804 sys_error("fork failed", __LINE__);
805 }
806
807 /*
808 * Wait for child process's semaphore request before proceeding...
809 */
810 while (!semctl(semid, 0, GETZCNT, arg))
811 sleep(1);
812
813 kill(pid, SIGUSR1);
814
815 waitpid(pid, &status, 0); /* Wait for child to complete */
816 if (WEXITSTATUS(status))
817 sys_error("child process terminated abnormally", __LINE__);
818
819 expected_value = 9;
820 arg.val = 0;
821 if ((val = semctl(semid, 0, GETVAL, arg)) < 0)
822 sys_error("semctl (GETVAL) failed", __LINE__);
823 if (val != expected_value)
824 error("incorrect semaphore value", __LINE__);
825
826 /* ------------------------------------------------------------------ */
827 /* TEST # 15 --- semval = 9, sem_op[0] = 0, sem_flg = 0 */
828 /* --- semval != 0 && ! IPC_NOWAIT caller sleeps */
829 /* --- ALSO ++semzcnt */
830 /* call #1 --- semval = 9, sem_op[0] = -9, sem_flg = 0 */
831 /* --- THEN (semval - |sem_op|) = 0 and --semzcnt */
832 /* --- "child" is awaken via call #1. */
833 /* ------------------------------------------------------------------ */
834 SEMOP_TABLE(9, 0, "0", "Sleep (until resource becomes available)");
835 /*
836 * Child process
837 */
838 if ((pid = fork()) == (pid_t) 0) {
839 semoparray[0].sem_num = 0;
840 semoparray[0].sem_op = 0;
841 semoparray[0].sem_flg = 0;
842 if (semop(semid, semoparray, 1) < 0)
843 sys_error("semop failed", __LINE__);
844 exit(0);
845 } else if (pid < (pid_t) 0) {
846 sys_error("fork failed", __LINE__);
847 }
848
849 /*
850 * Wait for child process's semaphore request before proceeding...
851 */
852 while (!semctl(semid, 0, GETZCNT, arg))
853 sleep(1);
854
855 semoparray[0].sem_num = 0;
856 semoparray[0].sem_op = -9;
857 semoparray[0].sem_flg = 0;
858
859 if (semop(semid, semoparray, 1) < 0)
860 sys_error("semop failed", __LINE__);
861
862 waitpid(pid, &status, 0); /* Wait for child to complete */
863 if (WEXITSTATUS(status))
864 sys_error("child process terminated abnormally", __LINE__);
865
866 expected_value = 0;
867 arg.val = 0;
868 if ((val = semctl(semid, 0, GETVAL, arg)) < 0)
869 sys_error("semctl (GETVAL) failed", __LINE__);
870 if (val != expected_value)
871 error("incorrect semaphore value", __LINE__);
872
873 /* ------------------------------------------------------------------ */
874 /* TEST # 16 --- semval = 4, sem_op[4] = 0, sem_flg = 0 */
875 /* --- semval != 0 && ! IPC_NOWAIT caller sleeps */
876 /* --- ALSO ++semzcnt */
877 /* --- "child" is awaken via removal of semaphores */
878 /* ------------------------------------------------------------------ */
879 SEMOP_TABLE(4, 0, "0", "Sleep (until semaphores are removed)");
880 /*
881 * Child process
882 */
883 arg.val = 4;
884 if (semctl(semid, 4, SETVAL, arg) < 0)
885 sys_error("semctl (SETALL) failed", __LINE__);
886
887 if ((pid = fork()) == (pid_t) 0) {
888 semoparray[0].sem_num = 4;
889 semoparray[0].sem_op = -8;
890 semoparray[0].sem_flg = 0;
891
892 if (semop(semid, semoparray, 1) >= 0)
893 error("semop did not return ERMID", __LINE__);
894 else if (errno != EIDRM) {
895 printf("semop returned: %d\n", errno);
896 sys_error("semop failed", __LINE__);
897 }
898 exit(0);
899 } else if (pid < 0) {
900 sys_error("fork failed", __LINE__);
901 }
902
903 /*
904 * Wait for child process's semaphore request before proceeding...
905 */
906 while (!semctl(semid, 4, GETNCNT, arg))
907 sleep(1);
908
909 arg.val = 0;
910 if (semctl(semid, 0, IPC_RMID, arg) < 0)
911 sys_error("semctl (IPC_RMDI) failed", __LINE__);
912
913 waitpid(pid, &status, 0); /* Wait for child to complete */
914 if (WEXITSTATUS(status))
915 sys_error("child process terminated abnormally", __LINE__);
916 }
917
918 /*---------------------------------------------------------------------+
919 | parse_args () |
920 | ==================================================================== |
921 | |
922 | Function: Parse the command line arguments & initialize global |
923 | variables. |
924 | |
925 | Updates: (command line options) |
926 | |
927 | [-p] nproc: number of child processes |
928 | |
929 +---------------------------------------------------------------------*/
parse_args(int argc,char ** argv)930 void parse_args(int argc, char **argv)
931 {
932 int opt;
933 int errflag = 0;
934 char *program_name = *argv;
935 extern char *optarg; /* Command line option */
936
937 while ((opt = getopt(argc, argv, "s:p:")) != EOF) {
938 switch (opt) {
939 case 's':
940 nsems = atoi(optarg);
941 break;
942 case 'p':
943 nprocs = atoi(optarg);
944 break;
945 default:
946 errflag++;
947 break;
948 }
949 }
950 if (nsems >= MAX_SEMAPHORES) {
951 errflag++;
952 fprintf(stderr, "ERROR: nsems must be less than %d\n",
953 MAX_SEMAPHORES);
954 }
955 if (nprocs >= MAX_CHILDREN) {
956 errflag++;
957 fprintf(stderr, "ERROR: nproc must be less than %d\n",
958 MAX_CHILDREN);
959 }
960
961 if (errflag) {
962 fprintf(stderr, USAGE, program_name);
963 exit(2);
964 }
965 }
966
967 /*---------------------------------------------------------------------+
968 | setup_signal_handler () |
969 | ==================================================================== |
970 | |
971 | Function: Sets up signal handler for SIGUSR1 signal |
972 | |
973 +---------------------------------------------------------------------*/
setup_signal_handler()974 static void setup_signal_handler()
975 {
976 struct sigaction sigact;
977
978 sigact.sa_flags = 0;
979 sigfillset(&sigact.sa_mask);
980
981 /*
982 * Establish the signal handler for SIGUSR1
983 */
984 sigact.sa_handler = (void (*)(int))catch;
985 if (sigaction(SIGUSR1, &sigact, NULL) < 0)
986 sys_error("sigaction failed", __LINE__);
987 }
988
989 /*---------------------------------------------------------------------+
990 | catch () |
991 | ==================================================================== |
992 | |
993 | Function: Signal catching function for SIGUSR1 |
994 | |
995 +---------------------------------------------------------------------*/
catch(int sig)996 static void catch(int sig)
997 {
998 char err_msg[256];
999 pid_t pid = getpid();
1000
1001 if (sig == SIGUSR1) {
1002 if (pid == parent_pid)
1003 printf
1004 ("\t\t\t\t <<< caught signal (SIGUSR1, %d) >>>\n",
1005 sig);
1006 } else {
1007 sprintf(err_msg, "caught unexpected signal (%d)", sig);
1008 error(err_msg, __LINE__);
1009 }
1010 }
1011
1012 /*---------------------------------------------------------------------+
1013 | sys_error () |
1014 | ==================================================================== |
1015 | |
1016 | Function: Creates system error message and calls error () |
1017 | |
1018 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)1019 static void sys_error(const char *msg, int line)
1020 {
1021 char syserr_msg[256];
1022
1023 sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
1024 error(syserr_msg, line);
1025 }
1026
1027 /*---------------------------------------------------------------------+
1028 | error () |
1029 | ==================================================================== |
1030 | |
1031 | Function: Prints out message and exits... |
1032 | |
1033 +---------------------------------------------------------------------*/
error(const char * msg,int line)1034 static void error(const char *msg, int line)
1035 {
1036 fprintf(stderr, "ERROR pid %d [line: %d] %s\n", errpid, line, msg);
1037 exit(-1);
1038 }
1039