diff --git a/kernel/exit.c b/kernel/exit.c index f9a45eb..2aa64e8 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1507,21 +1507,11 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) return retval; } -/* - * Consider @p for a wait by @parent. - * - * -ECHILD should be in ->notask_error before the first call. - * Returns nonzero for a final return, when we have unlocked tasklist_lock. - * Returns zero if the search for a child should continue; - * then ->notask_error is 0 if @p is an eligible child, - * or another error from security_task_wait(), or still -ECHILD. - */ -static int wait_consider_task(struct wait_opts *wo, int ptrace, - struct task_struct *p) +static int can_wait_task_common(struct wait_opts *wo, struct task_struct *p) { int ret = eligible_child(wo, p); if (!ret) - return ret; + return 0; ret = security_task_wait(p); if (unlikely(ret < 0)) { @@ -1537,7 +1527,25 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, return 0; } - if (likely(!ptrace) && unlikely(task_ptrace(p))) { + if (p->exit_state == EXIT_DEAD) + return 0; + + return 1; +} + +static int can_wait_task_ptrace(struct wait_opts *wo, struct task_struct *p) +{ + /* don't worry, gcc will optimize away this function :) */ + return can_wait_task_common(wo, p); +} + +static int can_wait_task(struct wait_opts *wo, struct task_struct *p) +{ + int ret = can_wait_task_common(wo, p); + if (!ret) + return 0; + + if (unlikely(task_ptrace(p))) { /* * This child is hidden by ptrace. * We aren't allowed to see it now, but eventually we will. @@ -1546,9 +1554,21 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, return 0; } - if (p->exit_state == EXIT_DEAD) - return 0; + return 1; +} +/* + * Consider @p for a wait by @parent. + * + * -ECHILD should be in ->notask_error before the first call. + * Returns nonzero for a final return, when we have unlocked tasklist_lock. + * Returns zero if the search for a child should continue; + * then ->notask_error is 0 if @p is an eligible child, + * or another error from security_task_wait(), or still -ECHILD. + */ +static int wait_consider_task(struct wait_opts *wo, int ptrace, + struct task_struct *p) +{ /* * We don't reap group leaders with subthreads. */ @@ -1578,10 +1598,14 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, */ static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk) { + int ret; struct task_struct *p; list_for_each_entry(p, &tsk->children, sibling) { - int ret = wait_consider_task(wo, 0, p); + ret = can_wait_task(wo, p); + if (!ret) + continue; + ret = wait_consider_task(wo, 0, p); if (ret) return ret; } @@ -1594,7 +1618,10 @@ static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk) struct task_struct *p; list_for_each_entry(p, &tsk->ptraced, ptrace_entry) { - int ret = wait_consider_task(wo, 1, p); + int ret = can_wait_task_ptrace(wo, p); + if (!ret) + continue; + ret = wait_consider_task(wo, 1, p); if (ret) return ret; }