diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 95 |
1 files changed, 6 insertions, 89 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 3e09b7cb3b20..506693dfdd4e 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -61,11 +61,6 @@ DEFINE_TRACE(sched_process_wait); | |||
61 | 61 | ||
62 | static void exit_mm(struct task_struct * tsk); | 62 | static void exit_mm(struct task_struct * tsk); |
63 | 63 | ||
64 | static inline int task_detached(struct task_struct *p) | ||
65 | { | ||
66 | return p->exit_signal == -1; | ||
67 | } | ||
68 | |||
69 | static void __unhash_process(struct task_struct *p) | 64 | static void __unhash_process(struct task_struct *p) |
70 | { | 65 | { |
71 | nr_threads--; | 66 | nr_threads--; |
@@ -731,85 +726,6 @@ static void exit_mm(struct task_struct * tsk) | |||
731 | mmput(mm); | 726 | mmput(mm); |
732 | } | 727 | } |
733 | 728 | ||
734 | /* | ||
735 | * Called with irqs disabled, returns true if childs should reap themselves. | ||
736 | */ | ||
737 | static int ignoring_children(struct sighand_struct *sigh) | ||
738 | { | ||
739 | int ret; | ||
740 | spin_lock(&sigh->siglock); | ||
741 | ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) || | ||
742 | (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT); | ||
743 | spin_unlock(&sigh->siglock); | ||
744 | return ret; | ||
745 | } | ||
746 | |||
747 | /* Returns nonzero if the tracee should be released. */ | ||
748 | int __ptrace_detach(struct task_struct *tracer, struct task_struct *p) | ||
749 | { | ||
750 | __ptrace_unlink(p); | ||
751 | |||
752 | if (p->exit_state != EXIT_ZOMBIE) | ||
753 | return 0; | ||
754 | /* | ||
755 | * If it's a zombie, our attachedness prevented normal | ||
756 | * parent notification or self-reaping. Do notification | ||
757 | * now if it would have happened earlier. If it should | ||
758 | * reap itself we return true. | ||
759 | * | ||
760 | * If it's our own child, there is no notification to do. | ||
761 | * But if our normal children self-reap, then this child | ||
762 | * was prevented by ptrace and we must reap it now. | ||
763 | */ | ||
764 | if (!task_detached(p) && thread_group_empty(p)) { | ||
765 | if (!same_thread_group(p->real_parent, tracer)) | ||
766 | do_notify_parent(p, p->exit_signal); | ||
767 | else if (ignoring_children(tracer->sighand)) | ||
768 | p->exit_signal = -1; | ||
769 | } | ||
770 | |||
771 | if (!task_detached(p)) | ||
772 | return 0; | ||
773 | |||
774 | /* Mark it as in the process of being reaped. */ | ||
775 | p->exit_state = EXIT_DEAD; | ||
776 | return 1; | ||
777 | } | ||
778 | |||
779 | /* | ||
780 | * Detach all tasks we were using ptrace on. | ||
781 | * Any that need to be release_task'd are put on the @dead list. | ||
782 | * | ||
783 | * Called with write_lock(&tasklist_lock) held. | ||
784 | */ | ||
785 | static void ptrace_exit(struct task_struct *parent, struct list_head *dead) | ||
786 | { | ||
787 | struct task_struct *p, *n; | ||
788 | |||
789 | list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) { | ||
790 | if (__ptrace_detach(parent, p)) | ||
791 | list_add(&p->ptrace_entry, dead); | ||
792 | } | ||
793 | } | ||
794 | |||
795 | /* | ||
796 | * Finish up exit-time ptrace cleanup. | ||
797 | * | ||
798 | * Called without locks. | ||
799 | */ | ||
800 | static void ptrace_exit_finish(struct task_struct *parent, | ||
801 | struct list_head *dead) | ||
802 | { | ||
803 | struct task_struct *p, *n; | ||
804 | |||
805 | BUG_ON(!list_empty(&parent->ptraced)); | ||
806 | |||
807 | list_for_each_entry_safe(p, n, dead, ptrace_entry) { | ||
808 | list_del_init(&p->ptrace_entry); | ||
809 | release_task(p); | ||
810 | } | ||
811 | } | ||
812 | |||
813 | /* Returns nonzero if the child should be released. */ | 729 | /* Returns nonzero if the child should be released. */ |
814 | static int reparent_thread(struct task_struct *p, struct task_struct *father) | 730 | static int reparent_thread(struct task_struct *p, struct task_struct *father) |
815 | { | 731 | { |
@@ -894,12 +810,10 @@ static void forget_original_parent(struct task_struct *father) | |||
894 | struct task_struct *p, *n, *reaper; | 810 | struct task_struct *p, *n, *reaper; |
895 | LIST_HEAD(ptrace_dead); | 811 | LIST_HEAD(ptrace_dead); |
896 | 812 | ||
813 | exit_ptrace(father); | ||
814 | |||
897 | write_lock_irq(&tasklist_lock); | 815 | write_lock_irq(&tasklist_lock); |
898 | reaper = find_new_reaper(father); | 816 | reaper = find_new_reaper(father); |
899 | /* | ||
900 | * First clean up ptrace if we were using it. | ||
901 | */ | ||
902 | ptrace_exit(father, &ptrace_dead); | ||
903 | 817 | ||
904 | list_for_each_entry_safe(p, n, &father->children, sibling) { | 818 | list_for_each_entry_safe(p, n, &father->children, sibling) { |
905 | p->real_parent = reaper; | 819 | p->real_parent = reaper; |
@@ -914,7 +828,10 @@ static void forget_original_parent(struct task_struct *father) | |||
914 | write_unlock_irq(&tasklist_lock); | 828 | write_unlock_irq(&tasklist_lock); |
915 | BUG_ON(!list_empty(&father->children)); | 829 | BUG_ON(!list_empty(&father->children)); |
916 | 830 | ||
917 | ptrace_exit_finish(father, &ptrace_dead); | 831 | list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) { |
832 | list_del_init(&p->ptrace_entry); | ||
833 | release_task(p); | ||
834 | } | ||
918 | } | 835 | } |
919 | 836 | ||
920 | /* | 837 | /* |