aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2011-04-01 14:11:50 -0400
committerTejun Heo <tj@kernel.org>2011-04-03 20:11:04 -0400
commit1deac632fc3dcff33a6df3e82ef10c738ac13fe6 (patch)
tree137481584f4692911e2725b31776de3d2dd72068 /kernel/signal.c
parent244056f9dbbc6dc4126a301c745fa3dd67d8af3c (diff)
signal: prepare_signal(SIGCONT) shouldn't play with TIF_SIGPENDING
prepare_signal(SIGCONT) should never set TIF_SIGPENDING or wake up the TASK_INTERRUPTIBLE threads. We are going to call complete_signal() which should pick the right thread correctly. All we need is to wake up the TASK_STOPPED threads. If the task was stopped, it can't return to usermode without taking ->siglock. Otherwise we don't care, and the spurious TIF_SIGPENDING can't be useful. The comment says: * If there is a handler for SIGCONT, we must make * sure that no thread returns to user mode before * we post the signal It is not clear what this means. Probably, "when there's only a single thread" and this continues to be true. Otherwise, even if this SIGCONT is not private, with or without this change only one thread can dequeue SIGCONT, other threads can happily return to user mode before before that thread handles this signal. Note also that wake_up_state(t, __TASK_STOPPED) can't race with the task which changes its state, TASK_STOPPED state is protected by ->siglock as well. In short: when it comes to signal delivery, SIGCONT is the normal signal and does not need any special support. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c27
1 files changed, 2 insertions, 25 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index f799a054f292..38ea9e2f1831 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -788,37 +788,14 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
788 } else if (sig == SIGCONT) { 788 } else if (sig == SIGCONT) {
789 unsigned int why; 789 unsigned int why;
790 /* 790 /*
791 * Remove all stop signals from all queues, 791 * Remove all stop signals from all queues, wake all threads.
792 * and wake all threads.
793 */ 792 */
794 rm_from_queue(SIG_KERNEL_STOP_MASK, &signal->shared_pending); 793 rm_from_queue(SIG_KERNEL_STOP_MASK, &signal->shared_pending);
795 t = p; 794 t = p;
796 do { 795 do {
797 unsigned int state;
798
799 task_clear_group_stop_pending(t); 796 task_clear_group_stop_pending(t);
800
801 rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); 797 rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
802 /* 798 wake_up_state(t, __TASK_STOPPED);
803 * If there is a handler for SIGCONT, we must make
804 * sure that no thread returns to user mode before
805 * we post the signal, in case it was the only
806 * thread eligible to run the signal handler--then
807 * it must not do anything between resuming and
808 * running the handler. With the TIF_SIGPENDING
809 * flag set, the thread will pause and acquire the
810 * siglock that we hold now and until we've queued
811 * the pending signal.
812 *
813 * Wake up the stopped thread _after_ setting
814 * TIF_SIGPENDING
815 */
816 state = __TASK_STOPPED;
817 if (sig_user_defined(t, SIGCONT) && !sigismember(&t->blocked, SIGCONT)) {
818 set_tsk_thread_flag(t, TIF_SIGPENDING);
819 state |= TASK_INTERRUPTIBLE;
820 }
821 wake_up_state(t, state);
822 } while_each_thread(p, t); 799 } while_each_thread(p, t);
823 800
824 /* 801 /*