用戶空間進程創建接口:fork,vfork,clone函數,這裡只做簡單說明。
fork:使用該系統調用時,子進程復制父進程的全部資源。由於要復制父進程進程描述符給子進程(進程描述的結構很大!!),這一過程開銷是很大的。linux采用了”寫時復制技術”(copy on write,COW),使子進程先共享父進程的物理頁,只有子進程進行寫操作時,再復制對應的物理頁,避免了無用的復制開銷,提高了系統的性能。
實現代碼(x86):arch/x86/kernel/process.c
int sys_fork(struct pt_regs *regs) { return do_fork(SIGCHLD, regs->sp, regs,0, NULL, NULL); }
實現代碼(arm):arch/arm/kernel/sys_arm.c
/* Fork a newtask - this creates a new program thread. * This is called indirectly via a smallwrapper */ asmlinkage int sys_fork(struct pt_regs *regs) { #ifdefCONFIG_MMU return do_fork(SIGCHLD, regs->ARM_sp,regs, 0, NULL, NULL); #else /* can not support in nommu mode */ return(-EINVAL); #endif }
vfork:該系統調用創建的子進程,完全運行在父進程地址空間之上。子進程對地址空間任何數據的修改同樣為父進程所見。vfork執行後父進程堵塞,知道子進程運行結束。
實現代碼(x86):arch/x86/kernel/process.c
intsys_vfork(struct pt_regs *regs) { return do_fork(CLONE_VFORK | CLONE_VM |SIGCHLD, regs->sp, regs, 0,NULL, NULL); }
實現代碼(arm):arch/arm/kernel/sys_arm.c
asmlinkage intsys_vfork(struct pt_regs *regs) { return do_fork(CLONE_VFORK | CLONE_VM |SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); }
clone:該調用是linux系統所特有的,其NPTL的實現依賴此函數。與fork,vfork相比clone對進程創建有更好的控制能力,能控制子進程和父進程共享何種資源。
實現代碼(x86):arch/x86/kernel/process.c
long sys_clone(unsignedlong 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); }
實現代碼(arm):arch/arm/kernel/sys_arm.c
/* Clone a task- this clones the calling program thread. * This is called indirectly via a smallwrapper */ asmlinkage intsys_clone(unsigned long clone_flags, unsigned long newsp, int __user *parent_tidptr, int tls_val,int__user *child_tidptr, struct pt_regs *regs) { if (!newsp) newsp = regs->ARM_sp; return do_fork(clone_flags, newsp, regs, 0,parent_tidptr, child_tidptr); }
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
上面進程的創建最終依賴於:do_fork,只是向其傳遞了不同的參數。
longdo_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)
參數clone_flags非常重要,fork把其設置為SIGCHLD,vfork把其設置為CLONE_VFORK|CLONE_VM|SIGCHLD,clone由用戶調用時傳遞。總的來說,do_fork由clone_flags決定。其值可以自由組合決定。include/linux/sched.h中宏定義:
/* *cloning flags: */ #define CSIGNAL 0x000000ff /*signal mask to be sent at exit */ #define CLONE_VM 0x00000100 /* set if VM shared between processes */ #define CLONE_FS 0x00000200 /* set if fs info shared between processes*/ #define CLONE_FILES 0x00000400 /* set if open files shared betweenprocesses */ #define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blockedsignals shared */ #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue onthe child too */ #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wakeit up on mm_release */ #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent asthe cloner */ #define CLONE_THREAD 0x00010000 /* Same thread group? */ #define CLONE_NEWNS 0x00020000 /* New namespace group? */ #define CLONE_SYSVSEM 0x00040000 /* share system V SEM_UNDO semantics */ #define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */ #define CLONE_PARENT_SETTID 0x00100000 /*set the TID in the parent */ #define CLONE_CHILD_CLEARTID 0x00200000 /*clear the TID in the child */ #define CLONE_DETACHED 0x00400000 /* Unused,ignored */ #define CLONE_UNTRACED 0x00800000 /* set ifthe tracing process can't force CLONE_PTRACE on this clone */ #define CLONE_CHILD_SETTID 0x01000000 /*set the TID in the child */ #define CLONE_STOPPED 0x02000000 /* Start instopped state */ #define CLONE_NEWUTS 0x04000000 /* Newutsname group? */ #define CLONE_NEWIPC 0x08000000 /* Newipcs */ #defineCLONE_NEWUSER 0x10000000 /* New user namespace */ #define CLONE_NEWPID 0x20000000 /* New pidnamespace */ #define CLONE_NEWNET 0x40000000 /* Newnetwork namespace */ #define CLONE_IO 0x80000000 /* Clone io context */
上面的宏定義都占用了獨立的bit,所以能或|組合使用。其低八位沒有使用,是為了能和信號量組合使用。
內核線程創建接口:
內核線程是一種特殊的進程,它只能運行在內核態,不能訪問用戶空間的內容。內核線程除了各自的棧和硬件上下文外,共享所用資源。內核利用內核線程來完成一些後台工作如kswapd,ksoftirqd。內核線程有kernel_thread創建。
在linux2.6.xxx/arch/x86/include/asm/processor.h /* * create a kernel thread without removing itfrom tasklists */ extern intkernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
在linux2.6.xxx/arch/arm/include/asm/processor.h
/* * Create a new kernel thread */ extern intkernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
參數說明:
fn:新創建的內核線程要執行的函數。
arg:fn的參數。
flags:和do_fork中的clone_flags作用相似。
kernel_thread函數分析:
在linux2.6.xxx/arch/x86/kernel/process.c
/* * Create a kernel thread */ intkernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs;//保存進程的硬件上下文 memset(®s, 0, sizeof(regs)); regs.si = (unsigned long) fn; regs.di = (unsigned long) arg; #ifdefCONFIG_X86_32 regs.ds = __USER_DS; regs.es = __USER_DS; regs.fs = __KERNEL_PERCPU; regs.gs = __KERNEL_STACK_CANARY; #else regs.ss = __KERNEL_DS; #endif regs.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.. */ return do_fork(flags | CLONE_VM |CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); }
分析:
從這段代碼可知,內核線程的創建最終還是調用了do_fork。
arm架構的kernel_thread實現:
/* * Create a kernel thread. */ pid_tkernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); regs.ARM_r4 = (unsigned long)arg; regs.ARM_r5 = (unsigned long)fn; regs.ARM_r6 = (unsignedlong)kernel_thread_exit; regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE |PSR_ISETSTATE; regs.ARM_pc = (unsignedlong)kernel_thread_helper; regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT; return do_fork(flags|CLONE_VM|CLONE_UNTRACED,0, ®s, 0, NULL, NULL); } /* * Shuffle the argument into the correctregister before calling the * thread function. r4 is the thread argument, r5 is the pointerto * the thread function, and r6 points to theexit function. */ extern voidkernel_thread_helper(void); asm( ".pushsection .text\n" " .align\n" " .type kernel_thread_helper,#function\n" "kernel_thread_helper:\n" #ifdefCONFIG_TRACE_IRQFLAGS " bl trace_hardirqs_on\n" #endif " msr cpsr_c,r7\n" " mov r0,r4\n" " mov lr,r6\n" " mov pc,r5\n" " .size kernel_thread_helper,. - kernel_thread_helper\n" " .popsection");
出處:http://blog.csdn.net/muge0913/article/details/7479379