在上次的文章中详细的介绍了几个系统调用,它们最终都是调用了do_fork来实现进程的创建。do_fork主要完成了进程描述符的创建和pid的创建,以及进程描述符的拷贝。
本系列文章所用源码均来自2.6.38.
源码分析如下:
-
[cpp] view plaincopyprint?
-
/*
-
* 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;
-
-
}
-
-
/*
-
* 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;
-
}
阅读(1496) | 评论(0) | 转发(0) |