Issue
When I execute a program in unix/Linux, what really happens under the hood?
Who is responsible for creating a process?
Do I need to make a call to kernel to start a process (instance of my program) ? In that sense, my program should be running on a processor to make kernel calls right? Then how does the first kernel call happened to start of a process? . Is it like a deadlock? Where exactly kernel first show-in then?
Sorry, I just read many documents about all these, but still couldn't connect the dots or get a full picture. Can someone elaborate on simple terms?
Solution
On Unix systems (as well as most modern non-Unix systems), processes are a tree - every process has a parent process (except for the process with Process ID 1, the init process, which is created by the kernel at startup).
When you log in to a system, you are usually logged into an instance of "shell" program (program = executable file, shell = user interaction). On Windows, Explorer.exe
is the shell. On Unix systems, traditionally your shell is something like bash
. On Linux desktops, you have a graphical environment like Gnome which is your shell, and you can use it to run programs like gnome-terminal
which happens to run another program which then happens to be a text-based shell like bash
rather than graphical shell.
Whether your run your program from Gnome, from bash
, or from any other program P
, whether interactive or not, P
is the parent process of your process, which we will call C
, and so P
is the process that jump-starts the creation of C
.
The way it works in Unix, usually, is as follows:
P
is actually running on some CPU.P
calls thefork()
system call, which is a kernel API.- In response, the kernel creates a copy of process
P
as a new process,C
.
- At that point,
C
is not running on any CPU. - Now you have 2 processes,
P
andC
are 2 separate instances of the same program.
- When the kernel's scheduler decides that it's time to run
C
, it selects a CPU, and sets that CPU's stack pointers, data pointers, code pointers, and page tables to point to the appropriate addresses inC
's memory. - The CPU is basically hardware that runs a loop that always executes the next code pointer ("instruction pointer"), so once you set the code pointer to new code, it will run the new code.
- Note that the new code - in
C
- is still a copy of the old code - inP
.
- Now that
C
is running, it calls theexecve()
system call, which is another kernel API.
- This is part of the parent process' logic to launch a program - you call
fork()
, then you check whether you're the originalP
or the cloneC
, and if you'reC
, you callexecve()
.
- In response, the kernel creates a new memory space ("address space") which will contain the new program's heap, stacks, code etc., loads the executable into this memory, and then declares this new memory to be "process
C
".
- Part of loading an executable into memory is creating new appropriate addresses of stack pointers, data pointers, code pointers, and page tables that the CPU can eventually point to.
- In particular, the address for the code pointer is the address of the new program's entry point.
- (I'm simplifying here) the kernel's scheduler then again sets the CPU's pointers to those
C
- essentially "rescheduling" it. Only now those point to the new memory space. - When control goes back from the kernel to
C
, it is now pointing to the new program's entrypoint, which will eventually callmain()
.
Answered By - root