Sunday, September 14, 2014

Unix Prog: Wait for Process -- wait, waitpid

1. wait, waitpid

Whenever a child process is terminated, the kernel will send one asynchronous signal to the parent process. The parent process can choose to :
1) ignore the signal
2) provide the signal handler

By calling wait, waitpid, the parent process can:
1) block if all of its child processes are still running
2) return immediately with the termination status of the child, if a child has terminated and is waiting for its termination status to be fetched.
3) return immediately with the error, if the parent process doesn't have any child processes.

Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/wait.h  
 ......  
 # define WEXITSTATUS(status)  __WEXITSTATUS (__WAIT_INT (status))  
 # define WTERMSIG(status)    __WTERMSIG (__WAIT_INT (status))  
 # define WSTOPSIG(status)    __WSTOPSIG (__WAIT_INT (status))  
 # define WIFEXITED(status)   __WIFEXITED (__WAIT_INT (status))  
 # define WIFSIGNALED(status)  __WIFSIGNALED (__WAIT_INT (status))  
 # define WIFSTOPPED(status)   __WIFSTOPPED (__WAIT_INT (status))  
 # ifdef __WIFCONTINUED  
 # define WIFCONTINUED(status) __WIFCONTINUED (__WAIT_INT (status))  
 # endif  
 ......  
 #ifdef __USE_BSD  
 # define WCOREFLAG       __WCOREFLAG  
 # define WCOREDUMP(status)   __WCOREDUMP (__WAIT_INT (status))  
 # define W_EXITCODE(ret, sig)  __W_EXITCODE (ret, sig)  
 # define W_STOPCODE(sig)    __W_STOPCODE (sig)  
 #endif  
   
 /* Wait for a child to die. When one does, put its status in *STAT_LOC  
   and return its process ID. For errors, return (pid_t) -1.  
   
   This function is a cancellation point and therefore not marked with  
   __THROW. */  
 extern __pid_t wait (__WAIT_STATUS __stat_loc);  
 ......  
 /* Wait for a child matching PID to die.  
   If PID is greater than 0, match any process whose process ID is PID.  
   If PID is (pid_t) -1, match any process.  
   If PID is (pid_t) 0, match any process with the  
   same process group as the current process.  
   If PID is less than -1, match any process whose  
   process group is the absolute value of PID.  
   If the WNOHANG bit is set in OPTIONS, and that child  
   is not already dead, return (pid_t) 0. If successful,  
   return PID and store the dead child's status in STAT_LOC.  
   Return (pid_t) -1 for errors. If the WUNTRACED bit is  
   set in OPTIONS, return status for stopped children; otherwise don't.  
   
   This function is a cancellation point and therefore not marked with  
   __THROW. */  
 extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options);  
 ......  

2. wait example
proc.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<sys/wait.h>  
 #include<unistd.h>  
   
 void pr_exit(int status)  
 {  
  if(WIFEXITED(status)) {  
   printf("normal termination: exit status = %d\n", WEXITSTATUS(status));  
  }  
  else if(WIFSIGNALED(status)) {  
   printf("abnormal termination: exit status = %d%s\n",  
       WTERMSIG(status), WCOREDUMP(status)? "(core file generated)" : "");  
  }  
  else if (WIFSTOPPED(status)) {  
   printf("child stopped, signal number = %d\n", WSTOPSIG(status));  
  }  
 }  
   
 int main(int argc, char* argv[])  
 {  
  pid_t pid;  
  int status;  
   
  // Launch the first child  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(1);  
  }  
  else if (pid == 0)  
   exit(7);  
   
  // Fetch the termination status of first child  
  if(wait(&status) != pid) {  
   printf("wait error!\n");  
   exit(2);  
  }  
  pr_exit(status);  
   
  // Launch the second child  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(1);  
  }  
  else if(pid == 0)  
   abort();  // Generate the SIGABRT  
   
  // Fetch the termination status of the second child  
  if(wait(&status) != pid) {  
   printf("wait error!\n");  
   exit(2);  
  }  
  pr_exit(status);  
   
  // Launch the third child  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(1);  
  }  
  else if(pid == 0)  
   status /= 0; // Generate the SIGFPE  
   
  // Fetch the termination status of third child  
  if(wait(&status) != pid) {  
   printf("wait error!\n");  
   exit(2);  
  }  
  pr_exit(status);  
   
  exit(0);  
 }  

shell:
 ubuntu@ip-172-31-23-227:~$ ./proc.out  
 normal termination: exit status = 7  
 abnormal termination: exit status = 6(core file generated)  
 abnormal termination: exit status = 8(core file generated)  

3. waitpid example:

waitflags definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/waitflags.h  
 ......  
 /* Bits in the third argument to `waitpid'. */  
 #define WNOHANG     1    /* Don't block waiting. */  
 #define WUNTRACED    2    /* Report status of stopped children. */  
 ......  

proc.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<sys/wait.h>  
   
 int main(int argc, char* argv[])  
 {  
  pid_t pid;  
   
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(1);  
  }  
  else if (pid == 0) {  
   /* first child process */  
   if ((pid = fork()) < 0) {  
    printf("fork error!\n");  
    exit(1);  
   }  
   else if (pid > 0) {  
    sleep(1);  
    printf("first child output!\n");  
    exit(0); // exit from first child process  
   }  
   
   // 2nd child process sleep for 2 seconds to let 1st  
   // child process exit, at this time, its parent process  
   // becomes "init" (process id: 1)  
   sleep(2);  
   printf("second child, parent pid = %d\n", getppid());  
   exit(0);  
  }  
   
  // Original Process: Wait for process id of first child  
  // Since first child will sleep for 1 second, and we don't setup  
  // WNOHANG flag as 3rd argument, so it will just block here to wait  
  // for first child  
  printf("before waitpid:\n");  
  if(waitpid(pid, NULL, 0) != pid) {  
   printf("waitpid error!\n");  
   exit(2);  
  }  
  printf("after waitpid:\n");  
   
  exit(0);  
 }  

shell:
 ubuntu@ip-172-31-23-227:~$ ./proc.out  
 before waitpid:  
 first child output!  
 after waitpid:  
 ubuntu@ip-172-31-23-227:~$ second child, parent pid = 1  

No comments:

Post a Comment