sched_fork 流程
  core.c
  int sched_fork(unsigned long clone_flags, struct task_struct *p)
  {
  unsigned long flags;
  int cpu = get_cpu();
  __sched_fork(clone_flags, p);
  //将子进程状态设置为 TASK_RUNNING
  p->state = TASK_RUNNING;
  //……
  //为子进程分配 CPU
  set_task_cpu(p, cpu);
  put_cpu();
  return 0;
  }
  我们可以看到sched_fork大致完成了两项重要工作,一是将子进程状态设置为 TASK_RUNNING,二是为其分配 CPU
  copy_thread 流程
  int copy_thread(unsigned long clone_flags, unsigned long sp,
  unsigned long arg, struct task_struct *p)
  {
  //获取寄存器信息
  struct pt_regs *childregs = task_pt_regs(p);
  struct task_struct *tsk;
  int err;
  p->thread.sp = (unsigned long) childregs;
  p->thread.sp0 = (unsigned long) (childregs+1);
  memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
  if (unlikely(p->flags & PF_KTHREAD)) {
  //内核线程
  memset(childregs, 0, sizeof(struct pt_regs));
  p->thread.ip = (unsigned long) ret_from_kernel_thread;
  task_user_gs(p) = __KERNEL_STACK_CANARY;
  childregs->ds = __USER_DS;
  childregs->es = __USER_DS;
  childregs->fs = __KERNEL_PERCPU;
  childregs->bx = sp; /* function */
  childregs->bp = arg;
  childregs->orig_ax = -1;
  childregs->cs = __KERNEL_CS | get_kernel_rpl();
  childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
  p->thread.io_bitmap_ptr = NULL;
  return 0;
  }
  //将当前寄存器信息复制给子进程
  *childregs = *current_pt_regs();
  //子进程 eax 置 0,因此fork 在子进程返回0
  childregs->ax = 0;
  if (sp)
  childregs->sp = sp;
  //子进程ip 设置为ret_from_fork,因此子进程从ret_from_fork开始执行
  p->thread.ip = (unsigned long) ret_from_fork;
  //……
  return err;
  }
  copy_thread 这段代码为我们解释了两个相当重要的问题!
  一是,为什么 fork 在子进程中返回0,原因是childregs->ax = 0;这段代码将子进程的 eax 赋值为0
  二是,p->thread.ip = (unsigned long) ret_from_fork;将子进程的 ip 设置为 ret_form_fork 的首地址,因此子进程是从 ret_from_fork 开始执行的
  总结
  新进程的执行源于以下前提:
  dup_task_struct中为其分配了新的堆栈
  调用了sched_fork,将其置为TASK_RUNNING
  copy_thread中将父进程的寄存器上下文复制给子进程,保证了父子进程的堆栈信息是一致的
  将ret_from_fork的地址设置为eip寄存器的值
  终子进程从ret_from_fork开始执行