fork(2)

System call

Duplicates the calling process. The child gets a copy of the memory and of the open descriptors, and the return value tells which one is which.

Synopsis
#include <unistd.h>
pid_t fork(void);

Description

fork creates a new process, the child, by copying the one that calls it, the parent. When the call returns, both run the rest of the same program. The child has its own PID, and its parent is the process that called fork.

Memory is copied: variables, stack, heap, and also the printf buffers that have not been flushed yet. Linux only really copies a page when one of the two processes modifies it (copy-on-write), which keeps the call fast. File descriptors are duplicated too, but each one refers to the same open file as in the parent, with the same read or write offset: that is what lets a parent and a child share a pipe.

Return value

fork returns twice, once in each process:

ValueIn which process
0the child
the child's PID, positivethe parent
-1the parent alone: no child was created, and errno says why

The usual causes of failure are EAGAIN (the process limit was reached) and ENOMEM (not enough kernel memory).

Pitfalls

  • Nothing guarantees whether the parent or the child runs first. A program that depends on an order has to synchronize, with waitpid or a pipe.

  • A printf called before fork can show up twice when output goes to a pipe or a file: the unflushed buffer is copied into the child. Call fflush(stdout) right before fork.

  • A child that has finished stays a zombie until the parent waits for it with wait or waitpid.

  • In a loop, forgetting to leave the child (with exit or a return) means the child keeps looping and creates processes of its own.

Example

copy.c
#include <stdio.h>#include <sys/wait.h>#include <unistd.h>
int main(void){    int x = 1;    pid_t pid = fork();
    if (pid == -1) {        perror("fork");        return 1;    }    if (pid == 0) {        x = 42;        printf("child: x = %d\n", x);        return 0;    }    waitpid(pid, NULL, 0);    printf("parent: x = %d\n", x);    return 0;}
Terminal
$ gcc -Wall -Wextra copy.c -o copy$ ./copychild: x = 42parent: x = 1

The child modifies its copy of x; the parent's copy has not moved. The parent waits for the child before printing, which fixes the order of the two lines.

C

process_stream_open

Write process_stream_open, which forks a child to run a command with execvp and hands the parent one end of a pipe, without waiting for the child.

Open the exercise

Now write it yourself.