diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 39 |
1 files changed, 21 insertions, 18 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 179ac74bf9..3f2182ccf1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -666,10 +666,14 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) | |||
| 666 | * the child reaper process (ie "init") in our pid | 666 | * the child reaper process (ie "init") in our pid |
| 667 | * space. | 667 | * space. |
| 668 | */ | 668 | */ |
| 669 | static void | 669 | static void forget_original_parent(struct task_struct *father) |
| 670 | forget_original_parent(struct task_struct *father, struct list_head *to_release) | ||
| 671 | { | 670 | { |
| 672 | struct task_struct *p, *n, *reaper = father; | 671 | struct task_struct *p, *n, *reaper = father; |
| 672 | struct list_head ptrace_dead; | ||
| 673 | |||
| 674 | INIT_LIST_HEAD(&ptrace_dead); | ||
| 675 | |||
| 676 | write_lock_irq(&tasklist_lock); | ||
| 673 | 677 | ||
| 674 | do { | 678 | do { |
| 675 | reaper = next_thread(reaper); | 679 | reaper = next_thread(reaper); |
| @@ -677,7 +681,7 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release) | |||
| 677 | reaper = task_child_reaper(father); | 681 | reaper = task_child_reaper(father); |
| 678 | break; | 682 | break; |
| 679 | } | 683 | } |
| 680 | } while (reaper->exit_state); | 684 | } while (reaper->flags & PF_EXITING); |
| 681 | 685 | ||
| 682 | /* | 686 | /* |
| 683 | * There are only two places where our children can be: | 687 | * There are only two places where our children can be: |
| @@ -714,12 +718,23 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release) | |||
| 714 | * while it was being traced by us, to be able to see it in wait4. | 718 | * while it was being traced by us, to be able to see it in wait4. |
| 715 | */ | 719 | */ |
| 716 | if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) | 720 | if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) |
| 717 | list_add(&p->ptrace_list, to_release); | 721 | list_add(&p->ptrace_list, &ptrace_dead); |
| 718 | } | 722 | } |
| 723 | |||
| 719 | list_for_each_entry_safe(p, n, &father->ptrace_children, ptrace_list) { | 724 | list_for_each_entry_safe(p, n, &father->ptrace_children, ptrace_list) { |
| 720 | p->real_parent = reaper; | 725 | p->real_parent = reaper; |
| 721 | reparent_thread(p, father, 1); | 726 | reparent_thread(p, father, 1); |
| 722 | } | 727 | } |
| 728 | |||
| 729 | write_unlock_irq(&tasklist_lock); | ||
| 730 | BUG_ON(!list_empty(&father->children)); | ||
| 731 | BUG_ON(!list_empty(&father->ptrace_children)); | ||
| 732 | |||
| 733 | list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_list) { | ||
| 734 | list_del_init(&p->ptrace_list); | ||
| 735 | release_task(p); | ||
| 736 | } | ||
| 737 | |||
| 723 | } | 738 | } |
| 724 | 739 | ||
| 725 | /* | 740 | /* |
| @@ -730,7 +745,6 @@ static void exit_notify(struct task_struct *tsk) | |||
| 730 | { | 745 | { |
| 731 | int state; | 746 | int state; |
| 732 | struct task_struct *t; | 747 | struct task_struct *t; |
| 733 | struct list_head ptrace_dead, *_p, *_n; | ||
| 734 | struct pid *pgrp; | 748 | struct pid *pgrp; |
| 735 | 749 | ||
| 736 | if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT) | 750 | if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT) |
| @@ -751,8 +765,6 @@ static void exit_notify(struct task_struct *tsk) | |||
| 751 | spin_unlock_irq(&tsk->sighand->siglock); | 765 | spin_unlock_irq(&tsk->sighand->siglock); |
| 752 | } | 766 | } |
| 753 | 767 | ||
| 754 | write_lock_irq(&tasklist_lock); | ||
| 755 | |||
| 756 | /* | 768 | /* |
| 757 | * This does two things: | 769 | * This does two things: |
| 758 | * | 770 | * |
| @@ -761,12 +773,9 @@ static void exit_notify(struct task_struct *tsk) | |||
| 761 | * as a result of our exiting, and if they have any stopped | 773 | * as a result of our exiting, and if they have any stopped |
| 762 | * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) | 774 | * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) |
| 763 | */ | 775 | */ |
| 776 | forget_original_parent(tsk); | ||
| 764 | 777 | ||
| 765 | INIT_LIST_HEAD(&ptrace_dead); | 778 | write_lock_irq(&tasklist_lock); |
| 766 | forget_original_parent(tsk, &ptrace_dead); | ||
| 767 | BUG_ON(!list_empty(&tsk->children)); | ||
| 768 | BUG_ON(!list_empty(&tsk->ptrace_children)); | ||
| 769 | |||
| 770 | /* | 779 | /* |
| 771 | * Check to see if any process groups have become orphaned | 780 | * Check to see if any process groups have become orphaned |
| 772 | * as a result of our exiting, and if they have any stopped | 781 | * as a result of our exiting, and if they have any stopped |
| @@ -831,12 +840,6 @@ static void exit_notify(struct task_struct *tsk) | |||
| 831 | 840 | ||
| 832 | write_unlock_irq(&tasklist_lock); | 841 | write_unlock_irq(&tasklist_lock); |
| 833 | 842 | ||
| 834 | list_for_each_safe(_p, _n, &ptrace_dead) { | ||
| 835 | list_del_init(_p); | ||
| 836 | t = list_entry(_p, struct task_struct, ptrace_list); | ||
| 837 | release_task(t); | ||
| 838 | } | ||
| 839 | |||
| 840 | /* If the process is dead, release it - nobody will wait for it */ | 843 | /* If the process is dead, release it - nobody will wait for it */ |
| 841 | if (state == EXIT_DEAD) | 844 | if (state == EXIT_DEAD) |
| 842 | release_task(tsk); | 845 | release_task(tsk); |
