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