diff --git a/kernel/exit.c b/kernel/exit.c index 8f3bf53a5b4d3cf4a09b9028eba496f38b69a141..2b332d170327763c8833da485dc93d9bec0a6b90 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -745,24 +745,6 @@ static void exit_notify(struct task_struct *tsk) struct task_struct *t; struct pid *pgrp; - if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT) - && !thread_group_empty(tsk)) { - /* - * This occurs when there was a race between our exit - * syscall and a group signal choosing us as the one to - * wake up. It could be that we are the only thread - * alerted to check for pending signals, but another thread - * should be woken now to take the signal since we will not. - * Now we'll wake all the threads in the group just to make - * sure someone gets all the pending signals. - */ - spin_lock_irq(&tsk->sighand->siglock); - for (t = next_thread(tsk); t != tsk; t = next_thread(t)) - if (!signal_pending(t) && !(t->flags & PF_EXITING)) - recalc_sigpending_and_wake(t); - spin_unlock_irq(&tsk->sighand->siglock); - } - /* * This does two things: * diff --git a/kernel/signal.c b/kernel/signal.c index 209eec11eef5dd0ca7662559e9988d7bcbe07056..3d3adb94561d141b950329ea283d0e91601c6dde 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1903,19 +1903,36 @@ int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, void exit_signals(struct task_struct *tsk) { int group_stop = 0; + struct task_struct *t; - spin_lock_irq(&tsk->sighand->siglock); - if (unlikely(tsk->signal->group_stop_count) && - !--tsk->signal->group_stop_count) { - tsk->signal->flags = SIGNAL_STOP_STOPPED; - group_stop = 1; + if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) { + tsk->flags |= PF_EXITING; + return; } + spin_lock_irq(&tsk->sighand->siglock); /* * From now this task is not visible for group-wide signals, * see wants_signal(), do_signal_stop(). */ tsk->flags |= PF_EXITING; + if (!signal_pending(tsk)) + goto out; + + /* It could be that __group_complete_signal() choose us to + * notify about group-wide signal. Another thread should be + * woken now to take the signal since we will not. + */ + for (t = tsk; (t = next_thread(t)) != tsk; ) + if (!signal_pending(t) && !(t->flags & PF_EXITING)) + recalc_sigpending_and_wake(t); + + if (unlikely(tsk->signal->group_stop_count) && + !--tsk->signal->group_stop_count) { + tsk->signal->flags = SIGNAL_STOP_STOPPED; + group_stop = 1; + } +out: spin_unlock_irq(&tsk->sighand->siglock); if (unlikely(group_stop)) {