diff options
-rw-r--r-- | include/linux/sched.h | 6 | ||||
-rw-r--r-- | kernel/signal.c | 29 |
2 files changed, 25 insertions, 10 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 1d02babdb2c7..ef5615270342 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -554,6 +554,12 @@ struct signal_struct { | |||
554 | #define SIGNAL_STOP_DEQUEUED 0x00000002 /* stop signal dequeued */ | 554 | #define SIGNAL_STOP_DEQUEUED 0x00000002 /* stop signal dequeued */ |
555 | #define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */ | 555 | #define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */ |
556 | #define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */ | 556 | #define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */ |
557 | /* | ||
558 | * Pending notifications to parent. | ||
559 | */ | ||
560 | #define SIGNAL_CLD_STOPPED 0x00000010 | ||
561 | #define SIGNAL_CLD_CONTINUED 0x00000020 | ||
562 | #define SIGNAL_CLD_MASK (SIGNAL_CLD_STOPPED|SIGNAL_CLD_CONTINUED) | ||
557 | 563 | ||
558 | /* If true, all threads except ->group_exit_task have pending SIGKILL */ | 564 | /* If true, all threads except ->group_exit_task have pending SIGKILL */ |
559 | static inline int signal_group_exit(const struct signal_struct *sig) | 565 | static inline int signal_group_exit(const struct signal_struct *sig) |
diff --git a/kernel/signal.c b/kernel/signal.c index 91d57f89f5a5..115c04f3f143 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -603,10 +603,8 @@ static void handle_stop_signal(int sig, struct task_struct *p) | |||
603 | * the SIGCHLD was pending on entry to this kill. | 603 | * the SIGCHLD was pending on entry to this kill. |
604 | */ | 604 | */ |
605 | p->signal->group_stop_count = 0; | 605 | p->signal->group_stop_count = 0; |
606 | p->signal->flags = SIGNAL_STOP_CONTINUED; | 606 | p->signal->flags = SIGNAL_STOP_CONTINUED | |
607 | spin_unlock(&p->sighand->siglock); | 607 | SIGNAL_CLD_STOPPED; |
608 | do_notify_parent_cldstop(p, CLD_STOPPED); | ||
609 | spin_lock(&p->sighand->siglock); | ||
610 | } | 608 | } |
611 | rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending); | 609 | rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending); |
612 | t = p; | 610 | t = p; |
@@ -643,25 +641,23 @@ static void handle_stop_signal(int sig, struct task_struct *p) | |||
643 | * We were in fact stopped, and are now continued. | 641 | * We were in fact stopped, and are now continued. |
644 | * Notify the parent with CLD_CONTINUED. | 642 | * Notify the parent with CLD_CONTINUED. |
645 | */ | 643 | */ |
646 | p->signal->flags = SIGNAL_STOP_CONTINUED; | 644 | p->signal->flags = SIGNAL_STOP_CONTINUED | |
645 | SIGNAL_CLD_CONTINUED; | ||
647 | p->signal->group_exit_code = 0; | 646 | p->signal->group_exit_code = 0; |
648 | spin_unlock(&p->sighand->siglock); | ||
649 | do_notify_parent_cldstop(p, CLD_CONTINUED); | ||
650 | spin_lock(&p->sighand->siglock); | ||
651 | } else { | 647 | } else { |
652 | /* | 648 | /* |
653 | * We are not stopped, but there could be a stop | 649 | * We are not stopped, but there could be a stop |
654 | * signal in the middle of being processed after | 650 | * signal in the middle of being processed after |
655 | * being removed from the queue. Clear that too. | 651 | * being removed from the queue. Clear that too. |
656 | */ | 652 | */ |
657 | p->signal->flags = 0; | 653 | p->signal->flags &= ~SIGNAL_STOP_DEQUEUED; |
658 | } | 654 | } |
659 | } else if (sig == SIGKILL) { | 655 | } else if (sig == SIGKILL) { |
660 | /* | 656 | /* |
661 | * Make sure that any pending stop signal already dequeued | 657 | * Make sure that any pending stop signal already dequeued |
662 | * is undone by the wakeup for SIGKILL. | 658 | * is undone by the wakeup for SIGKILL. |
663 | */ | 659 | */ |
664 | p->signal->flags = 0; | 660 | p->signal->flags &= ~SIGNAL_STOP_DEQUEUED; |
665 | } | 661 | } |
666 | } | 662 | } |
667 | 663 | ||
@@ -1784,6 +1780,19 @@ relock: | |||
1784 | try_to_freeze(); | 1780 | try_to_freeze(); |
1785 | 1781 | ||
1786 | spin_lock_irq(¤t->sighand->siglock); | 1782 | spin_lock_irq(¤t->sighand->siglock); |
1783 | |||
1784 | if (unlikely(current->signal->flags & SIGNAL_CLD_MASK)) { | ||
1785 | int why = (current->signal->flags & SIGNAL_STOP_CONTINUED) | ||
1786 | ? CLD_CONTINUED : CLD_STOPPED; | ||
1787 | current->signal->flags &= ~SIGNAL_CLD_MASK; | ||
1788 | spin_unlock_irq(¤t->sighand->siglock); | ||
1789 | |||
1790 | read_lock(&tasklist_lock); | ||
1791 | do_notify_parent_cldstop(current->group_leader, why); | ||
1792 | read_unlock(&tasklist_lock); | ||
1793 | goto relock; | ||
1794 | } | ||
1795 | |||
1787 | for (;;) { | 1796 | for (;;) { |
1788 | struct k_sigaction *ka; | 1797 | struct k_sigaction *ka; |
1789 | 1798 | ||