diff options
Diffstat (limited to 'kernel')
| -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 ce53ab19c21..dee8cc927a6 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 | /* |
