if (unlikely(current->ptrace)) {
trace = fork_traceflag (clone_flags);
if (trace)
clone_flags |= CLONE_PTRACE;
}
判断当前进程是否处于被跟踪状态。如果当前进程处于被跟踪调试状态且传进来的实际参数 clone_flags 没有使用标记 CLONE_UNPTRACED 强调子进程不可被跟踪,那么在标记 clone_flags 中添加标记 CLONE_PTRACE ,使创建的进程也处于被跟踪调试状态!
此时current 为进程0 ,current->ptrace = 0 没有处于被跟踪调试状态!
p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
完成具体进城创建工作。该函数创建一个但前进程的进程描述符的拷贝(内容不完全相同)作为新创建进程描述符,并将描述符地址返回!
/*
* Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly.
*/
if (!IS_ERR(p)) {
判断返回的描述符是否正确!
static inline long IS_ERR(const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L)
若描述符地址大于FFFFFC18 则说明描述符创建错误!
书上说此处有一个书写bug !在内核初始化内存时,在0xFFFFF000 ~ 0xFFFFFFFF之间保留了一个物理页面大小的物理空间用于捕捉内核错误 (unsigned long)-1000L 应该为 (unsigned long)-0x1000L!(因为 -0x1000 才是 0xFFFFF000)
struct completion vfork;
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
}
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);
}
若存在以上标志,在新建进程处理链表中添加信号SIGSTOP,并设置进程的有信号处理标记 TIF_SIGPENDING,这样在进程 获得处理器时会立即处理信号 SIGSTOP,此时进程会立即放弃处理器进入睡眠状态!
if (!(clone_flags & CLONE_STOPPED))
wake_up_new_task(p, clone_flags);
else
p->state = TASK_STOPPED;
若含有CLONE_STOPPED 标记则将新创建进程状态设置为 TASK_STOPPED ,说明新创建的进程不会运行,除非有进程通过信号唤醒它!
若没有 把当前进程添加到当前处理器队列中!
wake_up_new_task() 函数最后分析!
if (unlikely (trace)) {
current->ptrace_message = pid;
ptrace_notify ((trace << 8) | SIGTRAP);
}
if (clone_flags & CLONE_VFORK) {
wait_for_completion(&vfork);
if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
}
若包含 CLONE_VFORK ,则将当前进程添加到新创建子进程的进程描述符中成员变量 vfork_done 包含的等待队列中,在子进程退出或通过系统调用 exec() 执行其他程序时,激活该等待队列中的进程!
} else {
若失败释放到申请的进程描述符
free_pidmap(pid);
pid = PTR_ERR(p);
}
return pid;
返回 进程号
}