加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

linux进程管理之wait系统调用

发布时间:2016-01-25 10:27:02 所属栏目: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(&current->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(&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;
}

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读