本系列文章由张同浩编写,转载请注明出处:http://blog.csdn.net/muge0913/article/details/7479451
在上次的文章中详细的介绍了几个系统调用,它们最终都是调用了do_fork来实现进程的创建。do_fork主要完成了进程描述符的创建和pid的创建,以及进程描述符的拷贝。
本系列文章所用源码均来自2.6.38.
源码分析如下:
/* * 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. */ /*这部分代码是在2.6.38中实现的*/ /*参数clone_flags由两部分组成,最低的一个字节为信号掩码,用于指定子进程退出时 *子进程向父进程发出的信号,通过sys_fork和sys_vfork知道它们的信号就是SIGCHLD,而 *clone由用户自己决定。对于第二部分表示资源和特性标志位,fork为0,vfork为CLONE_VFORK和CLONE_VM *而clone由用户自己定义。 */ 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) { /*定义一个进程描述符*/ struct task_struct *p; int trace = 0; long nr;//子进程号 /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ /* *一些必要的检查工作,我们会发现在sys_fork,sys_vfork,kernel_thread中都没有传递CLONE_NEWUSER可见 *以下这些代码没有执行,这个检查主要是为sys_clone使用的。 */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD)//跟踪标志被设置,出错。 return -EINVAL; /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } /* * We hope to recycle these flags after 2.6.26 */ /*这些代码也是就一些检查工作*/ if (unlikely(clone_flags & CLONE_STOPPED)) { static int __read_mostly count = 100; if (count > 0 && printk_ratelimit()) { char comm[TASK_COMM_LEN]; count--; printk(KERN_INFO "fork(): process `%s' used deprecated " "clone flags 0x%lx\n", get_task_comm(comm, current), clone_flags & CLONE_STOPPED); } } /* * When called from kernel_thread, don't do user tracing stuff. */ if (likely(user_mode(regs))) trace = tracehook_prepare_clone(clone_flags); /*copy_process来完成具体进程的创建,在系统资源丰富的条件下,来完成进程描述符的拷贝,当然进程号不同*/ p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); /* *调用完copy_process后如果没有指定CLONE_STOPPED就会调用下面的wake_up_new_task把新建的进程放到 *运行队列中。如果父子进程在同一个cpu中运行,且在没有设置CLONE_VM标志,则会采用写实复制技术,把子进程放到 *父进程的前面,如果子进程调用了exec就会避免一系列不必要的复制操作。 */ /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ /*IS_ERR()判断p是否正确*/ if (!IS_ERR(p)) { /*进程描述符创建成功后,根据clone_flags来设置进程状态*/ struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); /* *在sys_fork,sys_vfork,kernel_thread中没有CLONE_PARENT_SETTID且parent_tidptr=NULL *为sys_clone使用 */ if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); /* *sys_fork 或 sys_clone检查的,如果设置了就把父进程放进等待队列中 */ if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } audit_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; if (unlikely(clone_flags & CLONE_STOPPED)) { /* * We'll start up with an immediate SIGSTOP. */ sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); __set_task_state(p, TASK_STOPPED); } else { wake_up_new_task(p, clone_flags); } tracehook_report_clone_complete(trace, regs, clone_flags, nr, p); if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork);//等待队列 freezer_count(); tracehook_report_vfork_done(p, nr); } } else { nr = PTR_ERR(p); } return nr; }