Commit 03e21831 authored by Roland McGrath's avatar Roland McGrath Committed by Kai Germaschewski

[PATCH] TASK_STOPPED wakeup cleanup

For handle_stop_signal to do the special case for SIGKILL and have it
work right in all SMP cases (without changing all the existing ptrace
stops), it needs to at least set TIF_SIGPENDING on each thread before
resuming it.

handle_stop_signal addresses a related race for SIGCONT by setting
TIF_SIGPENDING already, so having SIGKILL handled the same way makes
sense.

Now it seems pretty clean to have handle_stop_signal resume threads for
SIGKILL, and have on SIGKILL special case in group_send_sig_info.

There is also an SMP race issue with cases like do_syscall_trace, i.e.
TASK_STOPPED state set without holding the siglock.  So I think
handle_stop_signal should call wake_up_process unconditionally.
parent 631da088
......@@ -120,6 +120,9 @@ int max_queued_signals = 1024;
#define SIG_KERNEL_STOP_MASK (\
M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) )
#define SIG_KERNEL_CONT_MASK (\
M(SIGCONT) | M(SIGKILL) )
#define SIG_KERNEL_COREDUMP_MASK (\
M(SIGQUIT) | M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | \
M(SIGFPE) | M(SIGSEGV) | M(SIGBUS) | M(SIGSYS) | \
......@@ -136,6 +139,8 @@ int max_queued_signals = 1024;
(((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_IGNORE_MASK))
#define sig_kernel_stop(sig) \
(((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_STOP_MASK))
#define sig_kernel_cont(sig) \
(((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_CONT_MASK))
#define sig_user_defined(t, signr) \
(((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) && \
......@@ -587,7 +592,7 @@ static void handle_stop_signal(int sig, struct task_struct *p)
t = next_thread(t);
} while (t != p);
}
else if (sig == SIGCONT) {
else if (sig_kernel_cont(sig)) {
/*
* Remove all stop signals from all queues,
* and wake all threads.
......@@ -617,23 +622,32 @@ static void handle_stop_signal(int sig, struct task_struct *p)
t = p;
do {
rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
if (t->state == TASK_STOPPED) {
/*
* If there is a handler for SIGCONT, we
* must make sure that no thread returns to
* user mode before we post the signal, in
* case it was the only thread eligible to
* run the signal handler--then it must not
* do anything between resuming and running
* the handler. With the TIF_SIGPENDING flag
* set, the thread will pause and acquire the
* siglock that we hold now and until we've
* queued the pending signal.
*/
if (sig_user_defined(p, SIGCONT))
set_tsk_thread_flag(t, TIF_SIGPENDING);
wake_up_process(t);
}
/*
* This wakeup is only need if in TASK_STOPPED,
* but there can be SMP races with testing for that.
* In the normal SIGCONT case, all will be stopped.
* A spuriously sent SIGCONT will interrupt all running
* threads to check signals even if it's ignored.
*
* If there is a handler for SIGCONT, we must make
* sure that no thread returns to user mode before
* we post the signal, in case it was the only
* thread eligible to run the signal handler--then
* it must not do anything between resuming and
* running the handler. With the TIF_SIGPENDING
* flag set, the thread will pause and acquire the
* siglock that we hold now and until we've queued
* the pending signal. For SIGKILL, we likewise
* don't want anybody doing anything but taking the
* SIGKILL. The only case in which a thread would
* not already be in the signal dequeuing loop is
* non-signal (e.g. syscall) ptrace tracing, so we
* don't worry about an unnecessary trip through
* the signal code and just keep this code path
* simpler by unconditionally setting the flag.
*/
set_tsk_thread_flag(t, TIF_SIGPENDING);
wake_up_process(t);
t = next_thread(t);
} while (t != p);
}
......
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