How do I use Fork, WAITPID & EXECL in Linux with C Program

If you want to create the new process to do some other task without disturbing your current process then probably you need to create new process or thread which can solve your purpose. It is always difficult to choose process or thread. The fork is used to create the new child process.  Remember if you are creating the new process. The value of variable could be different in both the processes (Parent & Child) because child & parent process will have the separate resource to work on.

pid_t pid;
pid = fork();

once the fork is successful means if a child process is created successfully then it fork will return the child process id. after fork system will have two processes.

  • Parent Process
  • Child Process

You can get child PID (process id) in a parent. but to get the parent PID you can use getpid() method to know the parent process id. getppid() is used to get the grand parent process it.
Whatever statement you are executing after fork that will be executed twice if it falls under both the process. because after fork system have two different processes. In child process PID is equal to 0.  Now both the processes child and parent will run independently. exit & _exit can be used at the end of a child process to terminate the execution. exit() will remove the resource occupied by the process properly. So it is preferred to use exit() rather than _exit();

if you are planning to use execl()  or any of exe family function then be careful about it use. execl will replace your process with a new process. It will not return if successful. If execl fails then it will return -1.

At any stage, you can get the error code or errno using errno system variable by including errno.h header. If you are not getting the prints, which you are trying to print then just add \n at the end of your printf statements or use fflush() to flush the buffer. I hope it will solve your problem.

waitpid:

waitpid is used get the status of the child process. It may possible that your child process stuck in between and terminated abnormally.  There could be many reason where you want to confirm the status of your child process. In such cases you need to use waitpid function call to get the status.

waitpid (pid, &status, Options);
waitpid has three arguments:


1: process id of the child process for which you want to get the status.
2: status of the child process will be reflected here
3: Third option specifies the flow. 

If you specify 0 as the third argument then it means that your parent process will wait till your child process finish its job. It is equal to use wait function.  If you use WNOHANG as the third argument then it means your parent and child process will run in parallel. The parent will not wait for child process to finish.  if waitpid fails the it returns -1. Here also you can use errno to get the exact reason for failure.

To readout the child process status it is necessary to convert the process to become zombie process after termination of the process. So once child process is terminated then it is converted to zombie process. In zombie process means, all the resource related to terminated process will not freed till call to waitpid is made. Some of the information related to process is still made available in process table to get out.  You should not to handle SIGCHLD signal to convert the process to become zombie. 

    #include  <sys/types.h>
    #include "errno.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "sys/wait.h"
    #include "unistd.h"
    #define   MAX_COUNT  5
    int k = 10;
    int childStatus;
    void  ChildProcess(void);                /* child process prototype  */
    void  ParentProcess(pid_t  *pid);               /* parent process prototype */
    void  main(void)
    {
         pid_t  pid;
         pid = fork();
         printf("forked child pid %d \n",pid);
         if (pid == 0)
         {
            ChildProcess();
            exit(5);
         }
         else if (pid > 0)
         {
             
               ParentProcess(&pid);
         }
         else
            printf("FAILED \n");
    }
    void  ChildProcess(void)
    {
         int   i;
         //execl("/usr/bin/find","find",(char *)NULL) ;
         execl("/bin/ls","ls",(char *)NULL) ;
         for (i = 1; i <= MAX_COUNT; i++)
         {   
        printf("   This line is from child, value = %d\n", i);
            sleep(2);
         }
         printf("   *** Child process is done ***\n");
         k = 15;
    }
    void  ParentProcess(pid_t  *pid)
    {
         int   i;
        sleep(5);
        pid_t ret = waitpid((*pid),&childStatus,WNOHANG);
        printf("waitpid return value: %d \n", (*pid));
            if(ret > 0)
            {
            printf("SUCCESS %d \n",ret);
                     printf("CHILD STATUS %d \n",childStatus);
            }
       
         for (i = 1; i <= MAX_COUNT; i++)
         {
             printf("This line is from parent, value = %d\n", i);
            //sleep(1);
         }
         printf("*** Parent is done ***\n");
    }

    Other Example:

      #include <errno.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <sys/wait.h>
      #include <unistd.h>
      #include <sys/ptrace.h>
      #include <signal.h>
      void handle_sigchld(int sig) {
        while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {}
      }
      int main(void)
      {
        
          struct sigaction sa;
          sa.sa_handler = SIG_IGN;
          sigemptyset(&sa.sa_mask);
          sa.sa_flags = 0;
          if (sigaction(SIGCHLD, &sa, 0) == -1) {
            perror(0);
            exit(1);
          }
        
          sigset_t blockMask, emptyMask;
        
          /*
          
          //sigemptyset(&sa.sa_mask);
          //sa.sa_flags = 0;
          sa.sa_handler = handle_sigchld;
          if (sigaction(SIGCHLD, &sa, NULL) == -1)
              printf("sigaction");
        
                   
          sigemptyset(&blockMask);
              sigaddset(&blockMask, SIGCHLD);
              if (sigprocmask(SIG_SETMASK, &blockMask, NULL) == -1)
                  printf("sigprocmask");
          */
        
          pid_t Checksum_pid = fork();
          printf("\nChecksum_pid : %d", Checksum_pid);
          if (Checksum_pid < 0)
              printf("Fork Failed\n");
          else if (Checksum_pid == 0)
          {
          printf("\nInside Child Process before execl\n");      
          //execl("/bin/sleep", "/bin/sleep", "2", NULL);
          execl("/bin/ls","ls",(char *)NULL) ;
          //exit(EXIT_FAILURE);
          printf("\nInside Child Process after execl\n");
          exit(EXIT_FAILURE);
          }
          else
          {
              int childStatus = 0xFF00;
          siginfo_t si;    
          printf("\nInside Parent Process");
        
          printf("\nParent Sleep for 5 second\n");  
          sleep(5);
        
          printf("\nchildStatus : %d", childStatus);
          printf("\nstrerror : %s", strerror(errno));
          pid_t returnValue = waitpid(Checksum_pid, &childStatus, WNOHANG);
          //pid_t returnValue = waitid(P_PID, Checksum_pid, &si, WNOHANG | WEXITED);  
          printf("\nreturnValue : %d", returnValue);
              printf("\nchildStatus : %d", childStatus);
          printf("\nstrerror : %s", strerror(errno));
          if (returnValue > 0)
              {
                  if (WIFEXITED(childStatus))
                      printf("\nChild Exit Code: %d\n", WEXITSTATUS(childStatus));
                  else
                      printf("\nChild Exit Status: 0x%.4X\n", childStatus);
              }
              else if (returnValue == 0)
                  printf("\nChild process still running\n");
              else
              {
                  if (errno == ECHILD)
                      printf("\nError ECHILD!!\n");
                  else if (errno == EINTR)
                      printf("\nError EINTR!!\n");
                  else
                      printf("\nError EINVAL!!\n");
              }
          if (WIFEXITED(childStatus)) {
                     printf("exited, status=%d\n", WEXITSTATUS(childStatus));
             } else if (WIFSIGNALED(childStatus)) {
                     printf("killed by signal %d\n", WTERMSIG(childStatus));
             } else if (WIFSTOPPED(childStatus)) {
                     printf("stopped by signal %d\n", WSTOPSIG(childStatus));
             } else if (WIFCONTINUED(childStatus)) {
                     printf("continued\n");
             }
          else{
              perror("waitpid error");
          }
          printf("\nParent: I am about to finish\n");
          }
          return 0;
      }

      Related Post:

      Removing Space from Given String & Different Methods to Count Number of Ones in Given Value

      Booting Sequence for Boot Process in Linux

      How to count number of 1 or set bits in a given number

      What is Segmentation fault ?

      How to Access Private Data Members in C++ without using friend function

      Process Vs Thread 

      How to Add Two Numbers Without Using + Operator in C 

      Overview of Function Pointer in C with Example - What is function pointer & how to use it

      How to Fork child process with waitpid & execl in Linux with c example code

      Share on Google Plus

      About Kapil Thakar

      "I am Kapil Thakar, an Embedded Engineer cum Blogger wants to learn new things. I love to share my knowledge solutions to the problems. Interested in Blogging, Creative-Writing, SEO, Website Creation, Video Making, Editing, Affiliation Programs, Online Making Money."
        Blogger Comment
        Facebook Comment

      0 comments :

      Post a Comment

      Related Posts Plugin for WordPress, Blogger...