aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2008-02-08 07:19:13 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:27 -0500
commit5dee1707dfbfc55eb7569b9ae5abaf932bd4c377 (patch)
tree6e162f61f9645f790aa14cb4146882b918bb0286 /kernel/signal.c
parent6806aac6d282d58b97763f5e17e2787e62c3b440 (diff)
move the related code from exit_notify() to exit_signals()
The previous bugfix was not optimal, we shouldn't care about group stop when we are the only thread or the group stop is in progress. In that case nothing special is needed, just set PF_EXITING and return. Also, take the related "TIF_SIGPENDING re-targeting" code from exit_notify(). So, from the performance POV the only difference is that we don't trust !signal_pending() until we take ->siglock. But this in fact fixes another ___pure___ theoretical minor race. __group_complete_signal() finds the task without PF_EXITING and chooses it as the target for signal_wake_up(). But nothing prevents this task from exiting in between without noticing the pending signal and thus unpredictably delaying the actual delivery. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Cc: Davide Libenzi <davidel@xmailserver.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 209eec11eef5..3d3adb94561d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1903,19 +1903,36 @@ relock:
1903void exit_signals(struct task_struct *tsk) 1903void exit_signals(struct task_struct *tsk)
1904{ 1904{
1905 int group_stop = 0; 1905 int group_stop = 0;
1906 struct task_struct *t;
1906 1907
1907 spin_lock_irq(&tsk->sighand->siglock); 1908 if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) {
1908 if (unlikely(tsk->signal->group_stop_count) && 1909 tsk->flags |= PF_EXITING;
1909 !--tsk->signal->group_stop_count) { 1910 return;
1910 tsk->signal->flags = SIGNAL_STOP_STOPPED;
1911 group_stop = 1;
1912 } 1911 }
1913 1912
1913 spin_lock_irq(&tsk->sighand->siglock);
1914 /* 1914 /*
1915 * From now this task is not visible for group-wide signals, 1915 * From now this task is not visible for group-wide signals,
1916 * see wants_signal(), do_signal_stop(). 1916 * see wants_signal(), do_signal_stop().
1917 */ 1917 */
1918 tsk->flags |= PF_EXITING; 1918 tsk->flags |= PF_EXITING;
1919 if (!signal_pending(tsk))
1920 goto out;
1921
1922 /* It could be that __group_complete_signal() choose us to
1923 * notify about group-wide signal. Another thread should be
1924 * woken now to take the signal since we will not.
1925 */
1926 for (t = tsk; (t = next_thread(t)) != tsk; )
1927 if (!signal_pending(t) && !(t->flags & PF_EXITING))
1928 recalc_sigpending_and_wake(t);
1929
1930 if (unlikely(tsk->signal->group_stop_count) &&
1931 !--tsk->signal->group_stop_count) {
1932 tsk->signal->flags = SIGNAL_STOP_STOPPED;
1933 group_stop = 1;
1934 }
1935out:
1919 spin_unlock_irq(&tsk->sighand->siglock); 1936 spin_unlock_irq(&tsk->sighand->siglock);
1920 1937
1921 if (unlikely(group_stop)) { 1938 if (unlikely(group_stop)) {