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