Process role playing in the Linux kernel

Source: Internet
Author: User
Tags signal handler

In the Linux kernel, the kernel treats processes, threads, and kernel threads equally, that is, the kernel uses unique data structure task_struct to represent them separately; the kernel uses the same scheduling algorithm to dispatch the three, and the kernel uses the same function do_fork () To create these three execution threads separately (thread of execution). A thread of execution typically refers to any code instance that is executing, such as a kernel thread, an interrupt handler, or a process that enters the kernel.

Such treatment is undoubtedly concise and convenient, and the kernel does not lose the characteristics of the three of them. This article will combine the characteristics of processes, threads, and kernel threads to talk about role-playing issues in the kernel.

1. Process descriptor task_struct Multi-Role play

The above three execution threads are represented in the kernel using a uniform data structure task_struct. The TASK_STRUCT structure is the so-called process descriptor, which contains all the information related to a process. The process descriptor contains not only a number of fields that describe the properties of the process, but also a series of pointers to other data structures. The following is a brief introduction to some of the more special fields in the process descriptor that point to the data structure that represents the resources owned by the process.

mm field : A pointer to the MM_STRUCT structure that describes the entire virtual address space of the process.

FS field : A pointer to the FS_STRUCT structure that describes the root directory of the file system where the process resides and the directory information for the current process.

files field : A pointer to the FILES_STRUCT structure that describes the information for the file opened by the current process.

signal field : A pointer to the SIGNAL_STRUCT structure (signal descriptor) that describes the signal that the process can handle.

For normal processes, the above fields point to a specific data structure to represent the resources owned by the process.

For each thread, the kernel is associated with it through a lightweight process. The lightweight process is lightweight because it shares the process resources mentioned above with other processes. For example, process a creates thread B, and the B thread corresponds to a lightweight process in the kernel. This lightweight process naturally corresponds to a process descriptor, except that some of the delegate resource pointers in the process descriptor of the B thread point to the same data structure as the corresponding fields in the a process, thus enabling resource sharing between multiple threads.

Because kernel threads run only in the kernel state and can only be created by other kernel threads, kernel threads do not need separate address spaces like normal processes. Therefore, the MM pointer in the process descriptor of the kernel thread is null. Whether the kernel thread shares some of the resources of the parent kernel thread, it is determined by passing parameters to the kernel thread to create the function Kernel_thread ().

The above analysis shows that the kernel uses a uniform process descriptor to represent processes, threads, and kernel threads, and depending on their characteristics, some of the fields that represent the resources in their process descriptors are pointed differently to achieve different roles.

2. Multi-Role play of Do_fork ()

Processes, threads, and kernel threads all have corresponding creation functions, but the corresponding creation functions of the three are ultimately created by Do_fork () in the kernel, and the specific call graph is as follows:

As you can see, the core function of the creation process in the kernel is to look at Do_fork (), the function is prototyped as follows:

Long do_fork (unsigned long clone_flags,
unsigned long Stack_start,
struct Pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)

The number of arguments to the function is fixed, and the function of each parameter is as follows:

clone_flags: A flag that represents the various characteristics of a process. Low byte specifies the signal code that is sent to the parent process at the end of the child process, typically a sigchld signal, and the remaining three bytes are the result of several flags or operations.

stack_start: A pointer to the child process's user-state stack, which is assigned to the ESP register of the child process.

regs: A pointer to a universal register value that is stored in the kernel stack when the process switches from the user state to the kernel state.

stack_size: Not used, the default value is 0.

parent_tidptr: The address of the parent process user-state variable for the child process, valid only if Clone_parent_settid is set.

child_tidptr: The address of the child process user-state variable, valid only if Clone_child_settid is set.

Since processes, threads, and kernel threads are all created through Do_fork () in the kernel, how does do_fork () reflect the diversity of its functions? In fact, the Clone_flags parameter plays a key role here, by selecting different flags to ensure that the do_fork () function implements multiple roles-creating processes, threads, and kernel threads-to implement the functionality. The Clone_flags parameter is a good number of flags, the following are only a few of the flags related to this article.

Clone_vim: The child process shares the parent process memory descriptor and all the page tables.

Clone_fs: The child process shares the root directory and current working directory of the file system where the parent process resides.

clone_files: The child process shares the file that the parent process opened.

Clone_sighand: The child process shares the parent process's signal handlers, blocking signals, and pending signals. Use this flag to set the CLONE_VM flag at the same time.

If the above flags are set when the child process is created, the child processes share the parent process resources that these flags represent.

2.1 Creation of the process

In the user-state program, processes can be created through the fork (), vfork (), and Clone () three interface functions, which correspond to system calls of the same name in the library, respectively. When the system call function enters the kernel through a soft interrupt of 128th, the appropriate system invoke service routine is called. The service histories for these three functions are sys_fork (), Sys_vfork (), and Sys_clone () respectively.

int sys_fork (struct pt_regs *regs)
{
Return Do_fork (SIGCHLD, REGS->SP, regs, 0, NULL, NULL);
}


int sys_vfork (struct pt_regs *regs)
{
Return Do_fork (Clone_vfork | CLONE_VM | SIGCHLD, REGS->SP, regs, 0,
NULL, NULL);
}

Long Sys_clone (unsigned long clone_flags, unsigned long newsp,
void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
{
if (!NEWSP)
NEWSP = regs->sp;
Return Do_fork (Clone_flags, newsp, regs, 0, Parent_tid, Child_tid);
}

Through the above system call service routine source code can be found, three service process internal call do_fork (), but the difference is that the first parameter passed the value of different. This also happens to cause the processes created by the three process creation functions to have different characteristics. The following is a brief description of each of these processes.

fork (): The process created by fork () does not share any resources of the parent process because the Clone_flags parameter in Do_fork () has no other attribute flags in addition to the SIGCHLD signal returned to the parent process at the end of the child process. The child process completely replicates the resources of the parent process, that is, the parent-child process is relatively independent. However, due to the introduction of copy on Write,cow, the child process can read only the physical page of the parent process, and only when one of the two goes to write a physical page, the kernel copies the contents of the page to a new physical page and assigns the new physical page to the process being written.

vfork (): Clone_flags in Do_fork () uses the clone_vfork and CLONE_VM two flags. The CLONE_VFORK flag causes the child process to execute before the parent process, and the parent process blocks to the end of the child process or executes a new program. The CLONE_VM flag causes the child process to share the memory address space of the parent process (except for the parent process's page table entry). Before the introduction of cow technology, vfork () applies the case of EXECV () immediately after the child process is formed. As a result, vfork () now has no special use, since realistic replication technology can completely replace the efficiency of its creation process.

Clone (): Clone is typically used to create lightweight processes. By passing different flags, you can control the sharing and copying of data between parent and child processes, and the general Flags value is clone_vm| clone_fs| clone_files| Clone_sighand. As can be seen from the above flags, lightweight processes typically share the memory address space of the parent process, the root directory of the file system where the parent process resides, and the working directory information, the file currently opened by the parent process, and the signal handler functions owned by the parent process.

2.2 Creation of Threads

Each thread corresponds to a lightweight process in the kernel, and the correlation is done through the line libraries. Thus the thread created through Pthread_create () is eventually created in the kernel through clone (), and clone () eventually calls Do_fork ().

2.3 Creation of kernel threads

The creation of a new kernel thread is created by using Kernel_thread () in an existing kernel thread, and its nature is created by providing a specific flags flag to do_fork ().

int kernel_thread (int (*FN) (void *), void *arg, unsigned long flags)
{
/*some Register operations*/
Return Do_fork (Flags | CLONE_VM | clone_untraced, 0, &regs, 0, NULL, NULL);
}

As can be seen from the combination of flags above, the new kernel thread will at least share the memory address space of the parent kernel thread. This is done in order to avoid assigning the page table of the calling thread, because the kernel thread does not access the user address space anyway. The clone_untraced flag ensures that kernel threads are not tracked by any process,

3. Scheduling of processes

Because processes, threads, and kernel threads are represented using uniform data structures, the kernel does not differentiate between the three, nor does it establish a separate scheduling algorithm for one of them. The kernel treats all three as a uniform dispatch.

Resources:

1. Deep understanding of the Linux kernel

2. Linux kernel design and implementation

Process role playing in the Linux kernel

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.