diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 34 | 
1 files changed, 23 insertions, 11 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index fd90195667e1..9e6e1356e6bb 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -746,7 +746,7 @@ void do_exit(long code)  		disassociate_ctty(1);  	exit_task_namespaces(tsk);  	exit_task_work(tsk); -	exit_thread(); +	exit_thread(tsk);  	/*  	 * Flush inherited counters to the parent - before the parent @@ -918,17 +918,28 @@ static int eligible_pid(struct wait_opts *wo, struct task_struct *p)  		task_pid_type(p, wo->wo_type) == wo->wo_pid;  } -static int eligible_child(struct wait_opts *wo, struct task_struct *p) +static int +eligible_child(struct wait_opts *wo, bool ptrace, struct task_struct *p)  {  	if (!eligible_pid(wo, p))  		return 0; -	/* Wait for all children (clone and not) if __WALL is set; -	 * otherwise, wait for clone children *only* if __WCLONE is -	 * set; otherwise, wait for non-clone children *only*.  (Note: -	 * A "clone" child here is one that reports to its parent -	 * using a signal other than SIGCHLD.) */ -	if (((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE)) -	    && !(wo->wo_flags & __WALL)) + +	/* +	 * Wait for all children (clone and not) if __WALL is set or +	 * if it is traced by us. +	 */ +	if (ptrace || (wo->wo_flags & __WALL)) +		return 1; + +	/* +	 * Otherwise, wait for clone children *only* if __WCLONE is set; +	 * otherwise, wait for non-clone children *only*. +	 * +	 * Note: a "clone" child here is one that reports to its parent +	 * using a signal other than SIGCHLD, or a non-leader thread which +	 * we can only see if it is traced by us. +	 */ +	if ((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE))  		return 0;  	return 1; @@ -1300,7 +1311,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,  	if (unlikely(exit_state == EXIT_DEAD))  		return 0; -	ret = eligible_child(wo, p); +	ret = eligible_child(wo, ptrace, p);  	if (!ret)  		return ret; @@ -1524,7 +1535,8 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,  	enum pid_type type;  	long ret; -	if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED)) +	if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED| +			__WNOTHREAD|__WCLONE|__WALL))  		return -EINVAL;  	if (!(options & (WEXITED|WSTOPPED|WCONTINUED)))  		return -EINVAL;  |