diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2008-04-30 03:52:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:34 -0400 |
commit | fc321d2e60d6f4eee17206612d0b50519f526daf (patch) | |
tree | 79dd03d347ccee2f5a538823f7434dfd40e302be /kernel/signal.c | |
parent | 6ca25b551309eb1b1b41f83414a92f7472e0b23d (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.c | 45 |
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 | /* |