设为首页 加入收藏

TOP

内核进程的复制(一)
2012-11-01 15:47:27 来源: 作者: 【 】 浏览:3001
Tags:内核 进程 复制
  在通过fork系统调用创建进程时,最终会进入内核的do_fork函数,这个函数的大部分工作都是进程的复制,就是把大部分工作都委托给函数copy_process函数来完成。本博文主要讨论进程的复制工作。
  
  下面分成几个段,所在代码包含了整个copy_process函数
  
  一,标志检查
  
  [cpp]
  
  static struct task_struct *copy_process(unsigned long clone_flags,
  
  unsigned long stack_start,
  
  struct pt_regs *regs,
  
  unsigned long stack_size,
  
  int __user *child_tidptr,
  
  struct pid *pid)
  
  {
  
  int retval;
  
  struct task_struct *p;
  
  int cgroup_callbacks_done = 0;
  
  if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
  
  return ERR_PTR(-EINVAL);
  
  /*
  
  * Thread groups must share signals as well, and detached threads
  
  * can only be started up within the thread group.
  
  */
  
  if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
  
  return ERR_PTR(-EINVAL);
  
  /*
  
  * Shared signal handlers imply shared VM. By way of the above,
  
  * thread groups also imply shared VM. Blocking this case allows
  
  * for various simplifications in other code.
  
  */
  
  if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
  
  return ERR_PTR(-EINVAL);
  
  retval = security_task_create(clone_flags);
  
  if (retval)
  
  goto fork_out;
  
  这是函数的开始部分,先进行传入的参数检查,主要是:
  
  如果创建进程的时候,要求创建一个新的命名空间(CLONE_NEWNS),并且同时要求与父进程共享所有的文件系统信息(CLONE_FS),这是不允许的。此时是要求共享其文件系统。
  
  在用CLONE_THREAD标志时,必须使用CLONE_SIGHAND标志,后者表示共享相同的信号处理表。
  
  在使用CLONE_SIGHAND标志时,必须使用CLONE_VM标志,后者表示子进程和你进程共享虚拟地址空间,也只有这个时候,才能提供共享的信号处理程序。
  
  二,建立副本
  
  [cpp]
  
  retval = -ENOMEM;
  
  p = dup_task_struct(current);
  
  <span>  </span>if (!p)
  
  <span>      </span>goto fork_out;
  
  dup_task_struct用来建立父进程的副本,函数如下:
  
  [cpp]
  
  static struct task_struct *dup_task_struct(struct task_struct *orig)
  
  {
  
  struct task_struct *tsk;
  
  struct thread_info *ti;
  
  int err;
  
  prepare_to_copy(orig);
  
  tsk = alloc_task_struct();
  
  if (!tsk)
  
  return NULL;
  
  ti = alloc_thread_info(tsk);
  
  if (!ti) {
  
  free_task_struct(tsk);
  
  return NULL;
  
  }
  
  *tsk = *orig;//将父进程的内容填充新的进程
  
  tsk->stack = ti;
  
  err = prop_local_init_single(&tsk->dirties);
  
  if (err) {
  
  free_thread_info(ti);
  
  free_task_struct(tsk);
  
  return NULL;
  
  }
  
  setup_thread_stack(tsk, orig);
  
  #ifdef CONFIG_CC_STACKPROTECTOR
  
  tsk->stack_canary = get_random_int();
  
  #endif
  
  /* One for us, one for whoever does the “release_task()” (usually parent) */
  
  atomic_set(&tsk->usage,2);//使用计数器置为2,表示当前进程描述符处于活动状态。
  
  atomic_set(&tsk->fs_excl, 0);
  
  #ifdef CONFIG_BLK_DEV_IO_TRACE
  
  tsk->btrace_seq = 0;
  
  #endif
  
  tsk->splice_pipe = NULL;
  
  return tsk;
  
  }
  
  调用alloc_task_struct为新进程分配进程结构,返回tsk指针。
  
  为新的进程分配一个核心态栈,也就是tsk->stack.栈和thread_info一同保存在一个联合结构中。thread_info用于保存进程所需的特定于处理器的底层信息,定义如下:
  
  [cpp]
  
  struct thread_info {
  
  struct task_struct  *task;      /* 不前的主进程 */
  
  unsigned long       flags;
  
  struct exec_domain  *exec_domain;   /* 执行区间 */
  
  int         preempt_count;  /* 内核抢占所需的一个计数器*/
  
  __u32 cpu; /* 进程正在其上执行的CPU数目 */
  
  struct restart_block    restart_block;//用于实现信号机制
  
  };
  
  而进程的栈和thread_info的联合体定义如下:
  
  [cpp]
  
  union thread_union {
  
  struct thread_info thread_info;
  
  unsigned long stack[THREAD_SIZE/sizeof(long)];
  
  };

[1] [2] [3] [4] [5] 下一页

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/16/16
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C/C++学习指针一些事 下一篇C/C++学习之++i 和 i++..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: