5.5 Program Examples

Example 5-1 shows the basic procedures for executing an image in a child process.

The child process in Example 5-1 prints a message 10 times.

Example 5-1 Creating the Child Process

/*  This example creates the child process.  The only     *
 *  functionality given to the child is the ability to    *
 *  print a message 10 times.                             *
 *                                                        *
 *    PARENT:                                             */

#include <climsgdef.h>        /* CLI status values        */
#include <stdio.h>
#include <perror.h>
#include <processes.h>

main()
{
   int status, cstatus;

    if ((status = vfork()) != 0)
      {
          if (status < 0)
            printf("Parent - Child process failed\n");
         else
            {
               printf("Parent - Waiting for Child\n");
                if ((status = wait(&cstatus)) == -1)
                  perror("Parent - Wait failed");
               else
                   if (cstatus == CLI$_IMAGEFNF)
                     printf("Parent - Child does not \
exist\n");

               else
                     printf("Parent - Child final \
status: %d\n", cstatus);

            }
      }
    else
      {
         printf("Parent - Starting Child\n");
         if ((status = execl("child", 0)) == -1)
            {
               perror("Parent - Execl failed");
               _exit();
            }
      }
}
/*  This is a program separate from the parent process.   *
 *                                                        *
 *  CHILD:                                                *
 *                                                        */

main()
{
   int i;

   for (i=0; i < 10; i++)
      printf("Child - executing\n");
}

Key to Example 5-1:

  1. The vfork function is called to set up the return address for the exec call.

    The vfork function is normally used in the expression of an if statement. This construct allows you to take advantage of the double return aspect of vfork, since one return value is 0 and the other is nonzero.

  2. A 0 return value is returned the first time vfork is called and the parent executes the else clause associated with the vfork call, which calls execl.

  3. A negative child process ID is returned when an exec function fails. The return value is checked for these conditions.

  4. The wait function is used to synchronize the parent and child processes.

  5. Since the exec functions can indicate success up to this point even if the image to be activated in the child does not exist, the parent checks the child's return status for the predefined status, CLI$_IMAGEFNF (file not found).

In Example 5-2, the parent passes arguments to the child process.

Example 5-2 Passing Arguments to the Child Process

/*  In this example, the arguments are placed in an array,     *
 *  gargv, but they can be passed to the child                 *
 *  explicitly as a zero-terminated series of character        *
 *  strings. The child program in this example writes          *
 *  to stdout the arguments that have been passed to it.       *
 *                                                             *
 *     PARENT:                                                 *
 *                                                             */

#include <climsgdef.h>
#include <stdio.h>
#include <perror.h>
#include <processes.h>

main()
{
   int status, cstatus;
   char *gargv[] = { "Child", "ARGC1", "ARGC2", "Parent", 0 };

   if ((status = vfork()) != 0)
      {
         if (status < -1)
            printf("Parent - Child process failed\n");
         else
            {
               printf("Parent - waiting for Child\n");
               if ((status = wait(&cstatus)) == -1)
                  perror("Parent - Wait failed");
               else
                  if (cstatus == CLI$_IMAGEFNF)
                     printf("Parent - Child does not exist\n");
                  else
                     printf("Parent - Child final status: %x\n",
                             cstatus);
            }
      }
   else
      {
         printf("Parent - Starting Child\n");
         if ((status = execv("Child", gargv)) == -1)
            {
               perror("Parent - Exec failed");
               _exit();
            }
      }
}

/*  This is a program separate from the parent process.        *
 *                                                             *
 *  CHILD:                                                     *
 *                                                             */

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

   printf("Program name: %s\n", argv[0]);

   for (i = 1; i < argc; i++)
      printf("Argument %d: %s\n", i, argv[i]);
}

Example 5-3 shows how to use the wait function to check the final status of multiple children being run simultaneously.

Example 5-3 Checking the Status of Child Processes

/*  In this example, the wait function is placed in a separate *
 *  for loop so that it is called once for each child. If      *
 *  wait were called within the first for loop, the parent     *
 *  would wait for one child to terminate before executing the *
 *  next child.  If there were only one wait request, any      *
 *  child still running when the parent exits would terminate  *
 *  prematurely.                                               *
 *                                                             *
 *     PARENT:                                                 *
 *                                                             */

#include <climsgdef.h>
#include <stdio.h>
#include <perror.h>
#include <processes.h>

main()
{
   int status, cstatus, i;

   for (i = 0; i < 5; i++)
      {
         if ((status = vfork()) == 0)
            {
               printf("Parent - Starting Child %d\n", i);
               if ((status = execl("child", 0)) == -1)
                  {
                     perror("Parent - Exec failed");
                     _exit();
                  }
            }
         else
            if (status < -1)
               printf("Parent - Child process failed\n");
      }

   printf("Parent - Waiting for children\n");

   for (i = 0; i < 5; i++)
      {
         if ((status = wait(&cstatus)) == -1)
            perror("Parent - Wait failed");
         else
            if (cstatus == CLI$_IMAGEFNF)
               printf("Parent - Child does not exist\n");
            else
               printf("Parent - Child %X final status: %d\n",
                       status, cstatus);
      }
}

/*  This is a program separate from the parent process.        *
 *                                                             *
 *  CHILD:                                                     *
 *                                                             */

main()
{
   int pid, i;

   printf("Child %0X: working...\n", (pid = getpid()));
   sleep(5);
   printf("Child %0X: Finished\n",pid);
}

Example 5-4 shows how to use the pipe and dup2 functions to communicate between a parent and child process through specific file descriptors. The #define preprocessor directive defines the preprocessor constants inpipe and outpipe as the names of file descriptors 11 and 12.

Example 5-4 Communicating Through a Pipe

/*  In this example, the parent writes a string to the pipe    *
 *  for the child to read.  The child then writes the string   *
 *  back to the pipe for the parent to read.  The wait         *
 *  function is called before the parent reads the string that *
 *  the child has passed back through the pipe.  Otherwise,    *
 *  the reads and writes will not be synchronized.             *
 *                                                             *
 *     PARENT:                                                 *
 *                                                             */

#include <perror.h>
#include <climsgdef.h>
#include <stdio.h>
#include <processes.h>
#include <unixio.h>
#define inpipe 11
#define outpipe 12

main()
{
   int pipes[2];
   int mode, status, cstatus, len;
   char *outbuf, *inbuf;

   if ((outbuf = malloc(512)) == 0)
      {
         printf("Parent - Outbuf allocation failed\n");
         exit();
      }

   if ((inbuf = malloc(512)) == 0)
      {
         printf("Parent - Inbuf allocation failed\n");
         exit();
      }
   if (pipe(pipes) == -1)
      {
         printf("Parent - Pipe allocation failed\n");
         exit();
      }

   dup2(pipes[0], inpipe);
   dup2(pipes[1], outpipe);
   strcpy(outbuf, "This is a test of two-way pipes.\n");

   status = vfork();

   switch (status)
      {
         case 0:
            printf("Parent - Starting child\n");
            if ((status = execl("child", 0)) == -1)
               {
                   printf("Parent - Exec failed");
                   _exit();
               }
            break;

         case -1:
            printf("Parent - Child process failed\n");
            break;

         default:
            printf("Parent - Writing to child\n");

            if (write(outpipe, outbuf, strlen(outbuf)+1)
                 == -1)
               {
                  perror("Parent - Write failed");
                  exit();
               }
            else
               {
                  if ((status = wait(&cstatus)) == -1)
                     perror("Parent - Wait failed");

                  if (cstatus == CLI$_IMAGEFNF)
                     printf("Parent - Child does not exist\n");
                  else
                     {
                        printf("Parent - Reading from child\n");
                        if ((len = read(inpipe, inbuf, 512))
                            <= 0)
                           {
                              perror("Parent - Read failed");
                              exit();
                           }
                        else
                           {
                              printf("Parent: %s\n", inbuf);
                              printf("Parent - Child final \
status: %d\n", cstatus);
                           }
                     }
               }
            break;
      }
}

/*  This is a program separate from the parent process.        *
 *                                                             *
 *  CHILD:                                                     *
 *                                                             */

#define inpipe 11
#define outpipe 12

main()
{
   char *buffer;
   int len;

   if ((buffer = malloc(512)) == 0)
      {
         perror("Child - Buffer allocation failed\n");
         exit();
      }

   printf("Child - Reading from parent\n");
   if ((len = read(inpipe, buffer, 512)) <=0)
      {
         perror("Child - Read failed");
         exit();
      }
   else
      {
         printf("Child: %s\n", buffer);
         printf("Child - Writing to parent\n");
         if (write(outpipe, buffer, strlen(buffer)+1) == -1)
            {
               perror("Child - Write failed");
               exit();
            }
      }
}


Previous Page | Next Page | Table of Contents | Index