How to properly fork() a process

1.6k views Asked by At

I'm trying to understand how to properly used fork() and execvp() to execute a command. So far I have the following code:

When I run ./test vim myFile.c it correctly opens myFile.c but I get strange behavior. It seems as though there are two processes running because whenever I enter anything it seems to happen twice. Why is this?

int main (int argc, char* argv[]) {
   int fdin, pid, w, status; 
   fdin = 0;                                                                   
   if ((pid = fork()) < 0)                                                     
       errorExit (EXIT_FAILURE);                                                                                                                              
   execvp(argv[0],argv);  

   do {
      w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
      if (w == -1) {
          perror("waitpid");
          exit(EXIT_FAILURE);
      }

     if (WIFEXITED(status)) {
          printf("exited, status=%d\n", WEXITSTATUS(status));
      } else if (WIFSIGNALED(status)) {
          printf("killed by signal %d\n", WTERMSIG(status));
      } else if (WIFSTOPPED(status)) {
          printf("stopped by signal %d\n", WSTOPSIG(status));
      } else if (WIFCONTINUED(status)) {
          printf("continued\n");
      }
  } while (!WIFEXITED(status) && !WIFSIGNALED(status))
}
3

There are 3 answers

3
David Ding On BEST ANSWER

When you call fork(), you create two almost completely identical processes, the parent process and the child process. The only difference between these two processes is the return value of fork(), which returns 0 to the child process and the pid of the child to the parent.

Hence, assuming fork succeeded, fork will return a nonnegative integer to both the parent and child process in line 4. Then, both the parent and child process will execute line 6, the execvp, and hence, you end up with two different processes running your vim myFile.c, causing all the problems you described.

The standard idiom is something like:

if ((pid = fork()) < 0) {
    // Handle fork error
}
else if (pid == 0) {
    // Child process
    execvp(...);
}
else {
    // Parent process
    w = waitpid(pid, ...);
}

Since the return value for fork is 0 for the child, after fork succeeds, the test (pid == 0) will be true for the child, so execvp will be called.

For the parent, fork returns the pid of the child, so the check (pid == 0), which still get executed, is false, so the else condition is executed, causing the parent to wait for the child.

1
abyss.7 On

Both parent and child in your program get execvp():

if ((pid = fork()) < 0)
    errorExit (EXIT_FAILURE);
execvp(argv[0],argv);

You should check, if you are in parent with pid != 0, and if you are in child otherwise.

0
Henrik Carlqvist On

You should look at the return value of fork, after a successful fork you will have two running processes at the same position in your program. The child process will get a return value of 0, the parent will get a return value which is the pid of the child. Most likely you want to do different things in the child process and the parent process.

You might also want to think again about how execvp is called. Do you really want to give "./test" as the first argument to execvp?