diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 74 |
1 files changed, 35 insertions, 39 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 506a957b665a..11fcce760151 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -255,6 +255,37 @@ static int has_stopped_jobs(struct pid *pgrp) | |||
255 | return retval; | 255 | return retval; |
256 | } | 256 | } |
257 | 257 | ||
258 | /* | ||
259 | * Check to see if any process groups have become orphaned as | ||
260 | * a result of our exiting, and if they have any stopped jobs, | ||
261 | * send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) | ||
262 | */ | ||
263 | static void | ||
264 | kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent) | ||
265 | { | ||
266 | struct pid *pgrp = task_pgrp(tsk); | ||
267 | struct task_struct *ignored_task = tsk; | ||
268 | |||
269 | if (!parent) | ||
270 | /* exit: our father is in a different pgrp than | ||
271 | * we are and we were the only connection outside. | ||
272 | */ | ||
273 | parent = tsk->real_parent; | ||
274 | else | ||
275 | /* reparent: our child is in a different pgrp than | ||
276 | * we are, and it was the only connection outside. | ||
277 | */ | ||
278 | ignored_task = NULL; | ||
279 | |||
280 | if (task_pgrp(parent) != pgrp && | ||
281 | task_session(parent) == task_session(tsk) && | ||
282 | will_become_orphaned_pgrp(pgrp, ignored_task) && | ||
283 | has_stopped_jobs(pgrp)) { | ||
284 | __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp); | ||
285 | __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp); | ||
286 | } | ||
287 | } | ||
288 | |||
258 | /** | 289 | /** |
259 | * reparent_to_kthreadd - Reparent the calling kernel thread to kthreadd | 290 | * reparent_to_kthreadd - Reparent the calling kernel thread to kthreadd |
260 | * | 291 | * |
@@ -635,22 +666,7 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) | |||
635 | p->exit_signal != -1 && thread_group_empty(p)) | 666 | p->exit_signal != -1 && thread_group_empty(p)) |
636 | do_notify_parent(p, p->exit_signal); | 667 | do_notify_parent(p, p->exit_signal); |
637 | 668 | ||
638 | /* | 669 | kill_orphaned_pgrp(p, father); |
639 | * process group orphan check | ||
640 | * Case ii: Our child is in a different pgrp | ||
641 | * than we are, and it was the only connection | ||
642 | * outside, so the child pgrp is now orphaned. | ||
643 | */ | ||
644 | if ((task_pgrp(p) != task_pgrp(father)) && | ||
645 | (task_session(p) == task_session(father))) { | ||
646 | struct pid *pgrp = task_pgrp(p); | ||
647 | |||
648 | if (will_become_orphaned_pgrp(pgrp, NULL) && | ||
649 | has_stopped_jobs(pgrp)) { | ||
650 | __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp); | ||
651 | __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp); | ||
652 | } | ||
653 | } | ||
654 | } | 670 | } |
655 | 671 | ||
656 | /* | 672 | /* |
@@ -738,8 +754,6 @@ static void forget_original_parent(struct task_struct *father) | |||
738 | static void exit_notify(struct task_struct *tsk) | 754 | static void exit_notify(struct task_struct *tsk) |
739 | { | 755 | { |
740 | int state; | 756 | int state; |
741 | struct task_struct *t; | ||
742 | struct pid *pgrp; | ||
743 | 757 | ||
744 | /* | 758 | /* |
745 | * This does two things: | 759 | * This does two things: |
@@ -753,25 +767,7 @@ static void exit_notify(struct task_struct *tsk) | |||
753 | exit_task_namespaces(tsk); | 767 | exit_task_namespaces(tsk); |
754 | 768 | ||
755 | write_lock_irq(&tasklist_lock); | 769 | write_lock_irq(&tasklist_lock); |
756 | /* | 770 | kill_orphaned_pgrp(tsk, NULL); |
757 | * Check to see if any process groups have become orphaned | ||
758 | * as a result of our exiting, and if they have any stopped | ||
759 | * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) | ||
760 | * | ||
761 | * Case i: Our father is in a different pgrp than we are | ||
762 | * and we were the only connection outside, so our pgrp | ||
763 | * is about to become orphaned. | ||
764 | */ | ||
765 | t = tsk->real_parent; | ||
766 | |||
767 | pgrp = task_pgrp(tsk); | ||
768 | if ((task_pgrp(t) != pgrp) && | ||
769 | (task_session(t) == task_session(tsk)) && | ||
770 | will_become_orphaned_pgrp(pgrp, tsk) && | ||
771 | has_stopped_jobs(pgrp)) { | ||
772 | __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp); | ||
773 | __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp); | ||
774 | } | ||
775 | 771 | ||
776 | /* Let father know we died | 772 | /* Let father know we died |
777 | * | 773 | * |
@@ -788,8 +784,8 @@ static void exit_notify(struct task_struct *tsk) | |||
788 | * the same after a fork. | 784 | * the same after a fork. |
789 | */ | 785 | */ |
790 | if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 && | 786 | if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 && |
791 | ( tsk->parent_exec_id != t->self_exec_id || | 787 | (tsk->parent_exec_id != tsk->real_parent->self_exec_id || |
792 | tsk->self_exec_id != tsk->parent_exec_id) | 788 | tsk->self_exec_id != tsk->parent_exec_id) |
793 | && !capable(CAP_KILL)) | 789 | && !capable(CAP_KILL)) |
794 | tsk->exit_signal = SIGCHLD; | 790 | tsk->exit_signal = SIGCHLD; |
795 | 791 | ||