Process management process (thread) creation

Source: Internet
Author: User
Tags goto

This section focuses on the process of creating processes (threads), and the following will not differentiate between processes and threads;


Basic knowledge

In a Linux system, the first process is inherent in the system and is arranged by the designer of the kernel; a new process must be copied by an existing process, not created, but the Linux system does not provide a direct

Process, the parent process can continue to go its own way and separate from the child process, but if the child process first exit (), a signal will be sent to the parent process, and the parent process can also choose to sleep, and so on child processes

Exit () dies later, and then the parent process resumes execution, you can use WAIT3 () a particular child process, WAIT4 () all child processes, and thirdly, exit () itself (required for each executable image, so that it is executed in the child process

is not returned); Linux divides the process creation into two steps from the execution of the target program;

(1) Copying a child process from an existing parent process like a cell division; the actual copied child process has its own task_struct and system space stack , but shares other resources with the parent process, for example, if the parent process opens 5 files, Then the child process also opened the 5 files, and the read and write location of the files are in the same location;fork () is all copy, all the resources of the parent process are copied to the child process through the data structure , but the process number is different;clone () has a selective copy of the parameters. A thread can be copied , and other resources are shared with the father through pointers , and vfork () is a thread that replicates all the resources except the task_struct and the system space stack, so it is highly efficient ;

(2) The execution of the target program, the creation of a process is to have a different target program to get the new program to execute, but after the replication, the child process will be separated from the parent process, with EXECVE () to execute the file as the executable image of the program;

In (1), replication only copies process basic resources, such as task_struct, System space stacks, page tables, etc., excluding the parent process's code and global variables, which are shared through read-only mode , when required to write, by Copy_on_write () Create a new copy of the page involved;


Fork,vfork,clone

(1) Clone () is primarily used to create a thread, including a user thread and a kernel thread ; When creating a user thread, a child thread can be given a user space stack location, which can also be used to create a process, selectively replicate the parent process's resources, andfork () is a comprehensive replication ;vfork () is to improve the efficiency of the creation, reduce the system overhead ;

(2) The Linux kernel does have a function to create a kernel thread, kernel_thread (), for kernel thread invocation, it is a wrapper over clone (), does not execute Execve (), but executes a function in the kernel, it returns a exit () system call to execute ;

(3) Fork,vfork,clone These three system calls are called do_fork (), but the parameters of the call is not the same, the following mainly to explain Do_fork ();

int sys_fork (struct pt_regs *regs) {//clone_flags Sigchldreturn do_fork (SIGCHLD, REGS->SP, regs, 0, NULL, NULL);}

int sys_vfork (struct pt_regs *regs) {//shared clone_vfork and Vmreturn do_fork (clone_vfork | CLONE_VM | SIGCHLD, REGS->SP, regs, 0,       null, NULL);}

Clone is responsible for building a lightweight process (can share the address space with other processes, or open files, etc.), newsp refers to the user stack pointer, Parent_tid represents the parent process's//user variable address, child_ TID represents the user variable for the new lightweight process address: longsys_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;  There is a new user stack address//where clone_flags generally has parameter sigchld, takes up a byte, the remaining 3 bytes can be drawn up, such as shared Memory descriptor, page table, file directory, signal processing flag, tracking etc. return do_fork (Clone_flags, NEWSP, regs, 0, Parent_tid, Child_tid);}

Explain the points

(1) NEWSP is a new stack of sub-processes, which may be in another address space;


/* * Create a kernel thread */int kernel_thread (int (*FN) (void *), void *arg, unsigned long flags) {struct Pt_regs regs;mem Set (&regs, 0, sizeof (regs)), regs.si = (unsigned long) Fn;regs.di = (unsigned long) arg; #ifdef Config_x86_32regs.ds = _ _user_ds;regs.es = __user_ds;regs.fs = __kernel_percpu;:regs.gs = __kernel_stack_canary; #elseregs. SS = __KERNEL_DS;# Endifregs.orig_ax = -1;regs.ip = (unsigned long) Kernel_thread_helper;regs.cs = __kernel_cs | GET_KERNEL_RPL (); regs.flags = X86_eflags_if | 0x2;/* Ok, create the new process. *///where CLONE_VM avoids invoking the page table of the process, the kernel thread is the address space without accessing the user's state; the return do_fork that will not be traced (flags | CLONE_VM | clone_untraced, 0, &regs, 0, NULL, NULL);}


Do_fork

/* Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. *///sys_clone//regs refers to the universal register pointer, which is a lightweight process that switches to the kernel state in the user state, saving to the kernel stack long do_fork (unsigned long clone_flags, unsigned long stack _start,//the start address of the stack under User state struct Pt_regs *regs,//pointer to the Register collection unsigned long stack_size,//user state, stack size int __user *PA rent_tidptr,//two pointers to address in user space int __user *child_tidptr) {struct task_struct *p;int trace = 0;long nr;/* * do some Preli Minary argument and permissions checking before we * actually start allocating stuff */if (Clone_flags & Clone_newuser  {//Create new user if (Clone_flags & Clone_thread)//But not create new thread return-einval;/* Hopefully this check would go away when userns Support are * complete */if (!capable (cap_sys_admin) | |!capable (CAP_SETUID) | |! Capable (cap_setgid)) Return-eperm;} /* * When the called from Kernel_thread, don ' t does user tracing stuff. */if (Likely (User_mode (regs))) trace = Tracehook_preparE_clone (clone_flags);//Perform the actual work of generating a new process P = copy_process (Clone_flags, Stack_start, Regs, Stack_size, Child_tidptr, NULL, */* * Prior waking up the new thread-the thread pointer * might get invalid after that point, if the Threa D exits quickly. */if (!is_err (p)) {struct completion vfork;trace_sched_process_fork (current, p); nr = Task_pid_vnr (p);//Gets the local Nrif ( Clone_flags & Clone_parent_settid) Put_user (NR, parent_tidptr);//copy NR to the address pointed to by the corresponding user space if (Clone_flags & Clone_   Vfork) {//If the function is executed vfork, the parent process will sleep P->vfork_done = &vfork;init_completion (&vfork); Sleep, at this time the parent process and other child processes}//schedule_tailaudit_finish_fork (p); Tracehook_report_clone (Regs, Clone_flags, nr, p);/* * * We set Pf_  Starting at creation in case tracing wants to * use this to distinguish a fully live task from one that * hasn ' t gotten to  Tracehook_report_clone () yet. Now we * clear it and set the child going. */p->flags &= ~pf_starting;wake_up_new_task (P, clone_flags);//The task_struct of the subprocess is placed in the new scheduler queue Tracehook_report_clone_complete (Trace, Regs,clone_flags, nr, p);//If you set the clone_vfork,//to insert the parent process into the wait queue, Until the child process releases its own memory address space (that is, the child process ends or executes a new program) if (Clone_flags & clone_vfork) {freezer_do_not_count (); Wait_for_completion ( &vfork);//The parent process will go to sleep state on the change Amount freezer_count (); Tracehook_report_vfork_done (P, NR);}} else {nr = Ptr_err (p);} return nr;}
Explain the points

(1) p = copy_process (Clone_flags, Stack_start, Regs, Stack_size, Child_tidptr, NULL, trace); Perform actual process copy work;

(2) if (Clone_flags & clone_vfork) indicates that if the function is executed vfork, the parent process will sleep;


Key code in Copy_process 1

Setting up the task_struct and system stacks

Task_struct can be anywhere in memory P = dup_task_struct (current),//Get and set the process descriptor for the subprocess, and set the Thread_infoif (!p) goto fork_out;


static struct task_struct *dup_task_struct (struct task_struct *orig) {struct task_struct *tsk;struct thread_info *ti; unsigned long *stackend;int err;prepare_to_copy (orig); Save the FPU and other register contents into Thread_info tsk = Alloc_task_struct ();//kem, get new process descriptor task_struct memory if (!tsk) return null;ti = Alloc_ Thread_info (TSK); Task useless, use get_free_pages to get two page size memory if (!ti) {//ti If allocation fails, also release original memory free_task_struct (TSK); return NULL;} err = Arch_dup_ Task_struct (tsk, orig);//Copy the old task_struct to the new Task_structif (err) goto out;tsk->stack = TI; The stack that changes the new process points to the new thread_info err = Prop_local_init_single (&tsk->dirties); if (err) goto Out;setup_thread_ Stack (tsk, orig);//link task_struct and Thread_info, determine memory layout, point to Clear_user_return_notifier (TSK); Clear_tsk_need_resched ( TSK); stackend = End_of_stack (tsk); *stackend = stack_end_magic;/* for overflow detection */#ifdef CONFIG_CC_ Stackprotectortsk->stack_canary = Get_random_int (); #endif/* One for us, one for whoever does the "Release_task ()" (Usua Lly parent) */atomic_set (&tsk->usage,2); To set the usage count of the new process to 2atomic_set (&TSK->FS_EXCL, 0), #ifdef config_blk_dev_io_tracetsk->btrace_seq = 0; #endiftsk- >splice_pipe = Null;account_kernel_stack (Ti, 1); return Tsk;out:free_thread_info (TI); free_task_struct (TSK); return NULL;}

int arch_dup_task_struct (struct task_struct *dst, struct task_struct *src) {int ret;*dst = *src;//Copy Two process descriptor if (fpu_ Allocated (&SRC->THREAD.FPU)) {//If the FPU of the source is set, then also assign the FPU memory of thread memset (&DST->THREAD.FPU, 0, sizeof (dst- >THREAD.FPU)///Fpuret = Fpu_alloc (&DST->THREAD.FPU), if (ret) return ret;fpu_copy (&dst-> THREAD.FPU, &SRC->THREAD.FPU);//assigned, direct copy}return 0;}


Key code in Copy_process 2

Settings for some fields

p->did_exec = 0;//Record the number of times the process emitted execve () Delayacct_tsk_init (P);/* must remain after dup_task_struct () */copy_flags (clone _flags, p); Init_list_head (&p->children); Init_list_head (&p->sibling); rcu_copy_process (P);p Vfork_done = Null;spin_lock_init (&p->alloc_lock); init_sigpending (&p->pending);//Initialize good signal processing// Initialize the statistics field of the CPU P->utime = Cputime_zero;p->stime = Cputime_zero;p->gtime = cputime_zero;p->utimescaled = cputime_zero;p->stimescaled = Cputime_zero;

Key code in Copy_process 2

Set scheduling information for a child process

/* Perform Scheduler related setup. Assign this task to a CPU. */sched_fork (P, clone_flags);  Complete initialization of the new process scheduler data structure

Key code in Copy_process 3

Copying and sharing parts of a process

if ((retval = Audit_alloc (P))) goto bad_fork_cleanup_policy;/* Copy all the process information */if ((retval = Copy_semund O (Clone_flags, p))) Goto bad_fork_cleanup_audit;if ((retval = Copy_files (Clone_flags, p)) Goto BAD_FORK_CLEANUP_ Semundo;if ((retval = Copy_fs (Clone_flags, p))) Goto bad_fork_cleanup_files;if ((retval = Copy_sighand (Clone_flags, p))) Goto Bad_fork_cleanup_fs;if ((retval = copy_signal (Clone_flags, p))) Goto bad_fork_cleanup_sighand;if ((retval = copy_mm (Clone_flags, p)))        Process address space processing goto bad_fork_cleanup_signal;if ((retval = copy_namespaces (Clone_flags, p))) Goto Bad_fork_cleanup_mm;if (( retval = Copy_io (Clone_flags, p)) goto bad_fork_cleanup_namespaces;//Set the kernel stack of the subprocess retval = Copy_thread (clone_flags, stack _start, Stack_size, p, regs);


Copy_files

static int copy_files (unsigned long clone_flags, struct task_struct * tsk) {struct files_struct *oldf, *newf;int error = 0; /* * A background process May is not having any files ... */oldf = current->files; Original Process files_structif (!oldf) goto out;if (Clone_flags & Clone_files) {//Share Open File Table Atomic_inc (&oldf->count); /Add reference count goto out;} NEWF = DUP_FD (Oldf, &error); if (!NEWF) goto out;tsk->files = Newf;error = 0;out:return error;}


Copy_thread

int Copy_thread (unsigned long clone_flags, unsigned long sp,unsigned long unused,struct task_struct *p, struct pt_regs *re GS) {struct Pt_regs *childregs;struct task_struct *tsk;int err;//fill contains all registers Childregs = Task_pt_regs (p); *childregs = *             Regs;childregs->ax = 0;            The return value of the child process is 0CHILDREGS->SP = SP;  The user space stack address of the child process P->THREAD.SP = (unsigned long) childregs; User space pointing to child process P->thread.sp0 = (unsigned long) (childregs+1);   Point to Pt_regsp->thread.ip = (unsigned long) ret_from_fork in the child process system space stack; The child process starts calling the function Task_user_gs (p) = Get_user_gs (regs);p->thread.io_bitmap_ptr = Null;tsk = Current;err =-enomem;memset ( p->thread.ptrace_bps, 0, sizeof (p->thread.ptrace_bps)); if (Unlikely (Test_tsk_thread_flag (tsk, Tif_io_bitmap) ) {p->thread.io_bitmap_ptr = Kmemdup (tsk->thread.io_bitmap_ptr,io_bitmap_bytes, GFP_KERNEL); if (!p-> THREAD.IO_BITMAP_PTR) {P->thread.io_bitmap_max = 0;return-enomem;} Set_tsk_thread_flag (P, tif_io_bitmap);} Err = 0;/* * Set A new TLS for THe child thread? */if (Clone_flags & clone_settls) Err = Do_set_thread_area (p,-1, struct USER_DESC __user *) childregs->si, 0); if (E RR && p->thread.io_bitmap_ptr) {kfree (p->thread.io_bitmap_ptr);p->thread.io_bitmap_max = 0;} return err;}

Key code in Copy_process 4

Get child process PID

if (pid! = &init_struct_pid) {retval =-enomem;pid = Alloc_pid (P->nsproxy->pid_ns);//Assign Good one pidif (!pid) goto bad _fork_cleanup_io;if (Clone_flags & clone_newpid) {retval = Pid_ns_prepare_proc (P->nsproxy->pid_ns); if ( retval < 0) goto Bad_fork_free_pid;}} P->pid = PID_NR (PID);//Get Global Nrp->tgid = p->pid;if (Clone_flags & clone_thread) P->tgid = current-> Tgid;  Set the thread group IDIF (current->nsproxy! = p->nsproxy) {retval = Ns_cgroup_clone (P, PID); if (retval) goto Bad_fork_free_pid ;} Change the Child_tidptr memory value of the child process user address space P->set_child_tid = (Clone_flags & clone_child_settid)? Child_tidptr:null;  Also save on the corresponding values go to/* * Clear TID on mm_release ()? *///in Mm_release, write 0 to Child_tidptr P->clear_child_tid = (Clone_flags & clone_child_cleartid)? Child_tidptr:null;


Key code in copy_process 5

Thread or process

/* Clone_parent re-uses the old PARENT */if (Clone_flags & (clone_parent| Clone_thread)) {  //In the same process group as the parent process, the same father p->real_parent = current->real_parent;//The current thread and the created thread's father the same thread p-> parent_exec_id = current->parent_exec_id;} else {                          //otherwise real_parent points to this process p->real_parent = current;p->parent_exec_id = current->self_exec_id;}

Thread

if (Clone_flags & clone_thread) {  //Sub-processes are put into the same thread group Current->signal->nr_threads++;atomic_inc (¤t-> signal->live); Atomic_inc (¤t->signal->sigcnt);p->group_leader = current->group_leader;// Point to Thread group leader List_add_tail_rcu (&p->thread_group, &p->group_leader->thread_group);//join to Thread Group}

Execve

/* * SYS_EXECVE () executes a new program. */long sys_execve (const char __user *name,const char __user *const __user *argv,const char __user *const __user *envp, str UCT Pt_regs *regs) {long Error;char *filename;filename = getname (name);    Find executable filename error = ptr_err (filename), if (Is_err (filename)) return error;error = Do_execve (filename, argv, ENVP, regs); Ifdef config_x86_32if (Error = = 0) {/* Make sure we don ' t return using sysenter: *                /Set_thread_flag (Tif_iret);        } #endifputname (filename); return error;}

Key code in DO_EXECVE

FILE = open_exec (filename),//Find Fileretval = Ptr_err (file), if (Is_err (file)) goto out_unmark;sched_exec ();bprm-> FILE = file;//sets the corresponding parameter Bprm->filename = filename;//name bprm->interp = Filename;retval = Bprm_mm_init (BPRM); if (retval Goto OUT_FILE;BPRM->ARGC = count (argv, max_arg_strings);//Calculation length

retval = Search_binary_handler (bprm,regs);  Used to find an appropriate binary format, such as A.out, elf format, etc.


int Search_binary_handler (struct LINUX_BINPRM *bprm,struct pt_regs *regs) {unsigned int depth = Bprm->recursion_depth ; int try,retval;struct Linux_binfmt *fmt;retval = Security_bprm_check (BPRM), if (retval) return retval;/* kernel module Loader fixup *//* So we don ' t try to load run modprobe in kernel space. */set_fs (user_ds); retval = AUDIT_BPRM (BPRM); if (retval) return retval;retval =-enoent;for (try=0; try<2; try++) {// Once the module is loaded, try Read_lock (&binfmt_lock) again, List_for_each_entry (FMT, &formats, LH) {int (*FN) (struct LINUX_BINPRM *, struct Pt_regs *) = Fmt->load_binary;if (!FN) continue;if (!try_module_get (Fmt->module)) Continue;read_unlock ( &binfmt_lock); retval = fn (BPRM, regs);//perform the corresponding loading function  <span style= "font-family:arial, Helvetica, Sans-serif;" >load_aout_binary</span>
Explain the points

(1) Load_aout_binary for the a.out executable file format, in addition to support the ELF and script format file loading;


Process management process (thread) creation

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.