Does waitpid yield valid status information for a child process that has already exited?

c, fork, posix-api, waitpid

Solution

Yes, `waitpid` will work after the child has exited. The OS will keep a child process' entry in the process table (including exit status) around until the parent calls `waitpid` (or another `wait`-family function) or until the parent exits (at which point the status is collected by the `init` process). This is what a "zombie" process is: a process that has exited by is still resident in the process table for exactly this purpose.

The process' entry in the table should go away after the first call to `waitpid`. I suspect the reason that in your example you seem to be able to call `waitpid` twice is simply because `waitpid` will not modify the `status` argument if `pid` no longer exists. So the first call should be working and filling in `status`, and the second call should be returning an error code and not changing `status`. You can verify this by inspecting the return values of the `waitpid` calls and/or using two different `status` variables.

Problem

If I `fork` a child process, and the child process exits before the parent calls `waitpid`, then is the exit status information that is set by `waitpid` still valid? If so, when does it become not valid; i.e., how do I ensure that I can call `waitpid` on the child pid and continue to get valid exit status information after an arbitrary amount of time, and how do I "clean up" (tell the OS that I am no longer interested in the exit status information for the finished child process)? I was playing around with the following code, and it appears that the exit status information is valid for at least a few seconds after the child finishes, but I do not know for how long or how to inform the OS that I won't be calling `waitpid` again: ``` #include <assert.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); if (pid < 0) { fprintf(stderr, "Failed to fork\n"); return EXIT_FAILURE; } else if (pid == 0) { // code for child process _exit(17); } else { // code for parent sleep(3); int status; waitpid(pid, &status, 0); waitpid(pid, &status, 0); // call `waitpid` again just to see if the first call had an effect assert(WIFEXITED(status)); assert(WEXITSTATUS(status) == 17); } return EXIT_SUCCESS; } ```

Original source