父进程执行wait4,并调用schedule切换到子进程:
wait4(child, NULL, 0, NULL);
像其他系统调用一样,wait4()在内核中的入口是sys_wait4(),代码如下:
asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)//pid为子进程的进程号
{
int flag, retval;
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
add_wait_queue(current->wait_chldexit,&wait);
repeat:
flag = 0;
current->state = TASK_INTERRUPTIBLE;//父进程设置为可中断等待状态
read_lock(&tasklist_lock);
tsk = current;
do {//第一层循环
struct task_struct *p;
for (p = tsk->p_cptr ; p ; p = p->p_osptr) {//第二层循环,从最年轻的子进程开始沿着由各个task_struct结构中的指针p_osptr所形成的链,找寻与所等待对象的pid相符的子进程、或符合其他一些条件的子进程
if (pid>0) {
if (p->pid != pid)//找到pid相符的子进程
continue;
} else if (!pid) {
if (p->pgrp != current->pgrp)
continue;
} else if (pid != -1) {
if (p->pgrp != -pid)
continue;
}
/* 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) ^ ((options & __WCLONE) != 0))//要求子进程发送的是SIGCHLD信号
&& !(options & __WALL))
continue;
flag = 1;//说明pid是当前进程的子进程号
switch (p->state) {
case TASK_STOPPED:
if (!p->exit_code)
continue;
if (!(options & WUNTRACED) && !(p->ptrace & PT_PTRACED))
continue;
read_unlock(&tasklist_lock);
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
if (!retval && stat_addr)
retval = put_user((p->exit_code << 8) | 0x7f, stat_addr);
if (!retval) {
p->exit_code = 0;
retval = p->pid;
}
goto end_wait4;//子进程处于停止状态,goto end_wait4
case TASK_ZOMBIE:
current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime;
current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime;
read_unlock(&tasklist_lock);
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
if (!retval && stat_addr)
retval = put_user(p->exit_code, stat_addr);
if (retval)
goto end_wait4;
retval = p->pid;
if (p->p_opptr != p->p_pptr) {
write_lock_irq(&tasklist_lock);
REMOVE_LINKS(p);
p->p_pptr = p->p_opptr;
SET_LINKS(p);
do_notify_parent(p, SIGCHLD);
write_unlock_irq(&tasklist_lock);
} else
release_task(p);//将子进程task_struct结构和系统空间堆栈,全部释放
goto end_wait4;子进程处于僵死状态,goto end_wait4
default:
continue;//否则继续第二层循环
}
}
if (options & __WNOTHREAD)
break;
tsk = next_thread(tsk);//从同一个thread_group队列中找到下一个线程的task_struct结构
} while (tsk != current);
read_unlock(&tasklist_lock);
if (flag) {//如果pid不是当前进程的子进程,直接到end_wait4
retval = 0;
if (options & WNOHANG)
goto end_wait4;
retval = -ERESTARTSYS;
if (signal_pending(current))
goto end_wait4;
schedule();
goto repeat;
}
retval = -ECHILD;
end_wait4:
current->state = TASK_RUNNING;
remove_wait_queue(¤t->wait_chldexit,&wait);
return retval;
}
下列条件之一得到满足时才结束,goto end_wait4:
1、所等待的子进程的状态变成TASK_STOPPED,TASK_ZOMBIE;
2、所等待的子进程存在,可不在上述两个状态,而调用参数options中的WHONANG标志位为1,或者当前进程接受到了其他的信号;
3、进程号pid的那个进程根本不存在,或者不是当前进程的子进程。
否则,当前进程将其自身的状态设成TASK_INTERRUPTIBLE,并调用schedule()。
schedule,代码如下:
asmlinkage void