1. 分配pid
long pid = alloc_pidmap();
2. 检查ptrace
if (unlikely(current->ptrace)) { /*父进程被跟踪*/
trace = fork_traceflag (clone_flags);
if (trace) /* 如果不是内核线程(no UNTRACED flag) */
clone_flags |= CLONE_PTRACE;
}
3. 调用copy_process() 复制进程描述符
4. 检查vfork flag. 如果是初始化vfork wait flag
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
}
5. 检查是否pending
if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {
/*
* We'll start up with an immediate SIGSTOP.
*/
sigaddset(&p->pending.signal, SIGSTOP);
set_tsk_thread_flag(p, TIF_SIGPENDING);
}
6. 检查stopped标志
1). 如果没有设置stopped标志
if (!(clone_flags & CLONE_STOPPED))
wake_up_new_task(p, clone_flags);
2). stopped被设置
p->state = TASK_STOPPED;
7. wake_up_new_task()
1). 如果未设VM, 插子进程在父进程运行队列,恰好在父进程前面
if (!(clone_flags & CLONE_VM)) {
/*
* The VM isn't cloned, so we're in a good position to
* do child-runs-first in anticipation of an exec. This
* usually avoids a lot of COW overhead.
*/
if (unlikely(!current->array))
__activate_task(p, rq);
else {
p->prio = current->prio;
list_add_tail(&p->run_list, ¤t->run_list); //前面
p->array = current->array;
p->array->nr_active++;
rq->nr_running++;
}
set_need_resched();
}
2). 否则不是同一cpu或者VM被设置,子进程插入父进程运行队列的队尾
__activate_task(p, rq);
8. 检查跟踪标志
if (unlikely (trace)) {
current->ptrace_message = pid; /* pid存入message */
ptrace_notify ((trace << 8) | SIGTRAP); /*SIGCHLD, 通知子进程的祖父进程(当前进程的父进程debugger), current创建了子进程,可以通过查找current->ptrace_message字段获得子进程的PID*/
}
9. 如果设置VFORK, 把父插入等待队列,直到子进程释放自己的内存地址空间
10. 结束返回子进程的pid