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