CS 3733 Operating Systems Notes: Fork, Wait, and Exec



fork:

   #include <sys/types.h>
   #include <unistd.h>

   pid_t fork(void);
return -1 if error
return 0 to child
return child's pid to parent

Example 2.3, Page 44: What is the value of x for each process?
Example 2.4, Page 44: Parent and child print different messages
Example 2.5, Pages 44-45: a chain of processes, parent always breaks
Example 2.6, Page 45: a fan of processes, the child breaks
Example 2.7: page 46: a tree, only break on error


Problem from Spring 2001 Final Exam:
Trace the following program segment and determine how many processes are created. Assume that no errors occur. Draw a graph that shows how the processes are related. In this graph each process will be represented by a small circle containing a number that represents which fork created the process. The original process will contain 0 and the process created by the first fork will contain 1. There will be arrows from each parent to all of its children. Each arrow should point in a downward direction.

   c2 = 0;
   c1 = fork();      /* fork number 1 */
   if (c1 == 0)
      c2 = fork();   /* fork number 2 */
   fork();           /* fork number 3 */
   if (c2 > 0)
      fork();        /* fork number 4 */


wait:

   #include <sys/types.h>
   #include <sys/wait.h>

   pid_t wait(int *stat_loc);
   pid_t waitpid(pid_t pid, int *stat_loc, int options);
wait:
If a child terminated, return its pid
Otherwise return -1 and set errno

waitpid:
Allows you to wait for a particular process, or all process if pid is -1. Important option is NOHANG which will return 0 if there is a specified child to wait for but it has not yet terminated.

Important values of errno:
ECHILD no unwaited for children
EINTR a signal was caught

The status value is 0 if and only if the process terminated normally and returned 0. In all other cases the status should be examined using the provided macros defined in sys/wait.h.
Example 2.8 on pages 48 and 49 illustrate the use of these.

Example 2.9. Page 50: Wait until a particular child finishes:
while (childpid != wait(&status)) ;

Example 2.10, page 51: The correct way to wait for a particular child:

   while (childpid != wait(&status))
      if ((childpid == -1) && (errno != EINTR) )
         break;
Example 2.11, Page 51: Wait without blocking for all children that have finished:
while(waitreturnpid = waitpid(-1, &status, WNOHANG))
   if (!((waitreturnpid == -1) && (errno != EINTR)))
      break;
Exercise 2.4, page 52: A process fan like in Example 2.6.
Each child returns from wait immediately
Parent only returns after all children are done
Parent's message is output last.

Exercise 2.5, pages 52-53: A process chain like in Example 25.
Each process waits for its child before printing.
The messages appear in reverse order of process creation.


exec

  #include <unistd.h>

  int execl(const char *path, const char *arg0, ...,
            const char *argn, char * /*NULL*/);
  int execlp (const char *file, const char *arg0, ...,
            const char *argn, char * /*NULL*/);
  int execle (const char *path,char *const arg0, ... ,
            const char *argn, char * /*NULL*/,
            char *const envp[]);

  int execv(const char *path, char *const argv[]);
  int execvp (const char *file, char *const argv[]);
  int execve (const char *path, char *const argv[],
        char *const envp[]);
The execl forms take a variable number of parameters with a NULL-terminated list of command line arguments.
The execv forms take an argv array which can be created with makeargv.

The p forms use the PATH environment variable to search for the executable.
The e forms allow you to set the environment of the new process rather than inheriting it from the calling process.

Program 2.6 from Pages 53-54 show a program that creates a child to execute ls -l.