LINUX kernel research ---- the similarities and differences of fork(), clone(), vfork() from the perspective of the kernel

The Linux system divides the creation of the process and the execution of the target process into two steps

The first step is to copy a child process from an already existing process like cell division. The child process has its own task_struct structure and system stack space, but shares all other resources with the parent process. For example, the file descriptor, the read and write pointers of the file stay in one place, and the parent and child share it.

LINUX provides three system calls for replication:

fork():

All the resources of the parent process are copied to the child process through the PCB. So what kind of replication does the bottom layer of fork do? How does a function return twice? Re-analysis by reading the source code.

clone():

Resources can be selectively copied to child processes, and data structures that are not copied are shared by copying pointers. Generally used to create threads

vfork():

Similar to fork(), vfork() creates a child process, and the return values ​​of these two functions have the same meaning. But the child process created by vfork() can basically only do one thing, which is to immediately call the _exit() function or member of the exec function family, call any other function (including exit()), modify any data (except save vfork () the variable that returns the value), and executing any other statement (including return) should not be used. In addition, after calling vfork(), the parent process will block until the child process calls _exit() to terminate, or calls a member of the exec function family to run other processes.

Several differences between vfork() and fork() lead to the above reasons:

    1. Fork() will copy the page table of the parent process, while vfork() will not copy, and directly let the child process share the page table of the parent process;

    2. Fork() uses copy-on-write technology, while vfork() does not, it will not copy the parent process address space at any time.

    3. Fork() will not block the parent process, while vfork() will block.

Therefore, the child process generated by vfork() completely shares the same address space with the parent process , and even shares the same function stack ! That is, any modification to any data variable in the child process, whether local or global, will affect the parent process. And any function call will modify the stack space, which is why the child process of vfork() cannot call other functions casually. And the return statement will release local variables, and have the behavior of pop() the stack, returning to the execution of the upper-level function. Exit directly exits, without the operation of exiting the stack, that is, it does not affect the memory of the stack. In C++, return will call the destructor of the local object, but exit will not. (Note: exit is not a system call, it is glibc's encapsulation of the system call _exit()). exit does many other things when calling _exit().

 

The bottom layers of these three system calls are implemented through the do_fork() kernel function, but different functions are implemented through different parameters passed to do_fork().

The first parameter clone_flags consists of two parts, the lowest byte of which is the signal type, which is used to specify the signal SIGCHLD that should be sent to the parent process when the child process dies;

The second part is some flags that represent resources and characteristics, to identify whether the resources for the parent process are copied or shared through pointers.

    fork(), these flags are all 0, indicating that all of them should be copied.

    vfork(), the parent and child processes share the virtual memory space.

    clone(), set by the caller and passed as a parameter, is generally used to create a thread

 

So, fork() creates the process;

vfork() is a created thread, which is an intermediate step in creating a process. If exec() is called directly after creating a process, vfork() can be used to reduce unnecessary copies;

clone() creates a thread, which can be a kernel thread or a user thread

 

 

The kernel entry for the system to call fork is sys_fork()

And sys_fork(), sys_clone(), sys_vfork() are all encapsulations of do_fork().

The specific calling process is shown in the figure.

 

复制:只是基本资源的复制,task_struct数据结构、系统堆栈空间。而对父进程代码和全局变量则并不需要复制,而是通过读共享,写时拷贝(即写的时候复制),所以说复制的代价比较低。

基于复制的特点,有利于父子进程通过管道来实现一种简单有效的进程间的通信,shell中的管道机制。

 

第二步是目标程序的执行:子进程调用execve()函数执行可执行文件的影像开始新的进程,涉及程序的加载过程。程序的加载执行过程在我的另外一篇博客有详细的分析

系统调用execve()的内核入口sys_execve()

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326660168&siteId=291194637