How the fork System Call Clones Processes in C
The fork() system call in the C programming language
creates a new process by duplicating the existing calling process in
Unix-like operating systems. This article explains how the operating
system duplicates execution state, manages memory through Copy-on-Write,
distinguishes between the parent and child processes using return
values, and manages system resources during this operation.
The Mechanism of Process Duplication
When a C program invokes fork(), defined in the
<unistd.h> header, the operating system halts the
calling process—known as the parent—and creates a near-identical copy
called the child process. The kernel allocates a new Process Control
Block (PCB) and assigns a unique Process Identifier (PID) to the
child.
The child inherits exact copies of the parent’s execution context, including:
- Virtual memory segments (text/code, initialized data, BSS, heap, and stack)
- CPU register values, including the instruction pointer (program counter)
- Open file descriptors, pointing to the same underlying file table entries
- Environment variables and current working directory
Because the child inherits the instruction pointer, both parent and
child processes resume execution starting from the exact point where
fork() returns, rather than starting from the
main() function.
Differentiating Parent and Child Execution
Although the processes share identical code and state at the moment
of creation, they execute independently. The fork()
function provides a return value that allows the program logic to branch
based on which process is running:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
// Fork failed
perror("fork failed");
return 1;
} else if (pid == 0) {
// Child process
printf("Child process executing. PID: %d\n", getpid());
} else {
// Parent process
printf("Parent process executing. Child PID: %d\n", pid);
}
return 0;
}The system call returns:
0to the child process.- The child's PID (a positive integer) to the parent process.
-1to the parent if process creation fails, settingerrno.
Memory Efficiency via Copy-on-Write (CoW)
Duplicating an entire address space physically in RAM for every
fork() call would be computationally expensive. Modern
operating systems implement an optimization called Copy-on-Write
(CoW).
Instead of creating a physical copy of the parent’s memory pages immediately:
- The kernel copies only the page tables from the parent to the child.
- The physical memory pages are marked as read-only and shared between both processes.
- If either process attempts to modify a page (such as writing to a variable or allocating memory), the hardware triggers a page fault.
- The kernel intercepts the fault, allocates a new physical page, copies the original data into it, and updates the modifying process’s page table with read-write permissions.
This ensures that only modified memory pages consume additional
physical RAM, making fork() fast and resource-efficient,
especially when paired with subsequent exec() family
functions to launch new binaries.