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