linux进程管理之wait系统调用

六: 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;
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索进程
, 状态
, continue
, Wait()
, Options
, fallthrough
, current
RETVAL
wait系统调用、linux 查看系统进程、linux 进程被系统kill、linux系统进程类型、linux系统进程管理,以便于您获取更多的相关知识。

时间: 2024-10-30 00:56:26

linux进程管理之wait系统调用的相关文章

Linux进程管理的4个常用命令

Linux是一个多用户.多任务的操作系统.在这样的系统中,各种计算机资源(如文件.内存.CPU等)的分配和管理都以进程为单位.为了协调多个进程对这些共享资源的访问,操作系统要跟踪所有进程的活动,以及它们对系统资源的使用情况,从而实施对进程和资源的动态管理.进程在一定条件下可以对诸如文件.数据库等客体进行操作.如果进程用作其他不法用途,将给系统带来重大危害.在现实生活当中,许多网络黑客都是通过种植"木马"的办法来达到破坏计算机系统和入侵的目的,而这些"木马"程序无一例

linux进程管理工具htop安装教程

htop 是一个 Linux 下的交互式的进程浏览器,可以用来替换Linux下的top命令. htop官网:http://hisham.hm/htop/ 系统环境:CentOS release 5.8 (Final) 安装htop需要ncurses支持,请确保已安装: [root@localhost ~]# yum install ncurses ncurses-devel 安装htop # wget http://hisham.hm/htop/releases/1.0/htop-1.0.tar

Linux进程管理与调度-之-目录导航【转】

转自:http://blog.csdn.net/gatieme/article/details/51456569 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme   目录(?)[-] 项目链接 进程的描述 进程的创建 进程的加载与运行 进程的退出 进程的调度 调度普通进程-完全公平调度器CFS   日期 内核版本 架构 作者 GitHub CSDN 2016-07-21 Linux-4.6 X86 & arm gat

Linux进程管理剖析:创建、管理、调度和销毁

简介:Linux 的用户空间进程的创建和管理所涉及的原理与 UNIX 有很多共同点,但也 有一些特定于 Linux 的独特之处.在本文中,了解 Linux 进程的生命周期,探索用户进程创建.内存管 理.调度和销毁的内核内幕. Linux 是一种动态系统,能够适应不断变化的计算需求.Linux 计 算需求的表现是以进程 的通用抽象为中心的.进程可以是短期的(从命令行执行的一个命令),也可以 是长期的(一种网络服务).因此,对进程及其调度进行一般管理就显得极为重要. 在用户空间,进程是由进程标识符(

linux进程管理和作业任务

  进程是为了使多个程序可以并发的执行,提高系统的资源利用和吞吐量 1.linux中每个进程都有一个识别号PID 2.系统第一个启动进程是init,PID是1,是唯一一个由系统内核直接运行的进程,新的进程都是系统调用fork来产生,除了init之外,每个进程都有一个父进程. 3每个进程有实际用户识别号(运行此进程的用户识别号),实际组识别号(运行此进程的组识别号). 4.进程的类型,交互进程,由一个Shell启动的进程. 批处理进程,不与特定的终端相关联,提交到等待队列中顺序执行的进程. 守护进

Linux 进程管理剖析(创建、管理、调度和销毁)

Linux 是一种动态系统,能够适应不断变化的计算需求.Linux 计算需求的表现是以进程 的通用抽象为中心的.进程可以是短期的(从命令行执行的一个命令),也可以是长期的(一种网络服务).因此,对进程及其调度进行一般管理就显得极为重要. 在用户空间,进程是由进程标识符(PID)表示的.从用户的角度来看,一个 PID 是一个数字值,可惟一标识一个进程.一个 PID 在进程的整个生命期间不会更改,但 PID 可以在进程销毁后被重新使用,所以对它们进行缓存并不见得总是理想的. 在用户空间,创建进程可以

Linux进程管理之“四大名捕”

一.四大名捕 四大名捕,最初出现于温瑞安创作的武侠小说,是朝廷中正义力量诸葛小花的四大徒弟,四人各怀绝技,分别是轻功暗器高手"无情".内功卓越的高手"铁手".腿功惊人的"追命"和剑法一流的"冷血" 本文四大名捕由linux命令所出演 无情:ps 出演 铁手:dstat 出演 追命:top 出演 冷血:htop 出演 二.进程相关基础知识 介绍四大名捕之前先介绍一下进程相关的基础知识,话不多说,看图. 三.轻功暗器高手"

Linux进程管理及作业控制

Linux是一个多任务的操作系统,系统上同时运行着多个进程,正在执行的一个或多个相关进程称为一个作业.使用作业控制,用户可以同时运行多个作业,并在需要时在作业之间进行切换.本章详细介绍进程管理及作业控制的命令,包括启动进程.查看进程.调度作业的命令. 进程及作业的概念 Linux是一个多用户多任务的操作系统.多用户是指多个用户可以在同一时间使用计算机系统:多任务是指Linux可以同时执行几个任务,它可以在还未执行完一个任务时又执行另一项任务. 操作系统管理多个用户的请求和多个任务.大多数系统都只

linux进程管理之进程创建

所谓进程就是程序执行时的一个实例. 它是现代操作系统中一个很重要的抽象,我们从进程的生命周期:创建,执行,消亡来分析一下Linux上的进程管理实现. 一:前言 进程管理结构; 在内核中,每一个进程对应一个task.就是以前所讲的PCB.它的结构如下(include/linux/sched.h): struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; at