Linux task_struct parent 和 real_parent 的区别

注:以下信息总结自邮件列表 https://www.mail-archive.com/[email protected]/msg04745.html



Linux的 process descriptor 由 task_struct 结构表示

    struct task_struct {
        // ...
        /* real parent process */
        struct task_struct __rcu *real_parent; 

        /* recipient of SIGCHLD, wait4() reports */
        struct task_struct __rcu *parent; 
    }

这里,出现了两个parent,real_parentparentfork()一个子进程的同时,更新real_parent

至于信号SIGCHLD,谁ptrace了这个子进程,子进程结束后,SIGCHLD就发给对应的process,也就是这里的parent。换句话说,parent是在ptrace的时候设置的。




11/20/2015

在 Linux 2.6.11.12 do_fork()所调用的copy_process()中,若child->ptracePT_PTRACED标志被置位,将会调用__ptrace_link(child, current->parent)

__ptrace_link()child添加至真实parent的trace list后,修改child->parent,使其指向current->parent。从这里可以很直观地看出,task_struct.parent所指向的,是跟踪(trace)自己的进程,与之对应的,real_parent则是fork他的那个进程。

/*
 * This creates a new process as a copy of the old one,
 * but does not actually start it yet.
 *
 * It copies the registers, and all the appropriate
 * parts of the process environment (as per the clone
 * flags). The actual kick-off is left to the caller.
 */
static task_t *copy_process(unsigned long clone_flags,
                            unsigned long stack_start,
                            struct pt_regs *regs,
                            unsigned long stack_size,
                            int __user *parent_tidptr,
                            int __user *child_tidptr,
                            int pid)
{
    // ...

    /* CLONE_PARENT re-uses the old parent */
    if (clone_flags & (CLONE_PARENT|CLONE_THREAD))
        p->real_parent = current->real_parent;
    else
        p->real_parent = current;
    p->parent = p->real_parent;
    // parent now is the same as real_parent

    // ...

    // if the PT_PTRACED bit is set
    if (p->ptrace & PT_PTRACED)
        __ptrace_link(p, current->parent);

    // ...
}


/*
 * ptrace a task: make the debugger its new parent and
 * move it to the ptrace list.
 *
 * Must be called with the tasklist lock write-held.
 */
void __ptrace_link(task_t *child, task_t *new_parent)
{
    if (!list_empty(&child->ptrace_list))
        BUG();
    if (child->parent == new_parent)
        return;
    // added to parent’s trace list
    // note: child->parent == child->real_parent
    list_add(&child->ptrace_list,
             &child->parent->ptrace_children);
    REMOVE_LINKS(child);

    // child->parent now points to the debugger
    child->parent = new_parent;
    SET_LINKS(child);
}




11/21/2015,Linux 2.6.11.12

进程退出时,将调用 exit_nofity(),这里所通知的,也是parent域所指向的进程(如果进程没有被跟踪,将有parent == real_parent)。

// file: exit.c
void exit_notify(struct task_struct *tsk)
{
    // ...

    /* If something other than our normal parent is ptracing us, then
     * send it a SIGCHLD instead of honoring exit_signal.  exit_signal
     * only has special meaning to our real parent.
     */
    if (tsk->exit_signal != -1 && thread_group_empty(tsk)) {
        int signal = tsk->parent == tsk->real_parent
                     ? tsk->exit_signal : SIGCHLD;
        do_notify_parent(tsk, signal);
    } else if (tsk->ptrace) {
        do_notify_parent(tsk, SIGCHLD);
    }

    // ...
}

你可能感兴趣的:(linux)