Processes
It's important to keep in mind that kernel itself being a C program that's being compiled to native code.
This means, all what kernel does is logic + data models defined in C structures. Process is one such structure.
Process/thread Structureβ
It's this structure task_struct that the kernel uses to manage the anything that must be executed. This has all information related to the process such as PID, page table location, register information such as current instruction pointer of the thread, all necessary register values, etc.
There is no big distinction between thread and process for the kernel when it comes to executing it. In fact, kernel knows only threads.
Both are represented using the same structure. This structure also has properties that links threads to main thread of the process.
Forkβ
Fork is the system call to start a process.
- When we connect to a computer using SSH, then SSHD process forks a new process for the user's session.
- When we execute commands then on the terminal, each command is executed via fork.
- When we execute an OS command from a Java application, it will also fork a new process from the JVM process.
When the OS boots, only the first process with PID 1 isn't booted via fork.
It's started by the Kernel and it then forks all other system services at boot.
Even simple commands such as ps or ls are also fork in the background.
Process creationβ
When a process forks another child process, the fork() system call will always create a child process as duplicate of itself.

For example, when bash wants to start another process, it will execute a fork or clone of the existing process.
This new process is created by the kernel which means a new process structure is created. This fork() function implementation of kernel sets the return value of fork() as 0 in the child process and the actual PID of the child process for the parent process.
Since the child process also continues the same parent program from the same instruction pointer which called the fork() system call, the child process's program takes a different path when it sees fork() returned 0.
This path then calls the other system call called execve() which then replaces the parent program with something else that was requested.
It's the responsibility of the parent process to have the below mentioned logic.
# Example code to show how programs that start another programs are implemented.
pid_t pid = fork();
if (pid == 0) {
// Child Process enters this path
setup_io_redirection();
execve("/bin/ls", args, envp);
} else {
// Parent process continues to wait.
// If its background process, then it will exit immediatly.
waitpid(pid, &status, 0);
}
- This is how bash executes other commands. The stdio values of the new command is also set to the values of bash process. That's why we see the output in the bash process still.
- Docker runtime starts different container processes also in this way.
- Kubelet also starts containers in this way.
It's a POSIX standard that fork() returns a 0 to the cloned child process.
Process is always forked or cloned from a parentβ
Processes are always started from another process. systemd is the only process that kernel starts itself. After that every process must come out of another process.
- Kubelet - it's configured as system service. So systemd will fork and then start kubelet program.
- containers - kubelet then forks other containers and start the container program.
Process versus programβ
Process is just a kernel object and the program is the one that's attached to the program. The kernel schedules the process for execution which in turn executes the program attached to it.
Process is created first and only after that a program is attached is it.
A process without a program is called Zombie.
