Commit 4c2e8e62 authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] let SIGKILL wake TASK_TRACED

Upon reevaluation we think it is indeed safe to permit the race between
a ptrace call and the traced thread waking up, as long as it will never
get back to user mode.  This patch makes SIGKILL wake up threads in
TASK_TRACED.  That alone resolves most of the deadlock issues that
became possible with the introduction of TASK_TRACED, getting us back to
the killing behavior of 2.6.8 and before. 

This patch also further cleans up ptrace detaching, so that threads are
left in TASK_STOPPED only if a job control stop is actually in effect,
and otherwise resume.  This removes the past nuisances requiring a
SIGCONT to resume a thread even when it had a pending SIGKILL. 
Signed-off-by: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 09207038
......@@ -38,25 +38,22 @@ void __ptrace_link(task_t *child, task_t *new_parent)
SET_LINKS(child);
}
static inline int pending_resume_signal(struct sigpending *pending)
{
#define M(sig) (1UL << ((sig)-1))
return sigtestsetmask(&pending->signal, M(SIGCONT) | M(SIGKILL));
}
/*
* Turn a tracing stop into a normal stop now, since with no tracer there
* would be no way to wake it up with SIGCONT or SIGKILL. If there was a
* signal sent that would resume the child, but didn't because it was in
* TASK_TRACED, resume it now.
* Requires that irqs be disabled.
*/
void ptrace_untrace(task_t *child)
{
spin_lock(&child->sighand->siglock);
child->state = TASK_STOPPED;
if (pending_resume_signal(&child->pending) ||
pending_resume_signal(&child->signal->shared_pending)) {
signal_wake_up(child, 1);
if (child->state == TASK_TRACED) {
if (child->signal->flags & SIGNAL_STOP_STOPPED) {
child->state = TASK_STOPPED;
} else {
signal_wake_up(child, 1);
}
}
spin_unlock(&child->sighand->siglock);
}
......
......@@ -587,15 +587,15 @@ void signal_wake_up(struct task_struct *t, int resume)
set_tsk_thread_flag(t, TIF_SIGPENDING);
/*
* If resume is set, we want to wake it up in the TASK_STOPPED case.
* We don't check for TASK_STOPPED because there is a race with it
* For SIGKILL, we want to wake it up in the stopped/traced case.
* We don't check t->state here because there is a race with it
* executing another processor and just now entering stopped state.
* By calling wake_up_process any time resume is set, we ensure
* the process will wake up and handle its stop or death signal.
* By using wake_up_state, we ensure the process will wake up and
* handle its death signal.
*/
mask = TASK_INTERRUPTIBLE;
if (resume)
mask |= TASK_STOPPED;
mask |= TASK_STOPPED | TASK_TRACED;
if (!wake_up_state(t, mask))
kick_process(t);
}
......@@ -935,11 +935,11 @@ __group_complete_signal(int sig, struct task_struct *p)
/*
* Don't bother traced and stopped tasks (but
* SIGKILL will punch through stopped state)
* SIGKILL will punch through that).
*/
mask = TASK_TRACED;
if (sig != SIGKILL)
mask |= TASK_STOPPED;
mask = TASK_STOPPED | TASK_TRACED;
if (sig == SIGKILL)
mask = 0;
/*
* Now find a thread we can wake up to take the signal off the queue.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment