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