1 /*
2 *
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 #include <sys/mman.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <signal.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
30
31 #ifndef _LINUX
32 /* LINUX INCLUDES */
33 #include <sys/mode.h>
34 #include <sys/timers.h>
35 #else
36 #include <sys/stat.h>
37 #include <time.h>
38 #include <sys/time.h>
39 #include <sys/ipc.h>
40 #endif
41 #include <sys/msg.h>
42 #include <sys/resource.h>
43 #include <sys/select.h>
44 #include <sys/sem.h>
45 #include <sys/shm.h>
46 #include <sys/types.h>
47 #include <sys/wait.h>
48 #include "lapi/semun.h"
49
50 /* indexes into environment variable array */
51 #define ADBG 0
52 #define BNDX 1
53 #define DNDX 2
54 #define TNDX 3
55 #define MAXBVAL 70
56 #define MAXDVAL 11
57 #define SLOTDIR "./slot/"
58
59 #ifdef _LINUX
60 /* LINUX #defnes */
61 #ifndef TRUE
62 #define TRUE 1
63 #endif
64 #ifndef FALSE
65 #define FALSE 0
66 #endif
67 #endif
68
69 #if defined _LINUX && defined DEBUG
70 #define prtln() printf("At line number: %d\n", __LINE__); \
71 fflush(NULL)
72 #define dprt(fmt, args...) printf(fmt, ## args)
73 #else
74 #define prtln()
75 #define dprt(fmt, args...)
76 #endif
77
78 /* aliases for environment variable entries */
79 #define AUSDEBUG (*edat[ADBG].eval.vint) /* debug value */
80 #define BVAL (*edat[BNDX].eval.vint) /* # of childern per parent */
81 #define DVAL (*edat[DNDX].eval.vint) /* depth of process tree */
82 #define TVAL (*edat[TNDX].eval.vint) /* timer value */
83
84 #ifdef _LINUX
85 typedef long mtyp_t;
86 #endif
87
88 /* structure of information stored about each process in shared memory */
89 typedef struct proc_info {
90 #ifdef __64LDT__
91 pid_t pid; /* process id */
92 pid_t ppid; /* parent process id */
93 #else
94 int pid; /* process id */
95 int ppid; /* parent process id */
96 #endif
97 int msg; /* parent process id */
98 int err; /* error indicator */
99 int *list; /* pointer to list of parent and sibling slot locations */
100 } Pinfo;
101
102 typedef struct messagebuf {
103 mtyp_t mtyp; /* message type */
104 char mtext[80]; /* message text */
105 } Msgbuf;
106
107 union semun semarg;
108
109 /* structure of all environment variable used by program */
110 struct envstruct {
111 char *env_name;
112 union {
113 char *chptr;
114 int *vint;
115 } eval;
116 } envdata[] = {
117 {
118 "AUSDBG", {
119 "0"}}, {
120 "BVAL", {
121 "3"}}, {
122 "DVAL", {
123 "2"}}, {
124 "FORCE", {
125 "0"}}, {
126 "TVAL", {
127 "1"}}, {
128 "", {
129 ""}}
130 };
131
132 char *errfile; /* pointer to errfile name */
133
134 int msgid; /* message queue for leaf nodes */
135 int msgerr; /* message queue for errors */
136 int nodesum; /* total number of process to be created */
137 int sem_count; /* counter semaphore */
138 int sem_lock; /* locks access to counter semaphore */
139 int shmid; /* global shared memory id varible */
140 int procgrp; /* process group id */
141
142 timer_t timer; /* timer structure */
143
144 Pinfo *shmaddr; /* Start address of shared memory */
145
146 #ifndef _LINUX
147 FILE *errfp = stderr; /* error file pointer, probably not necessary */
148 FILE *debugfp = stderr; /* debug file pointer, used if AUSDEBUG set */
149 #else
150 #define errfp stderr
151 #define debugfp stderr
152 #endif
153
154 struct envstruct *edat = envdata; /* pointer to environment data */
155
156 /* external function declarations */
157 extern int killpg(int procgrp, int sig);
158 extern timer_t gettimerid(int Timer_type, int Notify_type);
159 extern int reltimerid(timer_t timer);
160
161 /* internal function declarations */
162 void cleanup(int sig, int code, struct sigcontext *scp);
163 void nextofkin(int sig, int code, struct sigcontext *scp);
164 void doit(void);
165 void debugout(char *fmt, ...);
166 int getenv_val(void);
167 void messenger(void);
168 void nextofkin(int sig, int code, struct sigcontext *scp);
169 int notify(int slot);
170 void parse_args(int argc, char *argv[]);
171 void print_shm(void);
172 Pinfo *put_proc_info(int tval);
173 void rm_msgqueue(void);
174 void rm_semseg(void);
175 void rm_shmseg(void);
176 int semoper(int slot, int smid, int opval);
177 int send_message(int id, mtyp_t type, char *text);
178 void set_timer(void);
179 void set_signals(void *sighandler());
180 void setup_msgqueue(void);
181 void setup_semaphores(void);
182 void setup_shm(void);
183 void severe(char *fmt, ...);
184 Pinfo *shmgetseg(void);
185 int spawn(int val);
186 unsigned long sumit(int B, int D);
187
188 /*
189 * Prints out the data structures in shared memory.
190 */
print_shm(void)191 void print_shm(void)
192 {
193 extern int nodesum; /* total number of nodes created */
194 extern Pinfo *shmaddr; /* shared memory pointer */
195 extern int shmid; /* shared memory id */
196
197 Pinfo *pinfo; /* pointer to process info in shared memory */
198 int *listp; /* pointer to sibling info in shared memory */
199 int i, j; /* counters */
200 struct shmid_ds buf;
201
202 if (shmctl(shmid, IPC_STAT, &buf))
203 return;
204
205 for (pinfo = shmaddr, i = 0; i < nodesum; i++, pinfo++) {
206 fprintf(errfp,
207 "slot: %-4d pid: %-6d ppid: %-6d msg: %-2d err: %-2d lst:",
208 i, pinfo->pid, pinfo->ppid, pinfo->msg, pinfo->err);
209 for (j = 0, listp = pinfo->list; j < BVAL; j++, listp++)
210 fprintf(errfp, " %d", *listp);
211 fprintf(errfp, "\n");
212 }
213 }
214
215 /*
216 * Generalized send routine. Sends a message on message queue.
217 */
send_message(int id,mtyp_t type,char * text)218 int send_message(int id, mtyp_t type, char *text)
219 {
220 int rc;
221
222 Msgbuf sndbuf;
223
224 strcpy(sndbuf.mtext, text);
225 sndbuf.mtyp = type;
226 while (TRUE) {
227 rc = msgsnd(id, &sndbuf, sizeof(struct messagebuf), IPC_NOWAIT);
228 if (rc == -1 && errno == EAGAIN) {
229 debugout("msgqueue %d of mtyp %d not ready to send\n",
230 msgid, type);
231 errno = 0;
232 } else
233 return (rc);
234 }
235 }
236
237 /*
238 * Sends error message to initial parent (messenger).i
239 */
severe(char * fmt,...)240 void severe(char *fmt, ...)
241 {
242 va_list args;
243 int rc;
244 char mtext[80];
245 extern int msgerr;
246
247 va_start(args, fmt);
248 vsprintf(mtext, fmt, args);
249 va_end(args);
250
251 rc = send_message(msgerr, 2, mtext);
252 if (rc == -1) {
253 perror("cannot send message to msgerr");
254 exit(1);
255 }
256 }
257
258 /*
259 * if AUSDEBUG set will print information to file associated with slot number.
260 */
debugout(char * fmt,...)261 void debugout(char *fmt, ...)
262 {
263 va_list args;
264
265 if (AUSDEBUG) {
266 va_start(args, fmt);
267 vfprintf(debugfp, fmt, args);
268 va_end(args);
269 }
270 }
271
272 /*
273 * Remove message queues.
274 */
rm_msgqueue(void)275 void rm_msgqueue(void)
276 {
277 extern int msgid;
278
279 /* remove message queue id. */
280 if (msgctl(msgid, IPC_RMID, NULL) && errno != EINVAL) {
281 fprintf(errfp, "msgctl failed msgid: errno %d\n", errno);
282 perror("msgctl failed");
283 }
284
285 /* remove message queue id. */
286 if (msgctl(msgerr, IPC_RMID, NULL) && errno != EINVAL) {
287 fprintf(errfp, "msgctl failed msgerr: errno %d\n", errno);
288 perror("msgctl failed");
289 }
290 }
291
292 /*
293 * Remove shared memory segment.
294 */
rm_shmseg(void)295 void rm_shmseg(void)
296 {
297 extern int shmid; /* Global shared memory id */
298 extern Pinfo *shmaddr; /* Global shared memory address */
299
300 /* remove shared memory id (and shared memory segment). */
301 if (shmctl(shmid, IPC_RMID, NULL) && errno != EINVAL) {
302 fprintf(errfp, "shmctl failed: errno %d\n", errno);
303 perror("shmctl failed");
304 }
305 }
306
307 /*
308 * Remove semaphores.
309 */
rm_semseg(void)310 void rm_semseg(void)
311 {
312 extern int sem_lock;
313 extern int sem_count;
314
315 /* remove sem_lock semaphore id */
316 semarg.val = 0; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
317 if (semctl(sem_lock, 0, IPC_RMID, semarg.val) && errno != EINVAL) {
318 fprintf(errfp, "semctl failed: errno %d\n", errno);
319 perror("semctl failed");
320 }
321 /* remove sem_count semaphore id. */
322 semarg.val = 0; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
323 if (semctl(sem_count, 0, IPC_RMID, semarg.val) && errno != EINVAL) {
324 fprintf(errfp, "semctl failed: errno %d\n", errno);
325 perror("semctl failed");
326 }
327 }
328
329 /*
330 * Routine to clean up shared memory and return exit status (CHILD handler).
331 */
cleanup(int sig,int code,struct sigcontext * scp)332 void cleanup(int sig, int code, struct sigcontext *scp)
333 {
334 int rc;
335 char mtext[80];
336
337 killpg(procgrp, SIGTERM);
338 sprintf(mtext, "%d", sig);
339 rc = send_message(msgerr, 3, mtext);
340 if (rc == -1) {
341 severe("msgsnd failed: %d msgid %d mtyp %d mtext %d\n",
342 errno, msgerr, 3, mtext);
343 }
344 }
345
346 /*
347 * Routine to clean up shared memory and return exit status (PARENT handler).
348 */
nextofkin(int sig,int code,struct sigcontext * scp)349 void nextofkin(int sig, int code, struct sigcontext *scp)
350 {
351 int rc;
352 char mtext[80];
353
354 sprintf(mtext, "%d", sig);
355 rc = send_message(msgerr, 3, mtext);
356 if (rc == -1) {
357 severe("msgsnd failed: %d msgid %d mtyp %d mtext %d\n",
358 errno, msgerr, 3, mtext);
359 }
360 #ifndef _LINUX
361 reltimerid(timer);
362 #endif
363 exit(1);
364 }
365
366 /* given breadth and depth of a tree, sum up total number of nodes created */
sumit(int B,int D)367 unsigned long sumit(int B, int D)
368 {
369 int i;
370 int exp = 1; /* exponent of breadth */
371 unsigned long sum = 1; /* running sum of nodes */
372
373 for (sum = 1, i = 1; i <= D; i++) {
374 exp = B * exp;
375 sum += (int)exp;
376 }
377 return (sum);
378 }
379
380 /* Finds correct slot for current process in shared memory and stores
381 * information about process in it.
382 */
put_proc_info(int tval)383 Pinfo *put_proc_info(int tval)
384 {
385 extern int nodesum;
386 extern Pinfo *shmaddr;
387
388 int sibslot = 0; /* sibling slot number */
389 int *listp; /* ptr to sibling info for current proc */
390 Pinfo *smp; /* ptr to current process data slot */
391
392 smp = shmaddr + tval;
393 smp->pid = getpid();
394 smp->ppid = getppid();
395 smp->err = 0;
396 smp->msg = 0;
397
398 /* if very first process (slot 0), dont fill in info about siblings
399 * and parent. Sibling and parent info is irrevelant in this case.
400 */
401 if (!tval)
402 return (smp);
403
404 /* find parent of current process and store slot location */
405 smp->list = (int *)(Pinfo *) (shmaddr + nodesum) + (BVAL * tval);
406 *smp->list = (tval - 1) / BVAL;
407 listp = smp->list + 1;
408
409 /* calculate and store sibling slot numbers of current process */
410 for (sibslot = *smp->list * BVAL + 1; listp < smp->list + BVAL;
411 sibslot++) {
412 if (tval != sibslot)
413 *(listp++) = sibslot;
414 }
415 return (smp);
416 }
417
418 /* This routine sends a message from the current process to all of her
419 * siblings and then waits to receive responses from them. A timer is
420 * set so that if a message is lost or not received for some reason
421 * we can exit gracefully.
422 */
notify(int slot)423 int notify(int slot)
424 {
425 extern int msgid;
426 extern Pinfo *shmaddr;
427
428 int i;
429 int rc;
430 int tslot;
431 int *listp = (shmaddr + slot)->list;
432 int cldcnt = 1;
433 int ndx = 0;
434 #ifdef __64LDT__
435 pid_t pid = 0;
436 #else
437 int pid = 0;
438 #endif
439 char mtext[80];
440
441 Msgbuf rcvbuf;
442
443 for (i = 1, listp++; i < BVAL; i++, listp++) {
444 sprintf(mtext, "%d %d %d", i, slot, (shmaddr + slot)->pid);
445 rc = send_message(msgid, (mtyp_t) * listp, mtext);
446 if (rc == -1) {
447 severe
448 ("notify: send_message Failed: %d msgid %d mtyp %d mtext %d\n",
449 errno, msgid, *listp, mtext);
450 exit(1);
451 }
452 }
453
454 while (cldcnt < BVAL) {
455 rc = msgrcv(msgid, &rcvbuf, sizeof(struct messagebuf), slot, 0);
456 if (rc == -1) {
457 switch (errno) {
458 case EAGAIN:
459 printf("msgqueue %d not ready to receive\n",
460 msgid);
461 fflush(stdout);
462 errno = 0;
463 break;
464 case ENOMSG:
465 printf("msgqueue %d no message\n", msgid);
466 fflush(stdout);
467 errno = 0;
468 break;
469 default:
470 perror("msgrcv failed");
471 severe("msgrcv failed, errno: %d\n", errno);
472 exit(1);
473 }
474 } else {
475 sscanf(rcvbuf.mtext, "%d %d %d", &ndx, &tslot, &pid);
476 if (*((shmaddr + tslot)->list + ndx) == slot &&
477 (shmaddr + tslot)->pid == pid) {
478 debugout
479 ("MSGRCV:slot: %d ndx: %d tslot: %d pid: %d\n",
480 slot, ndx, tslot, pid);
481 (shmaddr + slot)->msg++;
482 cldcnt++;
483 } else {
484 (shmaddr + slot)->err--;
485 debugout
486 ("MSGRCV: slot: %d ndx: %d tslot: %d pid: %d\n",
487 slot, ndx, tslot, pid);
488 }
489 }
490 }
491 return 0;
492 }
493
494 /*
495 * Calculates semaphore number and sets semaphore (lock).
496 */
semoper(int slot,int smid,int opval)497 int semoper(int slot, int smid, int opval)
498 {
499 int pslot; /* parent slot */
500 struct sembuf smop; /* semaphore operator */
501
502 pslot = (slot - 1) / BVAL; /* calculate parent node */
503 smop.sem_num = pslot;
504 smop.sem_op = opval;
505 smop.sem_flg = 0;
506 semop(smid, &smop, 1);
507 return (pslot);
508 }
509
510 /*
511 * This is the meat and potatoes of the program. Spawn creates a tree
512 * of processes with Dval depth and Bval breadth. Each parent will spawn
513 * Bval children. Each child will store information about themselves
514 * in shared memory. The leaf nodes will communicate the existence
515 * of one another through message queues, once each leaf node has
516 * received communication from all of her siblings she will reduce
517 * the semaphore count and exit. Meanwhile all parents are waiting
518 * to hear from their children through the use of semaphores. When
519 * the semaphore count reaches zero then the parent knows all the
520 * children have talked to one another. Locking of the connter semaphore
521 * is provided by the use of another (binary) semaphore.
522 */
spawn(int val)523 int spawn(int val)
524 {
525 extern int sem_count; /* used to keep track of childern */
526 extern int sem_lock; /* used to lock access to sem_count semaphore */
527
528 int i; /* Breadth counter */
529 static int level = 0; /* level counter */
530 int lvlflg = 0; /* level toggle, limits parental spawning
531 to one generation */
532 int pslot = 0;
533 #ifdef __64LDT__
534 pid_t pid; /* pid of child process */
535 #else
536 int pid; /* pid of child process */
537 #endif
538 Pinfo *pinfo; /* pointer to process information in shared mem */
539 int semval; /* value of semaphore ( equals BVAL initially */
540 static int tval = 1; /* tree node value of child. */
541
542 char foo[1024];
543
544 level++;
545
546 for (i = 1; i <= BVAL; i++) {
547 tval = (val * BVAL) + i;
548 if (!lvlflg) {
549 pid = fork();
550 if (!pid) { /* CHILD */
551 if (AUSDEBUG) {
552 sprintf(foo, "%sslot%d", SLOTDIR, tval);
553 debugfp = fopen(foo, "a+");
554 }
555 pinfo = put_proc_info(tval);
556
557 debugout
558 ("pid: %-6d ppid: %-6d lev: %-2d i: %-2d val: %-3d\n",
559 pinfo->pid, pinfo->ppid, level, i, tval);
560
561 set_timer(); /* set up signal handlers and initialize pgrp */
562 if (level < DVAL) {
563 if (spawn(tval) == -1) {
564 pslot =
565 semoper(tval, sem_lock, -1);
566 semarg.val = 0; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
567 semval =
568 semctl(sem_count, pslot,
569 GETVAL, semarg);
570 semarg.val = --semval; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
571 semctl(sem_count, pslot, SETVAL,
572 semarg);
573 semarg.val = 1; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
574 semctl(sem_lock, pslot, SETVAL,
575 semarg);
576 }
577 lvlflg++;
578 } else { /* leaf node */
579 notify(tval);
580 return (-1);
581 }
582 }
583 #ifdef __64LDT__
584 else if (pid > 0 && i >= BVAL) { /* PARENT */
585 #else
586 else if (pid > (pid_t) 0 && i >= BVAL) { /* PARENT */
587 #endif
588 pslot = semoper(tval, sem_count, 0);
589 pslot = semoper(pslot, sem_lock, -1);
590 semarg.val = 0; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
591 semval =
592 semctl(sem_count, pslot, GETVAL, semarg);
593 semarg.val = --semval; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
594 semctl(sem_count, pslot, SETVAL, semarg);
595 semarg.val = 1; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
596 semctl(sem_lock, pslot, SETVAL, semarg);
597 (shmaddr + val)->msg++;
598 }
599 #ifdef __64LDT__
600 else if (pid < (pid_t) 0) {
601 #else
602 else if (pid < 0) {
603 #endif
604 perror("spawn: fork failed");
605 severe
606 ("spawn: fork failed, exiting with errno %d\n",
607 errno);
608 exit(1);
609 } else
610 (shmaddr + val)->msg++;
611 }
612 }
613 return (pslot);
614 }
615
616 /*
617 * Allocate message queues.
618 */
619 void setup_msgqueue(void)
620 {
621 extern int msgid;
622 extern int msgerr;
623
624 msgid = msgget(IPC_PRIVATE,
625 IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
626 S_IWGRP);
627 if (msgid == -1) {
628 perror("msgget msgid failed");
629 fprintf(stderr, " SEVERE : msgget msgid failed: errno %d\n",
630 errno);
631 exit(1);
632 }
633
634 msgerr = msgget(IPC_PRIVATE,
635 IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
636 S_IWGRP);
637 if (msgerr == -1) {
638 perror("msgget msgerr failed");
639 fprintf(stderr, " SEVERE : msgget msgerr failed: errno %d\n",
640 errno);
641 exit(1);
642 }
643 }
644
645 /*
646 * Set up and initialize all semaphores
647 */
648 void setup_semaphores(void)
649 {
650 extern int sem_count;
651 extern int sem_lock;
652
653 int i;
654 int rc;
655
656 prtln();
657 sem_lock = semget(IPC_PRIVATE, nodesum - 1,
658 IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
659 S_IWGRP);
660 dprt("nodesum = %d, sem_lock = %d\n", nodesum, sem_lock);
661
662 prtln();
663 if (sem_lock == -1) {
664 perror("semget failed for sem_lock");
665 fprintf(stderr,
666 " SEVERE : semget failed for sem_lock, errno: %d\n",
667 errno);
668 rm_shmseg();
669 exit(1);
670 }
671
672 prtln();
673 sem_count = semget(IPC_PRIVATE, nodesum - 1,
674 IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
675 S_IWGRP);
676
677 if (sem_count == -1) {
678 perror("semget failed for sem_count");
679 fprintf(stderr,
680 " SEVERE : semget failed for sem_count, errno: %d\n",
681 errno);
682 rm_shmseg();
683 exit(1);
684 }
685 prtln();
686
687 for (i = 0; i < (nodesum - 1); i++) {
688 semarg.val = 1; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
689 rc = semctl(sem_lock, i, SETVAL, semarg);
690 prtln();
691 if (rc == -1) {
692 perror("semctl failed for sem_lock failed");
693 fprintf(stderr,
694 " SEVERE : semctl failed for sem_lock, errno: %d\n",
695 errno);
696 rm_shmseg();
697 exit(1);
698 }
699
700 semarg.val = BVAL; /* to fix problem with 4th arg of semctl in 64 bits MARIOG */
701 rc = semctl(sem_count, i, SETVAL, semarg);
702 prtln();
703 if (rc == -1) {
704 perror("semctl failed for sem_lock failed");
705 fprintf(stderr,
706 " SEVERE : semctl failed for sem_lock, errno: %d\n",
707 errno);
708 rm_shmseg();
709 exit(1);
710 }
711 }
712 }
713
714 /*
715 * Set up and allocate shared memory.
716 */
717 void setup_shm(void)
718 {
719 extern int nodesum; /* global shared memory id */
720 extern int shmid; /* global shared memory id */
721 extern Pinfo *shmaddr;
722
723 int i, j; /* counters */
724 Pinfo *shmad = NULL; /* ptr to start of shared memory. */
725 Pinfo *pinfo = NULL; /* ptr to struct in shared memory. */
726
727 debugout("size = %d, size (in hex) = %#x nodes: %d\n",
728 sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)),
729 sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)),
730 nodesum);
731
732 /* Get shared memory id */
733 shmid = shmget(IPC_PRIVATE,
734 sizeof(Pinfo) * nodesum + (nodesum * BVAL * sizeof(int)),
735 IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP |
736 S_IWGRP);
737 if (shmid < 0) {
738 perror("shmget failed");
739 fprintf(stderr, " SEVERE : shmget failed: errno %d\n", errno);
740 exit(1);
741 }
742
743 /* allocate shared memory */
744
745 if ((shmad = shmat(shmid, (char *)shmad, 0)) == MAP_FAILED) {
746 printf("SEVERE : shmat failed\n");
747 exit(1);
748 } else {
749 shmctl(shmid, IPC_RMID, NULL);
750 }
751
752 /* set all fields in shared memory to -1 */
753 for (pinfo = shmad, i = 0; i < nodesum; i++, pinfo++) {
754 #ifdef __64LDT__
755 pinfo->pid = (pid_t) - 1;
756 pinfo->ppid = (pid_t) - 1;
757 #else
758 pinfo->pid = -1;
759 pinfo->ppid = -1;
760 #endif
761 pinfo->msg = -1;
762 pinfo->err = -1;
763
764 /* Changed 10/9/97 */
765 /* pinfo->list = (int *)((ulong)shmad + nodesum * sizeof(Pinfo)
766 + (sizeof(int) * BVAL * i)); */
767 pinfo->list =
768 (int *)((long)shmad + nodesum * sizeof(Pinfo) +
769 (sizeof(int) * BVAL * i));
770 for (j = 0; j < BVAL; j++)
771 *(pinfo->list + j) = -1;
772 }
773 shmaddr = shmad;
774 }
775
776 /*
777 * Set up Signal handler and which signals to catch
778 */
779 void set_signals(void *sighandler())
780 {
781 int i;
782 int rc;
783
784 struct sigaction action;
785
786 /* list of signals we want to catch */
787 static struct signalinfo {
788 int signum;
789 char *signame;
790 } siginfo[] = {
791 {
792 SIGHUP, "SIGHUP"}, {
793 SIGINT, "SIGINT"}, {
794 SIGQUIT, "SIGQUIT"}, {
795 SIGABRT, "SIGABRT"}, {
796 SIGBUS, "SIGBUS"}, {
797 SIGSEGV, "SIGSEGV"}, {
798 SIGALRM, "SIGALRM"}, {
799 SIGUSR1, "SIGUSR1"}, {
800 SIGUSR2, "SIGUSR2"}, {
801 -1, "ENDSIG"}
802 };
803
804 char tmpstr[1024];
805
806 action.sa_handler = (void *)sighandler;
807
808 #ifdef _LINUX
809 sigfillset(&action.sa_mask);
810 #else
811 SIGINITSET(action.sa_mask);
812 #endif
813 action.sa_flags = 0;
814
815 /* Set the signal handler up */
816 #ifdef _LINUX
817 sigaddset(&action.sa_mask, SIGTERM);
818 #else
819 SIGADDSET(action.sa_mask, SIGTERM);
820 #endif
821 for (i = 0; siginfo[i].signum != -1; i++) {
822 #ifdef _LINUX
823 sigaddset(&action.sa_mask, siginfo[i].signum);
824 #else
825 SIGADDSET(action.sa_mask, siginfo[i].signum);
826 #endif
827 rc = sigaction(siginfo[i].signum, &action, NULL);
828 if (rc == -1) {
829 sprintf(tmpstr, "sigaction: %s\n", siginfo[i].signame);
830 perror(tmpstr);
831 fprintf(stderr,
832 " SEVERE : Could not set %s signal action, errno=%d.",
833 siginfo[i].signame, errno);
834 exit(1);
835 }
836 }
837 }
838
839 /*
840 * Get and set a timer for current process.
841 */
842 #ifndef _LINUX
843 void set_timer(void)
844 {
845 struct itimerstruc_t itimer, old_itimer;
846
847 if ((timer = gettimerid(TIMERID_REAL, DELIVERY_SIGNALS)) == -1) {
848 perror("gettimerid");
849 fprintf(stderr, " SEVERE : Could not get timer id, errno=%d.",
850 errno);
851 exit(1);
852 }
853
854 /*
855 * Start the timer.
856 */
857 itimer.it_interval.tv_nsec = 0;
858 itimer.it_interval.tv_sec = 0;
859 itimer.it_value.tv_nsec = 0;
860 itimer.it_value.tv_sec = (time_t) (TVAL * 60.0);
861 if (incinterval(timer, &itimer, &old_itimer) == -1) {
862 perror("incinterval");
863 fprintf(stderr,
864 " SEVERE : Could not set timer interval, errno=%d.",
865 errno);
866 (void)reltimerid(timer);
867 exit(1);
868 }
869 }
870 #else
871
872 void set_timer(void)
873 {
874 struct itimerval itimer;
875
876 memset(&itimer, 0, sizeof(struct itimerval));
877 /*
878 * Start the timer.
879 */
880 itimer.it_interval.tv_usec = 0;
881 itimer.it_interval.tv_sec = 0;
882 itimer.it_value.tv_usec = 0;
883 itimer.it_value.tv_sec = (time_t) (TVAL * 60.0);
884
885 if (setitimer(ITIMER_REAL, &itimer, NULL)) {
886 perror("setitimer");
887 exit(1);
888 }
889 }
890 #endif
891
892 /*
893 * parse_args
894 *
895 * Parse command line arguments. Any errors cause the program to exit
896 * at this point.
897 */
898 void parse_args(int argc, char *argv[])
899 {
900 int i;
901 int opt, errflag = 0;
902 int dflag = 0, bflag = 0, fflag = 0, tflag = 0;
903 extern int optind;
904 extern char *optarg;
905
906 /* DVAL: 0 1 2 3 4 5 6 7 8 9 10 11 */
907 int limits[] = { -1, -1, MAXBVAL, 17, 8, 5, 4, 3, 2, 2, 2, 2 };
908
909 while ((opt = getopt(argc, argv, "b:d:ft:D?")) != EOF) {
910 switch (opt) {
911 case 'b':
912 if (bflag)
913 errflag++;
914 else {
915 bflag++;
916 errno = 0;
917 BVAL = atoi(optarg);
918 if (errno) {
919 perror("atoi");
920 fprintf(stderr,
921 " ERROR : atoi - errno %d.",
922 errno);
923 errflag++;
924 }
925 }
926 break;
927 case 'd':
928 if (dflag)
929 errflag++;
930 else {
931 dflag++;
932 errno = 0;
933 DVAL = atoi(optarg);
934 if (errno) {
935 perror("atoi");
936 fprintf(stderr,
937 " ERROR : atoi - errno %d.",
938 errno);
939 errflag++;
940 }
941 }
942 break;
943 case 'f':
944 fflag = 1;
945 break;
946 case 'D':
947 AUSDEBUG = 1;
948 break;
949 case 't':
950 if (tflag)
951 errflag++;
952 else {
953 tflag++;
954 errno = 0;
955 TVAL = atoi(optarg);
956 if (!TVAL || errno) {
957 perror("atoi");
958 fprintf(stderr,
959 " ERROR : atoi - errno %d.",
960 errno);
961 errflag++;
962 }
963 }
964 break;
965 case '?':
966 errflag++;
967 break;
968 }
969 }
970
971 if (BVAL < 2) {
972 errflag++;
973 fprintf(stderr, "The value of b must be greater than 1\n");
974 } else if (DVAL < 2) {
975 errflag++;
976 fprintf(stderr, "The depth value must be greater than 1\n");
977 } else if (!fflag && (DVAL > MAXDVAL)) {
978 /* || BVAL > limits[DVAL])) { */
979 fprintf(stderr, "\tExceeded process creation limits. \
980 \n\tParameters will generate %lu processes. \n\tThe preset limits are as \
981 follows:\n\t\tdepth\tbreadth\ttotal\n", sumit(BVAL, DVAL));
982 for (i = 2; i <= MAXDVAL; i++)
983 fprintf(stderr, "\t\t %-3d\t %-5d\t%-5lu\n", i,
984 limits[i], sumit(limits[i], i));
985 exit(1);
986 }
987
988 if (errflag) {
989 fprintf(stderr,
990 "usage: %s [-b number] [-d number] [-t number] \n",
991 argv[0]);
992 fprintf(stderr, "where:\n");
993 fprintf(stderr,
994 "\t-b number\tnumber of children each parent will spawn ( > 1)\n");
995 fprintf(stderr, "\t-d number\tdepth of process tree ( > 1)\n");
996 fprintf(stderr, "\t-t\t\tset timeout value\n");
997 fprintf(stderr, " SEVERE : Command line parameter error.\n");
998 exit(1);
999 }
1000 }
1001
1002 /*
1003 * Initializes environment variables, using defaults if not set in env.
1004 */
1005 int getenv_val(void)
1006 {
1007 char *c; /* character pointer */
1008 struct envstruct *envd = envdata; /* pointer to environment data */
1009
1010 union {
1011 int *vint;
1012 char *chptr;
1013 } val;
1014
1015 /*
1016 * Loop through envdata, set default first then set environment
1017 * variable value if present.
1018 */
1019 for (; *envd->env_name != '\0'; envd++) {
1020 if ((val.chptr = getenv(envd->env_name)) == NULL)
1021 val.chptr = envd->eval.chptr;
1022
1023 c = val.chptr;
1024 while (isdigit(*c))
1025 c++;
1026
1027 if (*c == '\0') {
1028 (envd->eval.vint) = malloc(sizeof(int));
1029 *(envd->eval.vint) = atoi(val.chptr);
1030 } else {
1031 envd->eval.chptr = malloc(strlen(val.chptr) + 1);
1032 strcpy(envd->eval.chptr, val.chptr);
1033 }
1034 }
1035 return 0;
1036 }
1037
1038 /*
1039 * Prints all errors coming from the children and terminates execution if
1040 * an error execption is received. In addition messenger() is sent the
1041 * process group id of the children so it can terminate all children.
1042 * This routine uses message queues to receive all communications.
1043 */
1044 void messenger(void)
1045 { /* AKA Assassin */
1046 Msgbuf rcvbuf;
1047
1048 int discrim = 0;
1049 int rc; /* generic return code var */
1050 int sig = -1; /* type of signal received */
1051 extern int msgerr; /* message queue used to send error messages */
1052 extern int procgrp; /* process group of children (used to kill them) */
1053
1054 /*
1055 * Infinite loop used to receive error messages from children and
1056 * to terminate process tree.
1057 */
1058 while (TRUE) {
1059 rc = msgrcv(msgerr, &rcvbuf, sizeof(struct messagebuf), 0, 0);
1060 if (rc == -1) {
1061 switch (errno) {
1062 case EAGAIN:
1063 printf("msgqueue %d not ready to receive\n",
1064 msgid);
1065 fflush(stdout);
1066 errno = 0;
1067 break;
1068 case ENOMSG:
1069 printf("msgqueue %d no message\n", msgid);
1070 fflush(stdout);
1071 errno = 0;
1072 break;
1073 default:
1074 perror("msgrcv failed");
1075 fprintf(stderr,
1076 " SEVERE : messenger - msgrcv failed, errno: %d\n",
1077 errno);
1078 errno = 0;
1079 break;
1080 }
1081 } else {
1082 switch ((int)rcvbuf.mtyp) {
1083 case 1: /* type 1: we received the process group id */
1084 sscanf(rcvbuf.mtext, "%d", &procgrp);
1085 break;
1086
1087 case 2: /* type 2: we received an error */
1088 fprintf(stderr, " SEVERE : %s ", rcvbuf.mtext);
1089 /* rcvbuf.mtext type %s ou %d ??? */
1090 break;
1091
1092 case 3: /* type 3: somebody got a signal, now we terminate */
1093 sscanf(rcvbuf.mtext, "%d", &sig);
1094
1095 switch (sig) {
1096 case SIGALRM:
1097 /* a process is hung, we will terminate */
1098 killpg(procgrp, sig);
1099 fprintf(errfp,
1100 "ALERT! ALERT! WE HAVE TIMED OUT\n");
1101 fprintf(stderr,
1102 " SEVERE : SIGALRM: A process timed out, we failed\n");
1103 shmaddr->err++;
1104 break;
1105
1106 case SIGUSR1:
1107 /* Special: means everything went ok */
1108 discrim = 1;
1109 break;
1110
1111 default:
1112 /* somebody sent a signal, we will terminate */
1113 killpg(procgrp, sig);
1114 fprintf(errfp,
1115 "We received signal %d\n", sig);
1116 fprintf(stderr,
1117 " SEVERE : signal %d received, A proc was killed\n",
1118 sig);
1119 break;
1120 }
1121 /* clean up and exit with status */
1122 rm_msgqueue();
1123 rm_semseg();
1124 if (AUSDEBUG)
1125 print_shm();
1126 prtln();
1127 rm_shmseg();
1128 prtln();
1129 if (discrim) {
1130 prtln();
1131 printf("Test exiting with SUCCESS\n");
1132 exit(0);
1133 }
1134 exit(1);
1135
1136 break;
1137 }
1138 }
1139 }
1140 }
1141
1142 /*
1143 * This routine spawns off the first child (node 0) of the process tree.
1144 * This child set up the signal handler for all of the children and also
1145 * sets up a process group so that all children can be terminated easily.
1146 * The child then calls spawn which creates the process tree. After spawn
1147 * has returned the child contacts the parent and the parent exits.
1148 * The parent sets her own signal handler and then calls messenger.
1149 */
1150 void doit(void)
1151 {
1152 pid_t pid; /* process id */
1153 int rc;
1154 char mtext[80]; /* message text */
1155 extern int msgerr;
1156 extern int procgrp;
1157
1158 pid = fork();
1159 #ifdef __64LDT__
1160 if (pid == (pid_t) 0) {
1161 #else
1162 if (pid == 0) {
1163 #endif
1164 /* set the process group so we can terminate all children */
1165 set_signals((void *)nextofkin); /* set up signal handlers and initialize pgrp */
1166 #ifndef _LINUX
1167 procgrp = setpgrp(0, 0);
1168 #else
1169 procgrp = setpgrp();
1170 #endif
1171 if (AUSDEBUG) {
1172 fprintf(stderr, "process group: %d\n", procgrp);
1173 fflush(stderr);
1174 }
1175 if (procgrp == -1) {
1176 perror("setpgid failed");
1177 fprintf(stderr, " SEVERE : setpgid failed, errno: %d\n",
1178 errno);
1179 exit(1);
1180 }
1181 sprintf(mtext, "%d", procgrp);
1182 rc = send_message(msgerr, 1, mtext);
1183 if (rc == -1) {
1184 perror("send_message failed");
1185 fprintf(stderr,
1186 " SEVERE : send_message failed, errno: %d\n",
1187 errno);
1188 exit(1);
1189 }
1190
1191 put_proc_info(0); /* store process info for this (root) process */
1192 spawn(0);
1193 if (shmaddr->pid == getpid()) {
1194 sprintf(mtext, "%d", SIGUSR1);
1195 rc = send_message(msgerr, 3, mtext);
1196 if (rc == -1) {
1197 severe
1198 ("msgsnd failed: %d msgid %d mtyp %d mtext %d\n",
1199 errno, msgerr, 3, mtext);
1200 exit(1);
1201
1202 }
1203 }
1204 exit(0);
1205 }
1206 #ifdef __64LDT__
1207 else if (pid > (pid_t) 0) {
1208 #else
1209 else if (pid > 0) {
1210 #endif
1211 set_signals((void *)cleanup); /* set up signal handlers and initialize pgrp */
1212 messenger(); /* receives and acts upon messages */
1213 exit(1);
1214 } else {
1215 perror("fork failed");
1216 fprintf(stderr,
1217 " SEVERE : fork failed, exiting with errno %d\n",
1218 errno);
1219 exit(1);
1220 }
1221 }
1222
1223 /* main */
1224 int main(int argc, char *argv[])
1225 {
1226 extern Pinfo *shmaddr; /* start address of shared memory */
1227
1228 prtln();
1229 getenv_val(); /* Get and initialize all environment variables */
1230 prtln();
1231
1232 if (argc < 2) {
1233 fprintf(stderr,
1234 "usage: %s [-b number] [-d number] [-t number] \n",
1235 argv[0]);
1236 fprintf(stderr, "where:\n");
1237 fprintf(stderr,
1238 "\t-b number\tnumber of children each parent will spawn ( > 1)\n");
1239 fprintf(stderr, "\t-d number\tdepth of process tree ( > 1)\n");
1240 fprintf(stderr, "\t-t\t\tset timeout value\n");
1241 fprintf(stderr, " SEVERE : Command line parameter error.\n");
1242 exit(1);
1243 }
1244
1245 parse_args(argc, argv); /* Get all command line arguments */
1246 dprt("value of BVAL = %d, value of DVAL = %d\n", BVAL, DVAL);
1247 nodesum = sumit(BVAL, DVAL);
1248 #ifdef _LINUX
1249 if (nodesum > 250) {
1250 printf("total number of process to be created "
1251 "nodesum (%d) is greater\n than the allowed "
1252 "SEMMSL value (250)\n", nodesum);
1253 printf("reseting the value of nodesum to SEMMSL\n");
1254 nodesum = 250;
1255 }
1256 #endif
1257
1258 dprt("value of nodesum is initiallized to: %d\n", nodesum);
1259
1260 prtln();
1261 setup_shm(); /* Set up, allocate and initialize shared memory */
1262 prtln();
1263 setup_semaphores(); /* Set up, allocate and initialize semaphores */
1264 prtln();
1265 setup_msgqueue(); /* Set up, allocate and initialize message queues */
1266 prtln();
1267
1268 doit(); /* spawn off processes */
1269 prtln();
1270 return 0;
1271
1272 }
1273