Linux内核源代码情景分析-wait()、schedule()

    父进程执行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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值