diff options
author | Oleg Nesterov <oleg@redhat.com> | 2014-04-07 18:38:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-07 19:36:05 -0400 |
commit | b436069059fede30ca31d4bf439cc86436ff5b1d (patch) | |
tree | d5d6875cdd317445cb1e84883b5a078bf8cf1451 /kernel/exit.c | |
parent | abd50b39e783e1b6c75c7534c37f1eb2d94a89cd (diff) |
wait: use EXIT_TRACE only if thread_group_leader(zombie)
wait_task_zombie() always uses EXIT_TRACE/ptrace_unlink() if
ptrace_reparented(). This is suboptimal and a bit confusing: we do not
need do_notify_parent(p) if !thread_group_leader(p) and in this case we
also do not need ptrace_unlink(), we can rely on ptrace_release_task().
Change wait_task_zombie() to check thread_group_leader() along with
ptrace_reparented() and simplify the final p->exit_state transition.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Tested-by: Michal Schmidt <mschmidt@redhat.com>
Cc: Jan Kratochvil <jan.kratochvil@redhat.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Lennart Poettering <lpoetter@redhat.com>
Cc: Roland McGrath <roland@hack.frob.com>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 17 |
1 files changed, 7 insertions, 10 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 022a0ff17318..4773ed990907 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1040,7 +1040,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1040 | /* | 1040 | /* |
1041 | * Move the task's state to DEAD/TRACE, only one thread can do this. | 1041 | * Move the task's state to DEAD/TRACE, only one thread can do this. |
1042 | */ | 1042 | */ |
1043 | state = traced ? EXIT_TRACE : EXIT_DEAD; | 1043 | state = traced && thread_group_leader(p) ? EXIT_TRACE : EXIT_DEAD; |
1044 | if (cmpxchg(&p->exit_state, EXIT_ZOMBIE, state) != EXIT_ZOMBIE) | 1044 | if (cmpxchg(&p->exit_state, EXIT_ZOMBIE, state) != EXIT_ZOMBIE) |
1045 | return 0; | 1045 | return 0; |
1046 | /* | 1046 | /* |
@@ -1140,18 +1140,15 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1140 | if (!retval) | 1140 | if (!retval) |
1141 | retval = pid; | 1141 | retval = pid; |
1142 | 1142 | ||
1143 | if (traced) { | 1143 | if (state == EXIT_TRACE) { |
1144 | write_lock_irq(&tasklist_lock); | 1144 | write_lock_irq(&tasklist_lock); |
1145 | /* We dropped tasklist, ptracer could die and untrace */ | 1145 | /* We dropped tasklist, ptracer could die and untrace */ |
1146 | ptrace_unlink(p); | 1146 | ptrace_unlink(p); |
1147 | /* | 1147 | |
1148 | * If this is not a sub-thread, notify the parent. | 1148 | /* If parent wants a zombie, don't release it now */ |
1149 | * If parent wants a zombie, don't release it now. | 1149 | state = EXIT_ZOMBIE; |
1150 | */ | 1150 | if (do_notify_parent(p, p->exit_signal)) |
1151 | state = EXIT_DEAD; | 1151 | state = EXIT_DEAD; |
1152 | if (thread_group_leader(p) && | ||
1153 | !do_notify_parent(p, p->exit_signal)) | ||
1154 | state = EXIT_ZOMBIE; | ||
1155 | p->exit_state = state; | 1152 | p->exit_state = state; |
1156 | write_unlock_irq(&tasklist_lock); | 1153 | write_unlock_irq(&tasklist_lock); |
1157 | } | 1154 | } |