Example of process management applications: fork() and exec()
Execution result
Rust user shell
>> forkexec
pid 2: parent start forking ...
pid 2: ready waiting child ...
pid 3: forked child start execing hello_world app ...
pid 3: Hello world from user mode program!
pid 2: got child info:: pid 3, exit code: 0
Shell: Process 2 exited with code 0
>> QEMU: Terminated
Outline
Basic concept of process
Process management
System calls for process management
Process control block (PCB)
Process creation and program loading
Process wait and exit
Thoughts on fork()
Process control block (PCB)
Shell executes user input commands
Process control block in shell execution
Process switching
The process of process switching
Pause the currently running process and change its state from running to another state
Schedule another process and change its state from ready to running
The requirements for process switching:
Save the process context before switching
Restore the process context after switching
Process lifecycle
Process switching
Pause the currently running process and change its state from running to another state
Schedule another process and change its state from ready to running
Information about the process lifecycle
Registers (PC, SP, …)
CPU status
Memory address space
Outline
Basic concepts of process
Process management
System calls for process management
Process control block (PCB)
Process creation and program loading
Process wait and exit
Thoughts on fork()
Process creation API of windows: CreateProcess(...)
Close all file descriptors in the child process during creation
CreateProcess(filename, CLOSE_FD)
Change the environment of the child process during creation
CreateProcess(filename, CLOSE_FD, new_envp)
Process creation/loading
System calls of process creation/loading in Unix: fork/exec
fork() creates a new process by duplicating the calling process
parent (old PID), child (new PID)
exec() overwrites the current process with a new program, but PID will not change
Example of creating a process with fork and exec
int pid = fork(); // create child processif(pid == 0) { // child process continues here// Do anything (unmap memory, close net connections…)
exec("program", argc, argv0, argv1, ...);
}
fork() creates an inherited child process
Copy all variables and memory of the parent process
Copy all CPU registers of the parent process (except one register, a0, i.e., the return value of fork())
Example of creating a process with fork and exec
int pid = fork(); // create child processif(pid == 0) { // child process continues here// Do anything (unmap memory, close net connections…)
exec("program", argc, argv0, argv1, ...);
}
Return value of fork()
fork() returns 0 in the child process
fork() returns the process ID (PID) of the child process in the parent process
The return value of fork() can be conveniently used for subsequent operations. The child process can use getpid() function to get its own PID
Execution process of process creation fork()
For the child process, fork() is a copy process of the parent process's address space
Example of program loading and execution
The system call exec() loads a new program to replace the currently running process (Is there any problem with the code???)
main()
…
int pid = fork(); // create child processif (pid == 0) { // child process continues here
exec_status = exec("calc", argc, argv0, argv1, ...);
printf("Why would I execute?"); // Can this line of code be executed???
} else { // parent process continues hereprintf("Whose your daddy?");
…
child_status = wait(pid);
}
Example of program loading and execution
The system call exec( ) loads a new program to replace the currently running process
main()
…
int pid = fork(); // create child processif (pid == 0) { // child process continues here
exec_status = exec("calc", argc, argv0, argv1, ...);
printf("Why would I execute?");
} else { // parent process continues hereprintf("Whose your daddy?");
…
child_status = wait(pid);
}
if (pid < 0) { /* error occurred */
Process of program loading and execution
Load the calculator after calling fork() in the shell
Process of program loading and execution
Load the calculator after calling fork() in the shell
Process of program loading and execution
Load the calculator after calling fork() in the shell
Process of program loading and execution
Load the calculator after calling fork() in the shell
Process of program loading and execution
Load the calculator after calling fork() in the shell
Process of program loading and execution
Load the calculator after calling fork() in the shell
Example of process management application:fork()
intmain(){
pid_t pid;
int i;
for (i=0; i<LOOP; i++)
{
/* fork another process */
pid = fork();
if (pid < 0) { /*error occurred */fprintf(stderr, “Fork Failed”);
exit(-1);
}
elseif (pid == 0) { /* child process */fprintf(stdout, “i=%d, pid=%d, parent pid=%d\n”,I,
getpid() ,getppid());
}
}
wait(NULL);
exit(0);
}
Example of process management application: fork()
Outline
Basic concept of process
Process management
System calls for process management
Process control block (PCB)
Process creation and program loading
Process wait and exit
Thoughts on fork()
Parent process waits for child process
The system call wait() is used by the parent process to wait for the termination of the child process
When the child process exits, it returns a value to the parent process through the system call exit()
The parent process accepts and processes the return value using wait()
Functionalities of wait()
When the child process is alive, the parent process enters the waiting state and waits for the return result of the child process
When the child process calls exit(), wake up the parent process and use the return value of exit() as the return value of wait() in the parent process
Zombie process and orphan process
Zombie process: A child process whose PCB has not been reclaimed by the parent process through the sys_wait system call, even though it has already executed the sys_exit system call
How to handle Zombie process?
Using signal or fork twice
Orphan process: A child process whose parent process has exited before it
The root process is responsible for waiting and reclaiming orphan processes
Process exit exit()
When a process ends, it calls exit() to complete process resource reclamation
Functionalities of exit()
Use the call argument as the "result" of the process
Close all occupied resource, such as opened files
Release memory
Release most of the kernel data structures associated with the process
Preserve the value of the result and check whether the parent process is alive
If it is not, set the parent process to the root process
Enter the zombie/defunct state, waiting for the parent process to reclaim it
Other related system calls for process management
Priority control
nice() is used to specify the initial priority of a process
In Unix, the priority of a process will decay over time
Process debugging
ptrace() allows one process to control the execution of another process
Set breakpoints, view registers, etc
Timing
sleep() allows a process to wait in the timer's waiting queue for a specific amount of time
Relationship between process management and process status
System calls related to process management may affect the state of the process
Relationship between process management and process status
Outline
Basic concept of process
Process management
3. Thoughts on fork()
Overhead of fork()?
Rethinking fork
Overhead of fork()?
Implementation overhead of fork()
Allocate memory for the child process
Copy the memory and CPU registers of the parent process to the child process
The overhead is expensive!!
Overhead of fork()?
In 99% cases, we call exec() after fork()
Memory copying during the fork() operation is unnecessary --why?
The child process may close opened files and network connections --why?
Overhead of fork()?
When vfork() creates a process, it no longer creates the same memory image
Lightweight fork()
The child process should call exec() almost immediately
Fork is not an inspired design, but an accident of history
Only Unix implemented it this way
We may be stuck with fork for a long time to co me
But, let's not pretend that it's still a good idea today!
Please, stop teaching students that fork is good design
Begin with spawn
Teach fork, but include historical context
Summary
Basic concepts of process
Process management
Thoughts on Fork()
Overhead of fork()?
Rethinking fork
https://www.infoq.cn/article/BYGiWI-fxHTNvSohEUNW
When Unix was rewritten for the PDP-11 computer (which had memory translation hardware that allowed multiple processes to remain resident), it was already inefficient to copy a process's entire memory just to drop a process in exec. We suspect that in the early days of Unix, fork survived primarily because programs and memory were small (only eight 8 KiB pages on the PDP-11), memory access was fast relative to instruction execution, And it provides a reasonable abstraction. There are two important points here: