⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exit.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 4 页
字号:
			status &= 0x7f;		}		retval = put_user((short)why, &infop->si_code);		if (!retval)			retval = put_user(status, &infop->si_status);	}	if (!retval && infop)		retval = put_user(pid, &infop->si_pid);	if (!retval && infop)		retval = put_user(p->uid, &infop->si_uid);	if (!retval)		retval = pid;	if (traced) {		write_lock_irq(&tasklist_lock);		/* We dropped tasklist, ptracer could die and untrace */		ptrace_unlink(p);		/*		 * If this is not a detached task, notify the parent.		 * If it's still not detached after that, don't release		 * it now.		 */		if (!task_detached(p)) {			do_notify_parent(p, p->exit_signal);			if (!task_detached(p)) {				p->exit_state = EXIT_ZOMBIE;				p = NULL;			}		}		write_unlock_irq(&tasklist_lock);	}	if (p != NULL)		release_task(p);	return retval;}/* * Handle sys_wait4 work for one task in state TASK_STOPPED.  We hold * read_lock(&tasklist_lock) on entry.  If we return zero, we still hold * the lock and this task is uninteresting.  If we return nonzero, we have * released the lock and the system call should return. */static int wait_task_stopped(int ptrace, struct task_struct *p,			     int options, struct siginfo __user *infop,			     int __user *stat_addr, struct rusage __user *ru){	int retval, exit_code, why;	uid_t uid = 0; /* unneeded, required by compiler */	pid_t pid;	if (!(options & WUNTRACED))		return 0;	exit_code = 0;	spin_lock_irq(&p->sighand->siglock);	if (unlikely(!task_is_stopped_or_traced(p)))		goto unlock_sig;	if (!ptrace && p->signal->group_stop_count > 0)		/*		 * A group stop is in progress and this is the group leader.		 * We won't report until all threads have stopped.		 */		goto unlock_sig;	exit_code = p->exit_code;	if (!exit_code)		goto unlock_sig;	if (!unlikely(options & WNOWAIT))		p->exit_code = 0;	uid = p->uid;unlock_sig:	spin_unlock_irq(&p->sighand->siglock);	if (!exit_code)		return 0;	/*	 * Now we are pretty sure this task is interesting.	 * Make sure it doesn't get reaped out from under us while we	 * give up the lock and then examine it below.  We don't want to	 * keep holding onto the tasklist_lock while we call getrusage and	 * possibly take page faults for user memory.	 */	get_task_struct(p);	pid = task_pid_vnr(p);	why = ptrace ? CLD_TRAPPED : CLD_STOPPED;	read_unlock(&tasklist_lock);	if (unlikely(options & WNOWAIT))		return wait_noreap_copyout(p, pid, uid,					   why, exit_code,					   infop, ru);	retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;	if (!retval && stat_addr)		retval = put_user((exit_code << 8) | 0x7f, stat_addr);	if (!retval && infop)		retval = put_user(SIGCHLD, &infop->si_signo);	if (!retval && infop)		retval = put_user(0, &infop->si_errno);	if (!retval && infop)		retval = put_user((short)why, &infop->si_code);	if (!retval && infop)		retval = put_user(exit_code, &infop->si_status);	if (!retval && infop)		retval = put_user(pid, &infop->si_pid);	if (!retval && infop)		retval = put_user(uid, &infop->si_uid);	if (!retval)		retval = pid;	put_task_struct(p);	BUG_ON(!retval);	return retval;}/* * Handle do_wait work for one task in a live, non-stopped state. * read_lock(&tasklist_lock) on entry.  If we return zero, we still hold * the lock and this task is uninteresting.  If we return nonzero, we have * released the lock and the system call should return. */static int wait_task_continued(struct task_struct *p, int options,			       struct siginfo __user *infop,			       int __user *stat_addr, struct rusage __user *ru){	int retval;	pid_t pid;	uid_t uid;	if (!unlikely(options & WCONTINUED))		return 0;	if (!(p->signal->flags & SIGNAL_STOP_CONTINUED))		return 0;	spin_lock_irq(&p->sighand->siglock);	/* Re-check with the lock held.  */	if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) {		spin_unlock_irq(&p->sighand->siglock);		return 0;	}	if (!unlikely(options & WNOWAIT))		p->signal->flags &= ~SIGNAL_STOP_CONTINUED;	spin_unlock_irq(&p->sighand->siglock);	pid = task_pid_vnr(p);	uid = p->uid;	get_task_struct(p);	read_unlock(&tasklist_lock);	if (!infop) {		retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;		put_task_struct(p);		if (!retval && stat_addr)			retval = put_user(0xffff, stat_addr);		if (!retval)			retval = pid;	} else {		retval = wait_noreap_copyout(p, pid, uid,					     CLD_CONTINUED, SIGCONT,					     infop, ru);		BUG_ON(retval == 0);	}	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 task_struct *parent, int ptrace,			      struct task_struct *p, int *notask_error,			      enum pid_type type, struct pid *pid, int options,			      struct siginfo __user *infop,			      int __user *stat_addr, struct rusage __user *ru){	int ret = eligible_child(type, pid, options, p);	if (!ret)		return ret;	if (unlikely(ret < 0)) {		/*		 * If we have not yet seen any eligible child,		 * then let this error code replace -ECHILD.		 * A permission error will give the user a clue		 * to look for security policy problems, rather		 * than for mysterious wait bugs.		 */		if (*notask_error)			*notask_error = ret;	}	if (likely(!ptrace) && unlikely(p->ptrace)) {		/*		 * This child is hidden by ptrace.		 * We aren't allowed to see it now, but eventually we will.		 */		*notask_error = 0;		return 0;	}	if (p->exit_state == EXIT_DEAD)		return 0;	/*	 * We don't reap group leaders with subthreads.	 */	if (p->exit_state == EXIT_ZOMBIE && !delay_group_leader(p))		return wait_task_zombie(p, options, infop, stat_addr, ru);	/*	 * It's stopped or running now, so it might	 * later continue, exit, or stop again.	 */	*notask_error = 0;	if (task_is_stopped_or_traced(p))		return wait_task_stopped(ptrace, p, options,					 infop, stat_addr, ru);	return wait_task_continued(p, options, infop, stat_addr, ru);}/* * Do the work of do_wait() for one thread in the group, @tsk. * * -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 there were any eligible children, * or another error from security_task_wait(), or still -ECHILD. */static int do_wait_thread(struct task_struct *tsk, int *notask_error,			  enum pid_type type, struct pid *pid, int options,			  struct siginfo __user *infop, int __user *stat_addr,			  struct rusage __user *ru){	struct task_struct *p;	list_for_each_entry(p, &tsk->children, sibling) {		/*		 * Do not consider detached threads.		 */		if (!task_detached(p)) {			int ret = wait_consider_task(tsk, 0, p, notask_error,						     type, pid, options,						     infop, stat_addr, ru);			if (ret)				return ret;		}	}	return 0;}static int ptrace_do_wait(struct task_struct *tsk, int *notask_error,			  enum pid_type type, struct pid *pid, int options,			  struct siginfo __user *infop, int __user *stat_addr,			  struct rusage __user *ru){	struct task_struct *p;	/*	 * Traditionally we see ptrace'd stopped tasks regardless of options.	 */	options |= WUNTRACED;	list_for_each_entry(p, &tsk->ptraced, ptrace_entry) {		int ret = wait_consider_task(tsk, 1, p, notask_error,					     type, pid, options,					     infop, stat_addr, ru);		if (ret)			return ret;	}	return 0;}static long do_wait(enum pid_type type, struct pid *pid, int options,		    struct siginfo __user *infop, int __user *stat_addr,		    struct rusage __user *ru){	DECLARE_WAITQUEUE(wait, current);	struct task_struct *tsk;	int retval;	add_wait_queue(&current->signal->wait_chldexit,&wait);repeat:	/*	 * If there is nothing that can match our critiera just get out.	 * We will clear @retval to zero if we see any child that might later	 * match our criteria, even if we are not able to reap it yet.	 */	retval = -ECHILD;	if ((type < PIDTYPE_MAX) && (!pid || hlist_empty(&pid->tasks[type])))		goto end;	current->state = TASK_INTERRUPTIBLE;	read_lock(&tasklist_lock);	tsk = current;	do {		int tsk_result = do_wait_thread(tsk, &retval,						type, pid, options,						infop, stat_addr, ru);		if (!tsk_result)			tsk_result = ptrace_do_wait(tsk, &retval,						    type, pid, options,						    infop, stat_addr, ru);		if (tsk_result) {			/*			 * tasklist_lock is unlocked and we have a final result.			 */			retval = tsk_result;			goto end;		}		if (options & __WNOTHREAD)			break;		tsk = next_thread(tsk);		BUG_ON(tsk->signal != current->signal);	} while (tsk != current);	read_unlock(&tasklist_lock);	if (!retval && !(options & WNOHANG)) {		retval = -ERESTARTSYS;		if (!signal_pending(current)) {			schedule();			goto repeat;		}	}end:	current->state = TASK_RUNNING;	remove_wait_queue(&current->signal->wait_chldexit,&wait);	if (infop) {		if (retval > 0)			retval = 0;		else {			/*			 * For a WNOHANG return, clear out all the fields			 * we would set so the user can easily tell the			 * difference.			 */			if (!retval)				retval = put_user(0, &infop->si_signo);			if (!retval)				retval = put_user(0, &infop->si_errno);			if (!retval)				retval = put_user(0, &infop->si_code);			if (!retval)				retval = put_user(0, &infop->si_pid);			if (!retval)				retval = put_user(0, &infop->si_uid);			if (!retval)				retval = put_user(0, &infop->si_status);		}	}	return retval;}asmlinkage long sys_waitid(int which, pid_t upid,			   struct siginfo __user *infop, int options,			   struct rusage __user *ru){	struct pid *pid = NULL;	enum pid_type type;	long ret;	if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED))		return -EINVAL;	if (!(options & (WEXITED|WSTOPPED|WCONTINUED)))		return -EINVAL;	switch (which) {	case P_ALL:		type = PIDTYPE_MAX;		break;	case P_PID:		type = PIDTYPE_PID;		if (upid <= 0)			return -EINVAL;		break;	case P_PGID:		type = PIDTYPE_PGID;		if (upid <= 0)			return -EINVAL;		break;	default:		return -EINVAL;	}	if (type < PIDTYPE_MAX)		pid = find_get_pid(upid);	ret = do_wait(type, pid, options, infop, NULL, ru);	put_pid(pid);	/* avoid REGPARM breakage on x86: */	asmlinkage_protect(5, ret, which, upid, infop, options, ru);	return ret;}asmlinkage long sys_wait4(pid_t upid, int __user *stat_addr,			  int options, struct rusage __user *ru){	struct pid *pid = NULL;	enum pid_type type;	long ret;	if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|			__WNOTHREAD|__WCLONE|__WALL))		return -EINVAL;	if (upid == -1)		type = PIDTYPE_MAX;	else if (upid < 0) {		type = PIDTYPE_PGID;		pid = find_get_pid(-upid);	} else if (upid == 0) {		type = PIDTYPE_PGID;		pid = get_pid(task_pgrp(current));	} else /* upid > 0 */ {		type = PIDTYPE_PID;		pid = find_get_pid(upid);	}	ret = do_wait(type, pid, options | WEXITED, NULL, stat_addr, ru);	put_pid(pid);	/* avoid REGPARM breakage on x86: */	asmlinkage_protect(4, ret, upid, stat_addr, options, ru);	return ret;}#ifdef __ARCH_WANT_SYS_WAITPID/* * sys_waitpid() remains for compatibility. waitpid() should be * implemented by calling sys_wait4() from libc.a. */asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options){	return sys_wait4(pid, stat_addr, options, NULL);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -