linux进程管理之wait系统调用
发布时间:2016-02-07 21:19:44 所属栏目:Linux 来源:网络整理
导读:六: wait4 ()系统调用 在父进程中,用wait4()可以获得子进程的退出状态,并且防止在父进程退出前,子进程退出造成僵死 状态。这是我们这节分析的最后一个小节了
|
副标题[/!--empirenews.page--] 六: wait4 ()系统调用 在父进程中,用wait4()可以获得子进程的退出状态,并且防止在父进程退出前,子进程退出造成僵死 状态。这是我们这节分析的最后一个小节了。 关于wait4()在用户空间的调用方式可以自行参考相关资料,在这里只是讨论内核对这个系统调用的实 现过程。 Wait4()的系统调用入口为sys_wait4().代码如下所示:
asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,
int options, struct rusage __user *ru)
{
long ret;
//options的标志为须为WNOHANG…__WALL的组合,否则会出错
//相关标志的作用在do_wait()中再进行分析
if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|
__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
ret = do_wait(pid, options | WEXITED, NULL, stat_addr, ru);
/* avoid REGPARM breakage on x86: */
prevent_tail_call(ret);
return ret;
}
do_wait()是其中的核心处理函数。代码如下:
static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
int __user *stat_addr, struct rusage __user *ru)
{
//初始化一个等待队列
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
int flag, retval;
int allowed, denied;
//将当前进程加入等待队列,子进程退出给父进程发送信号会wake up些等待队列
add_wait_queue(¤t->signal->wait_chldexit,&wait);
repeat:
flag = 0;
allowed = denied = 0;
//设置进程状态为TASK_INTERRUPTIBLE.下次调度必须要等到子进程唤醒才可以了
current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock);
tsk = current;
do {
struct task_struct *p;
struct list_head *_p;
int ret;
//遍历进程下的子进程
list_for_each(_p,&tsk->children) {
p = list_entry(_p, struct task_struct, sibling);
//判断是否是我们要wait 的子进程
ret = eligible_child(pid, options, p);
if (!ret)
continue;
if (unlikely(ret < 0)) {
denied = ret;
continue;
}
allowed = 1;
switch (p->state) {
//子进程为TASK_TRACED.即处于跟踪状态。则取子进程的相关信息
case TASK_TRACED:
flag = 1;
//判断是否是被父进程跟踪的子进程
//如果是则返回1..不是返回0
if (!my_ptrace_child(p))
continue;
/*FALLTHROUGH*/
case TASK_STOPPED:
flag = 1;
//WUNTRACED:子进程是停止的,也马上返回
//没有定义WUNTRACED 参数.继续遍历子进程
/*从此看出.生父进程是不会处理STOP状态的子进程的.只有
发起跟踪的进程才会
*/
if (!(options & WUNTRACED) &&
!my_ptrace_child(p))
continue;
//WNOWAIT:不会将zombie子进程的退出状态撤销
//下次调用wait系列函数的时候还可以继续获得这个退出状态
retval = wait_task_stopped(p, ret == 2,
(options & WNOWAIT),
infop,
stat_addr, ru);
if (retval == -EAGAIN)
goto repeat;
if (retval != 0) /* He released the lock. */
goto end;
break;
default:
// case EXIT_DEAD:
//不需要处理DEAD状态
if (p->exit_state == EXIT_DEAD)
continue;
// case EXIT_ZOMBIE:
//子进程为僵尸状态
if (p->exit_state == EXIT_ZOMBIE) {
if (ret == 2)
goto check_continued;
if (!likely(options & WEXITED))
continue;
retval = wait_task_zombie(
p, (options & WNOWAIT),
infop, stat_addr, ru);
/* He released the lock. */
if (retval != 0)
goto end;
break;
}
check_continued:
/*
* It's running now, so it might later
* exit, stop, or stop and then continue.
*/
flag = 1;
//WCONTINUED:报告任何继续运行的指定进程号的子进程的状态
if (!unlikely(options & WCONTINUED))
continue;
//取进程的相关状态
retval = wait_task_continued(
p, (options & WNOWAIT),
infop, stat_addr, ru);
if (retval != 0) /* He released the lock. */
goto end;
break;
}
}
//遍历被跟踪出去的子进程
//从这里可以看出.如果一个子进程被跟踪出去了.那么子进程的退出
//操作并不是由生父进程进行了
if (!flag) {
list_for_each(_p, &tsk->ptrace_children) {
p = list_entry(_p, struct task_struct,
ptrace_list);
if (!eligible_child(pid, options, p))
continue;
flag = 1;
break;
}
}
if (options & __WNOTHREAD)
break;
//也有可能是进程中的线程在wait其fork出来的子进程
tsk = next_thread(tsk);
BUG_ON(tsk->signal != current->signal);
} while (tsk != current);
//
read_unlock(&tasklist_lock);
if (flag) {
retval = 0;
//如果定义了WHNOHANG:马上退出
if (options & WNOHANG)
goto end;
retval = -ERESTARTSYS;
if (signal_pending(current))
goto end;
schedule();
goto repeat;
}
retval = -ECHILD;
if (unlikely(denied) && !allowed)
retval = denied;
end:
//将进程设为运行状态,从等待队列中移除
current->state = TASK_RUNNING;
remove_wait_queue(¤t->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;
}
(编辑:应用网_镇江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
站长推荐

