diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 66 |
1 files changed, 35 insertions, 31 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index ae0f2c4e452b..d3ad54677f9c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -52,6 +52,11 @@ | |||
52 | 52 | ||
53 | static void exit_mm(struct task_struct * tsk); | 53 | static void exit_mm(struct task_struct * tsk); |
54 | 54 | ||
55 | static inline int task_detached(struct task_struct *p) | ||
56 | { | ||
57 | return p->exit_signal == -1; | ||
58 | } | ||
59 | |||
55 | static void __unhash_process(struct task_struct *p) | 60 | static void __unhash_process(struct task_struct *p) |
56 | { | 61 | { |
57 | nr_threads--; | 62 | nr_threads--; |
@@ -160,7 +165,7 @@ repeat: | |||
160 | zap_leader = 0; | 165 | zap_leader = 0; |
161 | leader = p->group_leader; | 166 | leader = p->group_leader; |
162 | if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) { | 167 | if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) { |
163 | BUG_ON(leader->exit_signal == -1); | 168 | BUG_ON(task_detached(leader)); |
164 | do_notify_parent(leader, leader->exit_signal); | 169 | do_notify_parent(leader, leader->exit_signal); |
165 | /* | 170 | /* |
166 | * If we were the last child thread and the leader has | 171 | * If we were the last child thread and the leader has |
@@ -170,7 +175,7 @@ repeat: | |||
170 | * do_notify_parent() will have marked it self-reaping in | 175 | * do_notify_parent() will have marked it self-reaping in |
171 | * that case. | 176 | * that case. |
172 | */ | 177 | */ |
173 | zap_leader = (leader->exit_signal == -1); | 178 | zap_leader = task_detached(leader); |
174 | } | 179 | } |
175 | 180 | ||
176 | write_unlock_irq(&tasklist_lock); | 181 | write_unlock_irq(&tasklist_lock); |
@@ -329,13 +334,11 @@ void __set_special_pids(struct pid *pid) | |||
329 | pid_t nr = pid_nr(pid); | 334 | pid_t nr = pid_nr(pid); |
330 | 335 | ||
331 | if (task_session(curr) != pid) { | 336 | if (task_session(curr) != pid) { |
332 | detach_pid(curr, PIDTYPE_SID); | 337 | change_pid(curr, PIDTYPE_SID, pid); |
333 | attach_pid(curr, PIDTYPE_SID, pid); | ||
334 | set_task_session(curr, nr); | 338 | set_task_session(curr, nr); |
335 | } | 339 | } |
336 | if (task_pgrp(curr) != pid) { | 340 | if (task_pgrp(curr) != pid) { |
337 | detach_pid(curr, PIDTYPE_PGID); | 341 | change_pid(curr, PIDTYPE_PGID, pid); |
338 | attach_pid(curr, PIDTYPE_PGID, pid); | ||
339 | set_task_pgrp(curr, nr); | 342 | set_task_pgrp(curr, nr); |
340 | } | 343 | } |
341 | } | 344 | } |
@@ -693,7 +696,7 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) | |||
693 | if (unlikely(traced)) { | 696 | if (unlikely(traced)) { |
694 | /* Preserve ptrace links if someone else is tracing this child. */ | 697 | /* Preserve ptrace links if someone else is tracing this child. */ |
695 | list_del_init(&p->ptrace_list); | 698 | list_del_init(&p->ptrace_list); |
696 | if (p->parent != p->real_parent) | 699 | if (ptrace_reparented(p)) |
697 | list_add(&p->ptrace_list, &p->real_parent->ptrace_children); | 700 | list_add(&p->ptrace_list, &p->real_parent->ptrace_children); |
698 | } else { | 701 | } else { |
699 | /* If this child is being traced, then we're the one tracing it | 702 | /* If this child is being traced, then we're the one tracing it |
@@ -717,18 +720,18 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) | |||
717 | /* If this is a threaded reparent there is no need to | 720 | /* If this is a threaded reparent there is no need to |
718 | * notify anyone anything has happened. | 721 | * notify anyone anything has happened. |
719 | */ | 722 | */ |
720 | if (p->real_parent->group_leader == father->group_leader) | 723 | if (same_thread_group(p->real_parent, father)) |
721 | return; | 724 | return; |
722 | 725 | ||
723 | /* We don't want people slaying init. */ | 726 | /* We don't want people slaying init. */ |
724 | if (p->exit_signal != -1) | 727 | if (!task_detached(p)) |
725 | p->exit_signal = SIGCHLD; | 728 | p->exit_signal = SIGCHLD; |
726 | 729 | ||
727 | /* If we'd notified the old parent about this child's death, | 730 | /* If we'd notified the old parent about this child's death, |
728 | * also notify the new parent. | 731 | * also notify the new parent. |
729 | */ | 732 | */ |
730 | if (!traced && p->exit_state == EXIT_ZOMBIE && | 733 | if (!traced && p->exit_state == EXIT_ZOMBIE && |
731 | p->exit_signal != -1 && thread_group_empty(p)) | 734 | !task_detached(p) && thread_group_empty(p)) |
732 | do_notify_parent(p, p->exit_signal); | 735 | do_notify_parent(p, p->exit_signal); |
733 | 736 | ||
734 | kill_orphaned_pgrp(p, father); | 737 | kill_orphaned_pgrp(p, father); |
@@ -781,18 +784,18 @@ static void forget_original_parent(struct task_struct *father) | |||
781 | } else { | 784 | } else { |
782 | /* reparent ptraced task to its real parent */ | 785 | /* reparent ptraced task to its real parent */ |
783 | __ptrace_unlink (p); | 786 | __ptrace_unlink (p); |
784 | if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && | 787 | if (p->exit_state == EXIT_ZOMBIE && !task_detached(p) && |
785 | thread_group_empty(p)) | 788 | thread_group_empty(p)) |
786 | do_notify_parent(p, p->exit_signal); | 789 | do_notify_parent(p, p->exit_signal); |
787 | } | 790 | } |
788 | 791 | ||
789 | /* | 792 | /* |
790 | * if the ptraced child is a zombie with exit_signal == -1 | 793 | * if the ptraced child is a detached zombie we must collect |
791 | * we must collect it before we exit, or it will remain | 794 | * it before we exit, or it will remain zombie forever since |
792 | * zombie forever since we prevented it from self-reap itself | 795 | * we prevented it from self-reap itself while it was being |
793 | * while it was being traced by us, to be able to see it in wait4. | 796 | * traced by us, to be able to see it in wait4. |
794 | */ | 797 | */ |
795 | if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) | 798 | if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && task_detached(p))) |
796 | list_add(&p->ptrace_list, &ptrace_dead); | 799 | list_add(&p->ptrace_list, &ptrace_dead); |
797 | } | 800 | } |
798 | 801 | ||
@@ -849,29 +852,30 @@ static void exit_notify(struct task_struct *tsk, int group_dead) | |||
849 | * we have changed execution domain as these two values started | 852 | * we have changed execution domain as these two values started |
850 | * the same after a fork. | 853 | * the same after a fork. |
851 | */ | 854 | */ |
852 | if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 && | 855 | if (tsk->exit_signal != SIGCHLD && !task_detached(tsk) && |
853 | (tsk->parent_exec_id != tsk->real_parent->self_exec_id || | 856 | (tsk->parent_exec_id != tsk->real_parent->self_exec_id || |
854 | tsk->self_exec_id != tsk->parent_exec_id) | 857 | tsk->self_exec_id != tsk->parent_exec_id) && |
855 | && !capable(CAP_KILL)) | 858 | !capable(CAP_KILL)) |
856 | tsk->exit_signal = SIGCHLD; | 859 | tsk->exit_signal = SIGCHLD; |
857 | 860 | ||
858 | |||
859 | /* If something other than our normal parent is ptracing us, then | 861 | /* If something other than our normal parent is ptracing us, then |
860 | * send it a SIGCHLD instead of honoring exit_signal. exit_signal | 862 | * send it a SIGCHLD instead of honoring exit_signal. exit_signal |
861 | * only has special meaning to our real parent. | 863 | * only has special meaning to our real parent. |
862 | */ | 864 | */ |
863 | if (tsk->exit_signal != -1 && thread_group_empty(tsk)) { | 865 | if (!task_detached(tsk) && thread_group_empty(tsk)) { |
864 | int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD; | 866 | int signal = ptrace_reparented(tsk) ? |
867 | SIGCHLD : tsk->exit_signal; | ||
865 | do_notify_parent(tsk, signal); | 868 | do_notify_parent(tsk, signal); |
866 | } else if (tsk->ptrace) { | 869 | } else if (tsk->ptrace) { |
867 | do_notify_parent(tsk, SIGCHLD); | 870 | do_notify_parent(tsk, SIGCHLD); |
868 | } | 871 | } |
869 | 872 | ||
870 | state = EXIT_ZOMBIE; | 873 | state = EXIT_ZOMBIE; |
871 | if (tsk->exit_signal == -1 && likely(!tsk->ptrace)) | 874 | if (task_detached(tsk) && likely(!tsk->ptrace)) |
872 | state = EXIT_DEAD; | 875 | state = EXIT_DEAD; |
873 | tsk->exit_state = state; | 876 | tsk->exit_state = state; |
874 | 877 | ||
878 | /* mt-exec, de_thread() is waiting for us */ | ||
875 | if (thread_group_leader(tsk) && | 879 | if (thread_group_leader(tsk) && |
876 | tsk->signal->notify_count < 0 && | 880 | tsk->signal->notify_count < 0 && |
877 | tsk->signal->group_exit_task) | 881 | tsk->signal->group_exit_task) |
@@ -1115,12 +1119,13 @@ asmlinkage long sys_exit(int error_code) | |||
1115 | NORET_TYPE void | 1119 | NORET_TYPE void |
1116 | do_group_exit(int exit_code) | 1120 | do_group_exit(int exit_code) |
1117 | { | 1121 | { |
1122 | struct signal_struct *sig = current->signal; | ||
1123 | |||
1118 | BUG_ON(exit_code & 0x80); /* core dumps don't get here */ | 1124 | BUG_ON(exit_code & 0x80); /* core dumps don't get here */ |
1119 | 1125 | ||
1120 | if (current->signal->flags & SIGNAL_GROUP_EXIT) | 1126 | if (signal_group_exit(sig)) |
1121 | exit_code = current->signal->group_exit_code; | 1127 | exit_code = sig->group_exit_code; |
1122 | else if (!thread_group_empty(current)) { | 1128 | else if (!thread_group_empty(current)) { |
1123 | struct signal_struct *const sig = current->signal; | ||
1124 | struct sighand_struct *const sighand = current->sighand; | 1129 | struct sighand_struct *const sighand = current->sighand; |
1125 | spin_lock_irq(&sighand->siglock); | 1130 | spin_lock_irq(&sighand->siglock); |
1126 | if (signal_group_exit(sig)) | 1131 | if (signal_group_exit(sig)) |
@@ -1172,7 +1177,7 @@ static int eligible_child(enum pid_type type, struct pid *pid, int options, | |||
1172 | * Do not consider detached threads that are | 1177 | * Do not consider detached threads that are |
1173 | * not ptraced: | 1178 | * not ptraced: |
1174 | */ | 1179 | */ |
1175 | if (p->exit_signal == -1 && !p->ptrace) | 1180 | if (task_detached(p) && !p->ptrace) |
1176 | return 0; | 1181 | return 0; |
1177 | 1182 | ||
1178 | /* Wait for all children (clone and not) if __WALL is set; | 1183 | /* Wait for all children (clone and not) if __WALL is set; |
@@ -1262,8 +1267,7 @@ static int wait_task_zombie(struct task_struct *p, int noreap, | |||
1262 | return 0; | 1267 | return 0; |
1263 | } | 1268 | } |
1264 | 1269 | ||
1265 | /* traced means p->ptrace, but not vice versa */ | 1270 | traced = ptrace_reparented(p); |
1266 | traced = (p->real_parent != p->parent); | ||
1267 | 1271 | ||
1268 | if (likely(!traced)) { | 1272 | if (likely(!traced)) { |
1269 | struct signal_struct *psig; | 1273 | struct signal_struct *psig; |
@@ -1364,9 +1368,9 @@ static int wait_task_zombie(struct task_struct *p, int noreap, | |||
1364 | * If it's still not detached after that, don't release | 1368 | * If it's still not detached after that, don't release |
1365 | * it now. | 1369 | * it now. |
1366 | */ | 1370 | */ |
1367 | if (p->exit_signal != -1) { | 1371 | if (!task_detached(p)) { |
1368 | do_notify_parent(p, p->exit_signal); | 1372 | do_notify_parent(p, p->exit_signal); |
1369 | if (p->exit_signal != -1) { | 1373 | if (!task_detached(p)) { |
1370 | p->exit_state = EXIT_ZOMBIE; | 1374 | p->exit_state = EXIT_ZOMBIE; |
1371 | p = NULL; | 1375 | p = NULL; |
1372 | } | 1376 | } |