C Programming – How Fork System Call Really Works

cforksystem-calls

I've a very specific question about fork system call. I've this piece of code:

int main (void) 
{
    for (int i = 0; i < 10; i++) {
        pid_t pid = fork ();

        if ( !pid ) {
            printf("CHILD | PID: %d, PPID: %d\n", getpid(), getppid());
            _exit(i + 1);
        }

    }

    for (int i = 0; i < 10; i++) {
        int status;
        waitpid(-1, &status, 0);

        if (WIFEXITED(status)) {
            printf("IM %d AND CHILD WITH EXIT CODE %d TERMINATED\n",
                    getpid(), WEXITSTATUS(status));

        } 
        else {
            printf("ERROR: CHILD NOT EXITED\n");
        }
    }

    return 0;
}

which produces this output:

CHILD | PID: 3565, PPID: 3564
CHILD | PID: 3566, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 1 TERMINATED
IM 3564 AND CHILD WITH EXIT CODE 2 TERMINATED
CHILD | PID: 3573, PPID: 3564
CHILD | PID: 3567, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 9 TERMINATED
IM 3564 AND CHILD WITH EXIT CODE 3 TERMINATED
CHILD | PID: 3568, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 4 TERMINATED
CHILD | PID: 3569, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 5 TERMINATED
CHILD | PID: 3570, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 6 TERMINATED
CHILD | PID: 3571, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 7 TERMINATED
CHILD | PID: 3572, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 8 TERMINATED
CHILD | PID: 3574, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 10 TERMINATED

which makes me wonder how fork really works and what code new processes really execute. Looking at the above output results, I can not understand:

  1. How does second for cycle prints before first for finish all iterations? I've also noticed this second for is always executed by parent process, which makes me wonder if while on first for cycle, if pid != 0 (which means parent process calling) second for cycle is executed (?)
  2. Why does CHILD processes are not sorted printed by PID?

So, bottom line, how does fork really works and who executes what?

Best Answer

When you fork, the kernel creates a new process which is a copy of the forking process, and both processes continue executing after the fork (with the return code showing whether an error occurred, and whether the running code is the parent or the child). This “continue executing” part doesn’t necessarily happen straight away: the kernel just adds the new process to the run queue, and it will eventually be scheduled and run, but not necessarily immediately.

This explains both behaviours you’re asking about:

  • since new processes aren’t necessarily scheduled immediately, the parent might continue running before any child gets a chance to run;
  • creation order doesn’t have much (if any) impact in the run queue, so there’s no guarantee the child processes will run in the order they’re created.