signal: Turn SIGNAL_STOP_DEQUEUED into GROUP_STOP_DEQUEUED
authorOleg Nesterov <oleg@redhat.com>
Fri, 1 Apr 2011 18:12:38 +0000 (20:12 +0200)
committerTejun Heo <tj@kernel.org>
Mon, 4 Apr 2011 00:11:05 +0000 (02:11 +0200)
commitee77f075921730b2b465880f9fd4367003bdab39
treedfae10b9718b79650477f912de148c903bc1bbd0
parent780006eac2fe7f4d2582da16a096e5a44c4767ff
signal: Turn SIGNAL_STOP_DEQUEUED into GROUP_STOP_DEQUEUED

This patch moves SIGNAL_STOP_DEQUEUED from signal_struct->flags to
task_struct->group_stop, and thus makes it per-thread.

Like SIGNAL_STOP_DEQUEUED, GROUP_STOP_DEQUEUED can be false-positive
after return from get_signal_to_deliver(), this is fine. The only
purpose of this bit is: we can drop ->siglock after __dequeue_signal()
returns the sig_kernel_stop() signal and before we call
do_signal_stop(), in this case we must not miss SIGCONT if it comes in
between.

But, unlike SIGNAL_STOP_DEQUEUED, GROUP_STOP_DEQUEUED can not be
false-positive in do_signal_stop() if multiple threads dequeue the
sig_kernel_stop() signal at the same time.

Consider two threads T1 and T2, SIGTTIN has a hanlder.

- T1 dequeues SIGTSTP and sets SIGNAL_STOP_DEQUEUED, then
  it drops ->siglock

- SIGCONT comes and clears SIGNAL_STOP_DEQUEUED, SIGTSTP
  should be cancelled.

- T2 dequeues SIGTTIN and sets SIGNAL_STOP_DEQUEUED again.
  Since we have a handler we should not stop, T2 returns
  to usermode to run the handler.

- T1 continues, calls do_signal_stop() and wrongly starts
  the group stop because SIGNAL_STOP_DEQUEUED was restored
  in between.

With or without this change:

- we need to do something with ptrace_signal() which can
  return SIGSTOP, but this needs another discussion

- SIGSTOP can be lost if it races with the mt exec, will
  be fixed later.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
include/linux/sched.h
kernel/signal.c