Chinaunix首页 | 论坛 | 博客
  • 博客访问: 491904
  • 博文数量: 72
  • 博客积分: 1851
  • 博客等级: 上尉
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 17:50
文章分类

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: LINUX

2011-07-21 08:01:46

系统调用

创建进程的系统调用为:fork,vfork,clone,其相对应的系统调用函数为sys_fork,sys_vfork,

sys_clone,这些函数都与体系相关,将用户空间的参数传递给内核空间,然后调用系统独立函数do_fork:

  1. long do_fork(unsigned long clone_flags,unsigned long stack_start,
  2.     struct pt_regs *regs,unsigned long stack_size,
  3.     int __user *parent_tidptr,int __user *child_tidptr)

其中

clone_flags:指明复制的属性,低字节表示当子进程退出时,发送给父进程的信号数量,高字节表示复制的各项参数

stack_start:复制的用户栈起始地址

regs:原始形式的调用参数,这里使用了与体系相关的结构参数,也就是用户传递的参数

stack_size:用户态栈的大小,一般设置为0

parent_tidptr,child_tidptr: 指向用户态,保存父子进程的线程id(tid),是线程库NPTL必不可少的部分。

不同的fork变体,采用不同的标志位,如:

  1. asmlinkage long sys_fork(struct pt_regs *reg)
  2. {
  3.     return do_fork(SIGCHLD,regs->rsp,regs,0,NULL,NULL);
  4. }
  5. asmlinkage long sys_vfork(struct pt_regs *regs)
  6. {
  7.     return do_fork(CLONE_VFORK|CLONE_VM|SIGCHLD,regs->rsp,reg,0,
  8.             NULL,NULL);
  9. }

sys_clone如下 :

  1. //regs:接收来自用户传递的参数
  2. asmlinkage long sys_clone(struct pt_regs regs)
  3. {
  4.     unsigned long clone_flags;
  5.     unsigned long newsp;
  6.     int __user *parent_tidptr,*child_tidptr;
  7.     /*将参数转化为具体的系统调用参数,传递给do_fork*/
  8.     clone_flags = regs.ebx;
  9.     newsp = regs.ecx;
  10.     parent_tidptr = (int __user *)regs.edx;
  11.     child_tidptr = (int __user*)regs.edi;
  12.     if(!newsp)
  13.         newsp = regs.esp;
  14.     return do_fork(clone_flags,newsp,&regs,0,parent_tidptr,child_tidptr);
  15. }

do_fork的实现

调用关系图如下:

do_fork主要执行下面的步骤:

1.判断clone_flags,调用copy_process,产生子进程,返回子进程之后,开始判断与进程属性相关的各种标志,然后进行相对应的处理。

2.产生新的pid,如果设置了CLONE_NEWPID,则在父进程的命名空间中分配新的pid,否则生成新的命名空间,返回pid

  1. nr = (clone_flags & CLONE_NEWPID)?
  2.     //直接从当前进程的命名空间中分配一个pid
  3.     task_pid_nr_ns(p,current->nsproxy->pid_ns):
  4.         task_pid_vnr(p);//

3.是否是创建线程?如果设置了CLONE_PARENT_SETTID,则需要将刚刚获取的nr写到用户的行参中.

  1. if(clone_flags & CLONE_PARENT_SETTID)
  2.         put_user(nr,parent_tidptr);

4.是否设置了CLONE_VFORK标志,如果设置了该标志,则需要初始化相关数据结构

  1. if(clone_flags & CLONE_VFORK) {
  2.         p->vfork_done = &vfork;
  3.         /*vfork类型定义如下:
  4.          struct completion {
  5.             unsigned int done;
  6.             wait_queue_head_t wait;
  7.          }
  8.         */
  9.         init_completion(&vfork);
  10.     }

5.判断CLONE_STOPPED,开始启动任务

  1. if(!(clone_flags & CLONE_STOPPED))
  2.         //放入调度队列,等待运行,防止一直fork,消耗cpu时间
  3.         wake_up_new_task(p,clone_flags);
  4.     else
  5.         p->state = TASK_STOPPED;

6.如果是vfork机制,则父进程开始睡眠,等待子进程退出,这样就能保证两个进程不能使用相同的进程地址空间。

  1. if(clone_flags & CLONE_VFORK) {
  2.         //设置内存访问标志,防止当前进程访问
  3.         freezer_do_not_count();
  4.         wait_for_completion(&vfork);
  5.         //解除访问标志
  6.         freezer_count();
  7.         …...
  8.     }

阅读(1624) | 评论(0) | 转发(0) |
0

上一篇:fuse中断处理流程

下一篇:进程创建(二)

给主人留下些什么吧!~~