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