aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2008-04-30 03:52:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 11:29:34 -0400
commitfc321d2e60d6f4eee17206612d0b50519f526daf (patch)
tree79dd03d347ccee2f5a538823f7434dfd40e302be /kernel/signal.c
parent6ca25b551309eb1b1b41f83414a92f7472e0b23d (diff)
handle_stop_signal: unify partial/full stop handling
Now that handle_stop_signal() doesn't drop ->siglock, we can't see both ->group_stop_count && SIGNAL_STOP_STOPPED. Merge two "if" branches. As Roland pointed out, we never actually needed 2 do_notify_parent_cldstop() calls. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Cc: Roland McGrath <roland@redhat.com> Cc: Jiri Kosina <jkosina@suse.cz> 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.c45
1 files changed, 19 insertions, 26 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index ce53ab19c21d..dee8cc927a63 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -585,33 +585,16 @@ static void handle_stop_signal(int sig, struct task_struct *p)
585 t = next_thread(t); 585 t = next_thread(t);
586 } while (t != p); 586 } while (t != p);
587 } else if (sig == SIGCONT) { 587 } else if (sig == SIGCONT) {
588 unsigned int why;
588 /* 589 /*
589 * Remove all stop signals from all queues, 590 * Remove all stop signals from all queues,
590 * and wake all threads. 591 * and wake all threads.
591 */ 592 */
592 if (unlikely(p->signal->group_stop_count > 0)) {
593 /*
594 * There was a group stop in progress. We'll
595 * pretend it finished before we got here. We are
596 * obliged to report it to the parent: if the
597 * SIGSTOP happened "after" this SIGCONT, then it
598 * would have cleared this pending SIGCONT. If it
599 * happened "before" this SIGCONT, then the parent
600 * got the SIGCHLD about the stop finishing before
601 * the continue happened. We do the notification
602 * now, and it's as if the stop had finished and
603 * the SIGCHLD was pending on entry to this kill.
604 */
605 p->signal->group_stop_count = 0;
606 p->signal->flags = SIGNAL_STOP_CONTINUED |
607 SIGNAL_CLD_STOPPED;
608 }
609 rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending); 593 rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
610 t = p; 594 t = p;
611 do { 595 do {
612 unsigned int state; 596 unsigned int state;
613 rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); 597 rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
614
615 /* 598 /*
616 * If there is a handler for SIGCONT, we must make 599 * If there is a handler for SIGCONT, we must make
617 * sure that no thread returns to user mode before 600 * sure that no thread returns to user mode before
@@ -621,7 +604,7 @@ static void handle_stop_signal(int sig, struct task_struct *p)
621 * running the handler. With the TIF_SIGPENDING 604 * running the handler. With the TIF_SIGPENDING
622 * flag set, the thread will pause and acquire the 605 * flag set, the thread will pause and acquire the
623 * siglock that we hold now and until we've queued 606 * siglock that we hold now and until we've queued
624 * the pending signal. 607 * the pending signal.
625 * 608 *
626 * Wake up the stopped thread _after_ setting 609 * Wake up the stopped thread _after_ setting
627 * TIF_SIGPENDING 610 * TIF_SIGPENDING
@@ -636,13 +619,23 @@ static void handle_stop_signal(int sig, struct task_struct *p)
636 t = next_thread(t); 619 t = next_thread(t);
637 } while (t != p); 620 } while (t != p);
638 621
639 if (p->signal->flags & SIGNAL_STOP_STOPPED) { 622 /*
640 /* 623 * Notify the parent with CLD_CONTINUED if we were stopped.
641 * We were in fact stopped, and are now continued. 624 *
642 * Notify the parent with CLD_CONTINUED. 625 * If we were in the middle of a group stop, we pretend it
643 */ 626 * was already finished, and then continued. Since SIGCHLD
644 p->signal->flags = SIGNAL_STOP_CONTINUED | 627 * doesn't queue we report only CLD_STOPPED, as if the next
645 SIGNAL_CLD_CONTINUED; 628 * CLD_CONTINUED was dropped.
629 */
630 why = 0;
631 if (p->signal->flags & SIGNAL_STOP_STOPPED)
632 why |= SIGNAL_CLD_CONTINUED;
633 else if (p->signal->group_stop_count)
634 why |= SIGNAL_CLD_STOPPED;
635
636 if (why) {
637 p->signal->flags = why | SIGNAL_STOP_CONTINUED;
638 p->signal->group_stop_count = 0;
646 p->signal->group_exit_code = 0; 639 p->signal->group_exit_code = 0;
647 } else { 640 } else {
648 /* 641 /*