Zhu Yuxiang + Original works reproduced please specify the source + "Linux kernel analysis" MOOC course http://mooc.study.163.com/course/USTC-1000029000
Today, we will simply analyze the process creation process in Linux systems by reading the kernel code of Linux.
As you know, Linux controls and manages processes through the Process Control block PCB, which stores the process data. In Linux, the code for the PCB is as follows (of course, the excerpt = =):
structtask_struct {volatile LongState//process Status void*stack;//process Stack pointeratomic_t usage; unsignedintflags; unsignedintptrace, .....//Some variables that record precedence intPrio, Static_prio, Normal_prio; unsignedintrt_priority; Const structSched_class *Sched_class; structsched_entity se; structsched_rt_entity RT, ... ..//Process Chain List structlist_head tasks; #ifdef CONFIG_SMPstructPlist_node Pushable_tasks; structRb_node pushable_dl_tasks;#endif //PID Numberpid_t pid; pid_t Tgid;//parent process and child process structTask_struct __rcu *real_parent; structTask_struct __rcu *parent; structList_head Children; structlist_head Sibling; structTask_struct *Group_leader, ...};
As can be seen, the PCB records the process ID number, priority, status, and other process relationships and other information, the operating system to manage the process.
It is important to note that in the specific implementation of the operating system kernel, the current process is all stored in a circular list for management. As shown in the following:
The specific experiment is a function created using the GDB debug process, which is as follows:
This time we set breakpoints at 6 functions (or system calls):
1.sys_clone
2.do_fork
3.dup_task_struct
4.copy_process
5.copy_thread
6.ret_from_fork
In the virtual system used in the lab building, the underlying function created by the process is sys_clone, and Sys_clone actually calls Do_fork, so do_fork is the function that really implements the details of the creation process.
LongDo_fork (unsignedLongclone_flags, unsignedLongStack_start, unsignedLongStack_size,int__user *Parent_tidptr,int__user *child_tidptr) { structTask_struct *p; inttrace =0; Longnr; ... p=copy_process (Clone_flags, Stack_start, Stack_size, Child_tidptr, NULL, Trace); ......}
In this function, p is the variable that records the PCB of the new process, and through copy_process, the system copies and modifies the parent process's PCB to the child process.
The Copy_process function is to first use dup_task_struct to copy the entire PCB of the parent process, and then modify the sub-parts that are different from the parent process.
Static structTask_struct *copy_process (unsignedLongclone_flags, unsignedLongStack_start, unsignedLongStack_size,int__user *Child_tidptr,structPID *PID,intTrace) { intretval; structTask_struct *p; //Copy the parent process's PCBp =dup_task_struct (current); if(!p)Gotofork_out; //Modify specific parts of the structureP->flags &= ~ (Pf_superpriv |pf_wq_worker); P->flags |=pf_forknoexec; Init_list_head (&p->children); Init_list_head (&p->sibling); Rcu_copy_process (P); P->vfork_done =NULL; Spin_lock_init (&p->alloc_lock); retval=Copy_thread (clone_flags,stack_start,stack_size,p);}
It is important to note that there is a copy_thread function in the copy_process function that, in its function implementation, finds the stack bottom space of the child process that is created and modifies the IP and SP data of the child process according to this: the SP points to the bottom of the stack, and the IP points to the ret_from_fork segment. What is the Ret_from_fork section, it is actually the following section of code:
ENTRY (ret_from_fork) Cfi_startproc %eax call schedule_tail get_thread_info (%ebp) %eax PUSHL_CFI $ 0x0202 # Reset kernel eflags popfl_cfi jmp syscall_exit cfi_endprocend (ret_from_fork)
As you can see, it eventually jumps to Syscall_exit, and Syscall_exit is the code in the interrupt handler Sys_call we analyzed last time. In this way, the SP points to the actual context that we triggered the end of the stack, IP point to Syscall_eixt, when the new process is created, it will first execute the code at Syscall_exit, will soon encounter Restore_all, restore the context, The new process can be implemented.
Summarize:
In the Linux kernel, when creating a new process, the basic idea is to copy the parent process's PCB to the child process, if there are different data to adjust. At the same time, the first command executed by the child process points to the code that interrupts the recovery, thereby achieving the effect of creating a new process.
Brief analysis of Linux process start-up process