forknwait.c

/**
   @file      forknwait.c
   @author    Mitch Richling <http://www.mitchr.me/>
   @Copyright Copyright 1995 by Mitch Richling.  All rights reserved.
   @brief     UNIX group queries@EOL
   @Keywords  fork wait UNIX
   @Std       ISOC POSIX UNIX98 BSD4.3 SYSV3

              This C program is intended to illustrate how to fork a
              process and how to wait for the child.  How to wait for
              the child is much more involved than simply calling the
              wait system call.  This is because the wait call can
              return for many reasons.
              
              To make applications more portable it is preferable not
              to use our special knowledge of the high/low order 8 bit
              quantities in the 16 bit return from wait.  Instead we
              can use the POSIX macros to do the same thing.  I have
              sprinkled comments in the code discussing the do-it
              yourself methods and the POSIX methods.

   @Tested    
              - Solaris 2.8
              - MacOS X.2
              - Linux (RH 7.3)
*/

#include <stdio.h>              /* I/O lib         ISOC  */
#include <string.h>             /* Strings         ISOC  */
#include <sys/types.h>          /* UNIX types      POSIX */
#include <unistd.h>             /* UNIX std stf    POSIX */
#include <errno.h>              /* error stf       POSIX */
#include <stdlib.h>             /* Standard Lib    ISOC  */
#include <sys/wait.h>           /* UNIX wait       POSIX */

int main(int argc, char *argv[]);

int main(int argc, char *argv[]) {
  pid_t parentPID, wPID, childPID;
  int i, whyWait, mustWait, unknownFail;

  /* Get the PID */
  parentPID = getpid();
  printf("PARENT: Process ID: %ld\n", (long)parentPID);

  childPID = fork();
  printf("PARENT: fork returned: %ld\n", (long)childPID);
  if(childPID) {                /* Parent */
    printf("PARENT: I'm still running after the fork.\n");
    if(childPID == -1) {
      printf("ERROR: The fork was not successful.\n");
      exit(2);
    } /* end if */
    printf("PARENT: My child's PID: %ld.\n", (long)childPID);

    /* We wait for the child to quit.  This is not as simple as just
       calling the wait(2) system call, because the wait call can return
       for many reasons.  */
    unknownFail = 0;
    mustWait = 1;
    do {
      wPID = wait(&whyWait);
      printf("PARENT: wait has returned(%ld).\n", (long)wPID);
      if(wPID == -1) {
        if(errno == ECHILD) {   /* My babies are all dead! */
          mustWait = 0;
        } else if(errno == EINTR) {     /* I was sent a signal. */
          printf("PARENT: received a signal.  Continuing.\n");
        } else {
          printf("PARENT: WARNING: unknown wait failure.\n");
          unknownFail++;
        } /* end if/else */
      } else {
        if(wPID == childPID) {  /* This is my baby. */
          if(WIFSTOPPED(whyWait)) {     /* STOPed my baby. */
            printf("PARENT: child was stopped with signal %d", (int)WSTOPSIG(whyWait));
          } else if(WIFEXITED(whyWait)) {       /* My baby died a natural death. */
            printf("PARENT: child exited with %d.\n", (int)WEXITSTATUS(whyWait));
            mustWait = 0;
          } else if(WIFSIGNALED(whyWait)) {     /* My baby was killed. */
            printf("PARENT: child was killed by signal %d.\n", (int)WTERMSIG(whyWait));
            if(WCOREDUMP(whyWait))
              printf("PARENT: child dumped core\n");
            else
              printf("PARENT: child did not dump core\n");
            mustWait = 0;
          } else {              /* We don't know why wait() returned.  This should not happen. */
            printf("PARENT: WARNING: wait failure(unknown status).\n");
            unknownFail++;
          } /* end if/else */
        } else {                /* wait() reports a pid that is not my child. */
          printf("PARENT: WARNING: wait failure(unknown child).\n");
          unknownFail++;
        } /* end if/else */
      } /* end if/else */
    } /* end do */
    while(mustWait && (unknownFail < 10));
    if(mustWait == 0)
      printf("PARENT: normal exit because child has gone away.\n");
    else
      printf("PARENT: exit because of repeated, unknown failures of wait(2).\n");
  } else {                      /* Child */
    printf("CHILD:  I'm running.\n");
    printf("CHILD:  Process ID: %ld\n", (long)getpid());
    printf("CHILD:  Process Group ID: %ld\n", (long)getpgrp());
    printf("CHILD:  I'm going to sleep for 10 seconds now.\n");
    for(i = 10; i > 0; i--) {
      printf("CHILD: Count down: %d\n", i);
      sleep(1);
    } /* end for */
    printf("CHILD:  I'm done sleeping.\n");
    printf("CHILD:  forknwait shutdown.\n");
  } /* end if/else */

  return (0);
} /* end func main */

Generated by GNU Enscript 1.6.5.2.