Linux process
How does a program create a new process?
Historically, programs loaded executables directly into memory. Modern operating systems prevent this each user process runs in a restricted address space. Instead, we use system calls, the OS API for creating processes, reading files and more. You can checkout there the list on Linux here.
Windows vs Linux
Here’s where they differ: Windows will create a new process with the executable and argument needed and voilà.
Linux on the other hand is a bit tricky it uses fork and copy the parent process’s same memory, same open file descriptors, same CPU state, different PID. It isn’t a literal copy though Linux uses copy on write (COW), so both processes share the same physical pages until one of them writes. That’s what makes forking cheap.
But you have to be careful because if you use multiple fork you will get exponential example here:
for(int i = 0; i < 3; i++) {
printf("PID %d: fork %d\n", getpid(), i);
fork();
}
output:
PID 1000: fork 0
PID 1000: fork 1
PID 1001: fork 1
PID 1000: fork 2
PID 1001: fork 2
PID 1002: fork 2
PID 1003: fork 2
Okay, but how do we create a new process nobody needs the same one! For that you will need to use the execv int execv(const char *path, char *const argv[]);, execv will replace the current process so we need to copy the current process then replace it.
But how to only replace the child process? We could use getpid() to differentiate the parent from the child. That’s okay:
pid_t parent_pid = getpid();
printf("Before fork, PID: %d\n", parent_pid);
fork();
if (getpid() == parent_pid) {
printf("Parent process");
} else {
printf("Child process");
}
But an even better way, the fork process returns the process id if it’s the parent else returns 0. so we could do this:
pid_t npid = fork();
if (npid == 0) {
printf("child process\n");
} else {
printf("parent process\n");
}
Cleaners only create a subprocess:
if (fork() == 0) {
execv(path, argv)
}
To know
Failure in execv
execv never return something after a success, but after a failure it does (return -1). The problem will be if execv fails the child process continues as the script we need an exit.
execv(path, argv);
perror("execv");
_exit(127);
exit: flushes buffer and handlers (clean exit). _exit: just dies.
Zombies
When a process is finished, the kernel frees the memory, but there is still a table entry holding the PID, this is called a zombie process. At the end of the parent process they need to reap zombies otherwise zombies can pile up until you can’t create a fork because of pid_max. When a parent dies zombies are transferred to PID 1 a parent and is reaped immediately afterward.
pid_t pid = fork();
if (pid == 0) {
do_child_work();
_exit(0);
} else {
do_parent_work();
waitpid(pid, NULL, 0); // remove the child zombie
}
Where does the first process come from?
On Linux all user processes are created by other processes that form a process tree. But what is the mother of all processes and how is it created? (Tips: use pstree to see that).

When the machine boots:
graph LR
A["BIOS / UEFI<br/>Firmware initialization"]:::blue
B["Bootloader<br/>GRUB, systemd-boot"]:::coral
C["Kernel<br/>vmlinuz, initramfs"]:::green
D["Init System<br/>systemd, SysVinit"]:::purple
A --> B --> C --> D
classDef blue fill:#185FA5,stroke:#0C447C,color:#fff,stroke-width:2px
classDef coral fill:#D85A30,stroke:#712B13,color:#fff,stroke-width:2px
classDef green fill:#639922,stroke:#27500A,color:#fff,stroke-width:2px
classDef purple fill:#534AB7,stroke:#3C3489,color:#fff,stroke-width:2px
At the kernel point there are no user processes.
The kernel initializes:
- memory
- scheduler
- interrupts
- drivers
- filesystems
Only after all that does it create the first userspace process, historically PID 1 is:
init- Nowadays often
systemd
It is not forked from another userspace process because none exists yet.