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