Chinaunix首页 | 论坛 | 博客
  • 博客访问: 622057
  • 博文数量: 69
  • 博客积分: 1891
  • 博客等级: 上尉
  • 技术积分: 1359
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-20 23:38
文章分类

全部博文(69)

文章存档

2012年(46)

2011年(23)

分类: LINUX

2012-02-12 16:43:45

这里接着讲do_fork的第一步——copy_process
这里是具体的调用
  1. p = copy_process(clone_flags, stack_start, regs, stack_size,
  2.              child_tidptr, NULL, trace);
接着看copy_process的代码,copy_process的代码比较长,这里先介绍一下主题流程,再将代码一段一段进行分析:
1、检查clone_flags参数,clone_flages参数参数如下:
  1. #define CSIGNAL        0x000000ff    /* signal mask to be sent at exit */
  2. #define CLONE_VM    0x00000100    /* set if VM shared between processes */
  3. #define CLONE_FS    0x00000200    /* set if fs info shared between processes */
  4. #define CLONE_FILES    0x00000400    /* set if open files shared between processes */
  5. #define CLONE_SIGHAND    0x00000800    /* set if signal handlers and blocked signals shared */
  6. #define CLONE_PTRACE    0x00002000    /* set if we want to let tracing continue on the child too */
  7. #define CLONE_VFORK    0x00004000    /* set if the parent wants the child to wake it up on mm_release */
  8. #define CLONE_PARENT    0x00008000    /* set if we want to have the same parent as the cloner */
  9. #define CLONE_THREAD    0x00010000    /* Same thread group? */
  10. #define CLONE_NEWNS    0x00020000    /* New namespace group? */
  11. #define CLONE_SYSVSEM    0x00040000    /* share system V SEM_UNDO semantics */
  12. #define CLONE_SETTLS    0x00080000    /* create a new TLS for the child */
  13. #define CLONE_PARENT_SETTID    0x00100000    /* set the TID in the parent */
  14. #define CLONE_CHILD_CLEARTID    0x00200000    /* clear the TID in the child */
  15. #define CLONE_DETACHED        0x00400000    /* Unused, ignored */
  16. #define CLONE_UNTRACED        0x00800000    /* set if the tracing process can't force CLONE_PTRACE on this clone */
  17. #define CLONE_CHILD_SETTID    0x01000000    /* set the TID in the child */
  18. /* 0x02000000 was previously the unused CLONE_STOPPED (Start in stopped state)
  19.    and is now available for re-use. */
  20. #define CLONE_NEWUTS        0x04000000    /* New utsname group? */
  21. #define CLONE_NEWIPC        0x08000000    /* New ipcs */
  22. #define CLONE_NEWUSER        0x10000000    /* New user namespace */
  23. #define CLONE_NEWPID        0x20000000    /* New pid namespace */
  24. #define CLONE_NEWNET        0x40000000    /* New network namespace */
  25. #define CLONE_IO         0x80000000    /* Clone io context */
参数比较多,clone_flags是这些参数的组合,这个检查的作用就是防止无效的组合进入。

  1.    if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
  2.         return ERR_PTR(-EINVAL);

  3.     /*
  4.      * Thread groups must share signals as well, and detached threads
  5.      * can only be started up within the thread group.
  6.      */
  7.     if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
  8.         return ERR_PTR(-EINVAL);

  9.     /*
  10.      * Shared signal handlers imply shared VM. By way of the above,
  11.      * thread groups also imply shared VM. Blocking this case allows
  12.      * for various simplifications in other code.
  13.      */
  14.     if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
  15.         return ERR_PTR(-EINVAL);

  16.   if ((clone_flags & CLONE_PARENT) &&
  17. current->signal->flags & SIGNAL_UNKILLABLE)
  18. return ERR_PTR(-EINVAL);
以上有三种组合是不通过的:
1)CLONE_NEWNS 和 CLONE_FS组合,一方面需要创建一个新的命名空间,同时又要与父进程公用文件系统信息,这显然是不成立的,不同的命名空间就是用来分隔系统资源的,这样资源跨命名空间的情况是不允许的。

2)CLONE_THREADE设置了,但是没有设置CLONE_SIGHAND:在用CLONE_THREAD创建一个线程时,必须用CLONE_SIGHAND激活信号共享

3)只有在父子进程之间共享虚拟地址空间(CLONE_VM)时,才能提供共享的信号处理程序
信号相关的内容后面会详细讲解的。

4)防止产生init进程的兄弟,如果当前的cloner是init进程(即是current->signal->flags设置了SIGNAL_UNKILLABLE),如果同时设置了CLONE_PARENT(新进程的parent设置为cloner的parent),那么这样生成的进程将是init进程的兄弟,由于在退出的时候没有父进程来对他进行回收,这样的进程会形成僵尸进程,所以要避免这样的进程产生。

PS:
还有一个问题就是ERR_PTR(-EINVAL),copy_process函数定义的返回结果是task_struct的指针,而EINVAL是一个整数,这里用ERR_PTR进行了转化
  1. static inline void * __must_check ERR_PTR(long error)
  2. {
  3.     return (void *) error;
  4. }
ERR_PTR将EINVAL转化成void指针进行返回,这样就可以了。
再看看ERR_PTR函数,前面有个__must_check,这个是什么呢,看看具体的代码
  1. #if __GNUC_MINOR__ >= 4
  2. #define __must_check        __attribute__((warn_unused_result))
  3. #endif
这里定义了宏__must_check,是利用gcc编译器的_attribute_给函数加上了属性,这个属性的作用是: 让编译器检查所有调用者是否都检查函数的结果。这确保调用者适当地检验函数结果,从而能够适当地处理错误。
也就是说,调用者在拿到结果后必须要进行检查是否返回了正确的结构,否则编译器会给出提示信息。


2、dup_task_struct
dup_task_struct的主要工作是生成新进程的task_struct结构,主要完成复制task_struct的工作,后面会详细分析这个函数的。


3、检查资源限制
  1. if (atomic_read(&p->real_cred->user->processes) >=
  2.             task_rlimit(p, RLIMIT_NPROC)) {
  3.         if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
  4.          p->real_cred->user != INIT_USER)
  5.             goto bad_fork_free;
  6.     }
4、完成一些初始化工作

5、sched_fork:完成调度相关的设置,将这个task分配给CPU
  1. sched_fork(p, clone_flags);
6、复制共享进程的的各个部分

7、设置各个ID以及进程关系,等等



阅读(3305) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~