tracehook: death
This moves the ptrace logic in task death (exit_notify) into tracehook.h inlines. Some code is rearranged slightly to make things nicer. There is no change, only cleanup. There is one hook called with the tasklist_lock write-locked, as ptrace needs. There is also a new hook called after exit_state changes and without locks. This is a better place for tracing work to be in the future, since it doesn't delay the whole system with locking. Signed-off-by: Roland McGrath <roland@redhat.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Reviewed-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
fa00b80b3c
commit
2b2a1ff64a
@ -1796,7 +1796,7 @@ extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_
|
|||||||
extern int kill_pgrp(struct pid *pid, int sig, int priv);
|
extern int kill_pgrp(struct pid *pid, int sig, int priv);
|
||||||
extern int kill_pid(struct pid *pid, int sig, int priv);
|
extern int kill_pid(struct pid *pid, int sig, int priv);
|
||||||
extern int kill_proc_info(int, struct siginfo *, pid_t);
|
extern int kill_proc_info(int, struct siginfo *, pid_t);
|
||||||
extern void do_notify_parent(struct task_struct *, int);
|
extern int do_notify_parent(struct task_struct *, int);
|
||||||
extern void force_sig(int, struct task_struct *);
|
extern void force_sig(int, struct task_struct *);
|
||||||
extern void force_sig_specific(int, struct task_struct *);
|
extern void force_sig_specific(int, struct task_struct *);
|
||||||
extern int send_sig(int, struct task_struct *, int);
|
extern int send_sig(int, struct task_struct *, int);
|
||||||
|
@ -471,4 +471,56 @@ static inline int tracehook_notify_jctl(int notify, int why)
|
|||||||
return notify || (current->ptrace & PT_PTRACED);
|
return notify || (current->ptrace & PT_PTRACED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tracehook_notify_death - task is dead, ready to notify parent
|
||||||
|
* @task: @current task now exiting
|
||||||
|
* @death_cookie: value to pass to tracehook_report_death()
|
||||||
|
* @group_dead: nonzero if this was the last thread in the group to die
|
||||||
|
*
|
||||||
|
* Return the signal number to send our parent with do_notify_parent(), or
|
||||||
|
* zero to send no signal and leave a zombie, or -1 to self-reap right now.
|
||||||
|
*
|
||||||
|
* Called with write_lock_irq(&tasklist_lock) held.
|
||||||
|
*/
|
||||||
|
static inline int tracehook_notify_death(struct task_struct *task,
|
||||||
|
void **death_cookie, int group_dead)
|
||||||
|
{
|
||||||
|
if (task->exit_signal == -1)
|
||||||
|
return task->ptrace ? SIGCHLD : -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 (thread_group_empty(task) && !ptrace_reparented(task))
|
||||||
|
return task->exit_signal;
|
||||||
|
|
||||||
|
return task->ptrace ? SIGCHLD : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tracehook_report_death - task is dead and ready to be reaped
|
||||||
|
* @task: @current task now exiting
|
||||||
|
* @signal: signal number sent to parent, or 0 or -1
|
||||||
|
* @death_cookie: value passed back from tracehook_notify_death()
|
||||||
|
* @group_dead: nonzero if this was the last thread in the group to die
|
||||||
|
*
|
||||||
|
* Thread has just become a zombie or is about to self-reap. If positive,
|
||||||
|
* @signal is the signal number just sent to the parent (usually %SIGCHLD).
|
||||||
|
* If @signal is -1, this thread will self-reap. If @signal is 0, this is
|
||||||
|
* a delayed_group_leader() zombie. The @death_cookie was passed back by
|
||||||
|
* tracehook_notify_death().
|
||||||
|
*
|
||||||
|
* If normal reaping is not inhibited, @task->exit_state might be changing
|
||||||
|
* in parallel.
|
||||||
|
*
|
||||||
|
* Called without locks.
|
||||||
|
*/
|
||||||
|
static inline void tracehook_report_death(struct task_struct *task,
|
||||||
|
int signal, void *death_cookie,
|
||||||
|
int group_dead)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* <linux/tracehook.h> */
|
#endif /* <linux/tracehook.h> */
|
||||||
|
@ -885,7 +885,8 @@ static void forget_original_parent(struct task_struct *father)
|
|||||||
*/
|
*/
|
||||||
static void exit_notify(struct task_struct *tsk, int group_dead)
|
static void exit_notify(struct task_struct *tsk, int group_dead)
|
||||||
{
|
{
|
||||||
int state;
|
int signal;
|
||||||
|
void *cookie;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This does two things:
|
* This does two things:
|
||||||
@ -922,22 +923,11 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
|
|||||||
!capable(CAP_KILL))
|
!capable(CAP_KILL))
|
||||||
tsk->exit_signal = SIGCHLD;
|
tsk->exit_signal = SIGCHLD;
|
||||||
|
|
||||||
/* If something other than our normal parent is ptracing us, then
|
signal = tracehook_notify_death(tsk, &cookie, group_dead);
|
||||||
* send it a SIGCHLD instead of honoring exit_signal. exit_signal
|
if (signal > 0)
|
||||||
* only has special meaning to our real parent.
|
signal = do_notify_parent(tsk, signal);
|
||||||
*/
|
|
||||||
if (!task_detached(tsk) && thread_group_empty(tsk)) {
|
|
||||||
int signal = ptrace_reparented(tsk) ?
|
|
||||||
SIGCHLD : tsk->exit_signal;
|
|
||||||
do_notify_parent(tsk, signal);
|
|
||||||
} else if (tsk->ptrace) {
|
|
||||||
do_notify_parent(tsk, SIGCHLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = EXIT_ZOMBIE;
|
tsk->exit_state = signal < 0 ? EXIT_DEAD : EXIT_ZOMBIE;
|
||||||
if (task_detached(tsk) && likely(!tsk->ptrace))
|
|
||||||
state = EXIT_DEAD;
|
|
||||||
tsk->exit_state = state;
|
|
||||||
|
|
||||||
/* mt-exec, de_thread() is waiting for us */
|
/* mt-exec, de_thread() is waiting for us */
|
||||||
if (thread_group_leader(tsk) &&
|
if (thread_group_leader(tsk) &&
|
||||||
@ -947,8 +937,10 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
|
|||||||
|
|
||||||
write_unlock_irq(&tasklist_lock);
|
write_unlock_irq(&tasklist_lock);
|
||||||
|
|
||||||
|
tracehook_report_death(tsk, signal, cookie, group_dead);
|
||||||
|
|
||||||
/* If the process is dead, release it - nobody will wait for it */
|
/* If the process is dead, release it - nobody will wait for it */
|
||||||
if (state == EXIT_DEAD)
|
if (signal < 0)
|
||||||
release_task(tsk);
|
release_task(tsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1326,9 +1326,11 @@ static inline void __wake_up_parent(struct task_struct *p,
|
|||||||
/*
|
/*
|
||||||
* Let a parent know about the death of a child.
|
* Let a parent know about the death of a child.
|
||||||
* For a stopped/continued status change, use do_notify_parent_cldstop instead.
|
* For a stopped/continued status change, use do_notify_parent_cldstop instead.
|
||||||
|
*
|
||||||
|
* Returns -1 if our parent ignored us and so we've switched to
|
||||||
|
* self-reaping, or else @sig.
|
||||||
*/
|
*/
|
||||||
|
int do_notify_parent(struct task_struct *tsk, int sig)
|
||||||
void do_notify_parent(struct task_struct *tsk, int sig)
|
|
||||||
{
|
{
|
||||||
struct siginfo info;
|
struct siginfo info;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -1399,12 +1401,14 @@ void do_notify_parent(struct task_struct *tsk, int sig)
|
|||||||
*/
|
*/
|
||||||
tsk->exit_signal = -1;
|
tsk->exit_signal = -1;
|
||||||
if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
|
if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
|
||||||
sig = 0;
|
sig = -1;
|
||||||
}
|
}
|
||||||
if (valid_signal(sig) && sig > 0)
|
if (valid_signal(sig) && sig > 0)
|
||||||
__group_send_sig_info(sig, &info, tsk->parent);
|
__group_send_sig_info(sig, &info, tsk->parent);
|
||||||
__wake_up_parent(tsk, tsk->parent);
|
__wake_up_parent(tsk, tsk->parent);
|
||||||
spin_unlock_irqrestore(&psig->siglock, flags);
|
spin_unlock_irqrestore(&psig->siglock, flags);
|
||||||
|
|
||||||
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
|
static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
|
||||||
|
Loading…
Reference in New Issue
Block a user