Search code examples
cforkexecposixwait

Execl() in a child process and wait() in the parent process


I don't understand why the parent process continues executing even if his child process didn't terminate.

This is a.c:

if (!fork()){
    execl("/bin/sh", "sh", "-c", "gnome-terminal -x ./b", (char *) 0);
}
else {

    int status;
    wait(&status);
    if ((status & 255) == 0) printf("\nProcess regularly exited ");
    printf("adios");
    return 0;
}

and this is b.c:

printf("hello\n");
fflush(0);
getchar();
exit(0);

It happens that the parent process prints "process regularly exited" and "adios" when the child process hasn't terminated and it is waiting for input by getchar() ,and I don't understand why.

Finally ,how can I force the parent process to wait until the execution of b.c is completed?


Solution

  • Converting comments into an answer.

    One key question when facing a C program that doesn't work as you expect when executing another is 'what happens in the shell'. For this question, that translates to: When you run sh -c "gnome-terminal …" from the command line, how long does it take before you get the prompt back?

    It is instantly.

    So — surprise, surprise — the same thing happens when you run it from your C code. The shell of the sh -c … exits promptly, so your parent process spots its death and exits. I think your second program is run as a grandchild or great-grandchild of the process you fork off. You have sh, which runs gnome-terminal, which probably forks and the parent exits while the child goes on to manage the terminal and fork a shell that runs your second command (or maybe doesn't use a shell and simply executes your second command). A process can only wait for its direct children to die; it can't wait for its children's children or more distant descendants.

    Now if I add while(1){} at the end of a.c before return 0, and at the end of b.c before exit(0), the top command indicates that I have 4 processes: 2 of a.c and 2 of b.c. Isn't it strange?

    There are multiple things that could be going on. It could be leftover processes from previous runs. You'd need to look at the process trees to know if those processes are related and how they're related.

    Thank you they were simply leftover processes.

    Finally, how can I force the parent process to wait until the execution of b.c is completed?

    Succinctly, you can't make A wait for B to finish. You'd need a way for A to know which process is the B that it should wait for. It can't wait directly for it because B is not its own child, so you'd probably end up doing some polling operation to see if B is still around. That might be testing with kill() and signal 0; on Linux, you might be able to play with iNotify on the /proc file system (and avoid polling).