Chinaunix首页 | 论坛 | 博客
  • 博客访问: 177449
  • 博文数量: 30
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-23 19:45
文章分类

全部博文(30)

文章存档

2016年(2)

2010年(3)

2009年(8)

2008年(17)

我的朋友

分类: LINUX

2008-11-22 21:45:39

前面几篇文章对进程作了一点初步了解,下面就是我关于创建进程的学习,进程的创建涉及到了很多知识,我一时半会不能全搞懂,所以这里只能照抄资料。在内核中,fork()、clone()、vfork()创建子进程的系统调用,最终由函数do_fork()来根据clone_flags参数的值来实现的。看它的源代码:

 

long do_fork(unsigned long clone_flags,
              unsigned long stack_start,
              struct pt_regs *regs,
              unsigned long stack_size,
              int __user *parent_tidptr,
              int __user *child_tidptr)
{
        struct task_struct *p;
        int trace = 0;
        struct pid *pid = alloc_pid();//解释1

        long nr;

        if (!pid)
                return -EAGAIN;
        nr = pid->nr;
        if (unlikely(current->ptrace)) {//解释2

                trace = fork_traceflag (clone_flags);
                if (trace)
                        clone_flags |= CLONE_PTRACE;
        }

        p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);//解释3

if (!IS_ERR(p)) {
                struct completion vfork;

                if (clone_flags & CLONE_VFORK) {
                        p->vfork_done = &vfork;
                        init_completion(&vfork);
                }

                if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {//解释4

                       
                        sigaddset(&p->pending.signal, SIGSTOP);
                        set_tsk_thread_flag(p, TIF_SIGPENDING);
                }

                if (!(clone_flags & CLONE_STOPPED))
                        wake_up_new_task(p, clone_flags);//解释5

                else
                        p->state = TASK_STOPPED;//解释6


                if (unlikely (trace)) {//解释7

                        current->ptrace_message = nr;
                        ptrace_notify ((trace << 8) | SIGTRAP);
                }
         if (clone_flags & CLONE_VFORK) {//解释8

                        freezer_do_not_count();
                        wait_for_completion(&vfork);
                        freezer_count();
                        if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) {
                                current->ptrace_message = nr;
                                ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
                        }
                }
        } else {
                free_pid(pid);
                nr = PTR_ERR(p);
        }
        return nr;//解释9

}


这个函数主要完成一下工作:
1.查找pidmap_array位图,为子进程分配新的PID,由函数alloc_pid()完成,pid->nr就是新进程的PID。
2.检查父进程的ptrace字段(current->ptrace):如果它的值不等于0,说明有另外一个进程正在跟踪父进程,因而,do_fork()检查debugger程序是否自己想跟踪子进程。
3.调用copy_process()复制进程描述符。如果所有必须的资源都是可用的,该函数返回刚创建的task_struct描述符的地址。这个函数很关键,后面再讲。
4. 如果设置了CLONE_STOPPED标志,或者必须跟踪子进程,即在p->ptrace中设置了PT_PTRACED标志,那么子进程的状态被设 置成TASK_STOPPED,并为自进程增加挂起的SIGSTOP信号。在另外一个进程把子进程的状态恢复为TASK_RUNNING之前(通常是通过 发送SIGCONT信号),子进程将一直保持状态TASK_STOPPED。
5.如果没有设置CLONE_STOPPED标志,则调用wake_up_new_task()函数。
6.如果设置了CLONE_STOPPED标志,则把子进程设置为TASK_STOPPED状态。
7. 如果父进程被跟踪,则把子进程的PID存入current的ptrace_message字段并调用ptrace_notify()。 ptrace_notify()使当前运行进程停止运行,并向当前进程的父进程发送SIGCHLD信号。子进程的祖父进程是跟踪父进程的debugger 进程。SIGCHILD信号通知debugger进程:当前进程(current进程)已将创建了一个子进程,可以通过查找 current->ptrace_message字段获得子进程的PID。
  
上面的解释是ULK中的,我的理解是:如果当前被 跟踪,则此时涉及3个进程:跟踪父进程的debugger进程(就叫他祖父进程吧),当前进程(叫他父进程)以及当前进程创建的进程(即子进程)。也就是 说父进程被跟踪了,停止运行,通知祖父进程debugger(向debugger发送了SIGCHLD信号),自己fork了一个子进程,可以通过 current->ptrace_message字段去获得子进程的PID。
8.如果设置了CLONE_VFORK标志( if (clone_flags & CLONE_VFORK)),则把父进程插入到等待队列,并挂起父进程知道子进程释放自己的内存地址空间,即就是等待子进程结束或执行新的程序。
9.结束并返回子进程的PID,注意这里就是返回值之一,在父进程中返回的子进程的PID。
阅读(2002) | 评论(0) | 转发(1) |
0

上一篇:进程的组织

下一篇:总结与反思

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