注:以下信息总结自邮件列表 https://www.mail-archive.com/kernelnewbies@kernelnewbies.org/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_parent
和parent
。fork()
一个子进程的同时,更新real_parent
。
至于信号SIGCHLD
,谁ptrace了这个子进程,子进程结束后,SIGCHLD
就发给对应的process,也就是这里的parent
。换句话说,parent
是在ptrace的时候设置的。
11/20/2015
在 Linux 2.6.11.12 do_fork()
所调用的copy_process()
中,若child->ptrace
的 PT_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);
}
// ...
}