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; ...@@ -120,6 +120,9 @@ int max_queued_signals = 1024;
#define SIG_KERNEL_STOP_MASK (\ #define SIG_KERNEL_STOP_MASK (\
M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) ) M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) )
#define SIG_KERNEL_CONT_MASK (\
M(SIGCONT) | M(SIGKILL) )
#define SIG_KERNEL_COREDUMP_MASK (\ #define SIG_KERNEL_COREDUMP_MASK (\
M(SIGQUIT) | M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | \ M(SIGQUIT) | M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | \
M(SIGFPE) | M(SIGSEGV) | M(SIGBUS) | M(SIGSYS) | \ M(SIGFPE) | M(SIGSEGV) | M(SIGBUS) | M(SIGSYS) | \
...@@ -136,6 +139,8 @@ int max_queued_signals = 1024; ...@@ -136,6 +139,8 @@ int max_queued_signals = 1024;
(((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_IGNORE_MASK)) (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_IGNORE_MASK))
#define sig_kernel_stop(sig) \ #define sig_kernel_stop(sig) \
(((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_STOP_MASK)) (((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) \ #define sig_user_defined(t, signr) \
(((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) && \ (((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) ...@@ -587,7 +592,7 @@ static void handle_stop_signal(int sig, struct task_struct *p)
t = next_thread(t); t = next_thread(t);
} while (t != p); } while (t != p);
} }
else if (sig == SIGCONT) { else if (sig_kernel_cont(sig)) {
/* /*
* Remove all stop signals from all queues, * Remove all stop signals from all queues,
* and wake all threads. * and wake all threads.
...@@ -617,23 +622,32 @@ static void handle_stop_signal(int sig, struct task_struct *p) ...@@ -617,23 +622,32 @@ static void handle_stop_signal(int sig, struct task_struct *p)
t = p; t = p;
do { do {
rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
if (t->state == TASK_STOPPED) { /*
/* * This wakeup is only need if in TASK_STOPPED,
* If there is a handler for SIGCONT, we * but there can be SMP races with testing for that.
* must make sure that no thread returns to * In the normal SIGCONT case, all will be stopped.
* user mode before we post the signal, in * A spuriously sent SIGCONT will interrupt all running
* case it was the only thread eligible to * threads to check signals even if it's ignored.
* run the signal handler--then it must not *
* do anything between resuming and running * If there is a handler for SIGCONT, we must make
* the handler. With the TIF_SIGPENDING flag * sure that no thread returns to user mode before
* set, the thread will pause and acquire the * we post the signal, in case it was the only
* siglock that we hold now and until we've * thread eligible to run the signal handler--then
* queued the pending signal. * it must not do anything between resuming and
*/ * running the handler. With the TIF_SIGPENDING
if (sig_user_defined(p, SIGCONT)) * flag set, the thread will pause and acquire the
set_tsk_thread_flag(t, TIF_SIGPENDING); * siglock that we hold now and until we've queued
wake_up_process(t); * 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); t = next_thread(t);
} while (t != p); } 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