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