wait4的实现

当进程已经死亡,但仍然以某种方式活着称它是僵尸进程。僵尸进程如何产生的呢?因为在UNIX OS下进程创建和销毁的方式。在两种事情发生时,程序将终止运行:一,进程必须由另一个进程或用户杀死(通过发送sigterm或sigkill信号来完成,这是正常的终止进程);二,进程的父进程在子进程终止时必须调用或已经调用wait4系统调用。

只有在第一个条件发生而第二个条件不成立时,才会出现僵尸进程。那么wait4是怎样实现的呢?

 

         wait4会挂起当前进程,等待指定的子进程状态改变,并且会返回关于子进程使用资源的信息。所谓的状态的改变包括终止,挂起所有的进程状态的改变。
其次,在linux中进程终止后不会释放其资源,它会进入一种僵死的状态,内核会为僵死态的进程保留最少的信息(进程标识,终止状态和资源使用信息).而wait4就可以释放与子进程关联的资源。如果父进程不执行wait,而父进程又死亡后,僵死态的子进程会被指定成系统初始化进程init的子进程.下面是wait4使用方法:
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
pid是要关注的子进程的pid(进程标识号)
status子进程的返回状态。
options进程等待选项
rusage死亡进程资源使用记录

pid这个很好理解,进程标识号,也是你ps -le显示出来的pid。如果指定了pid则会在指定pid发生变化后唤醒父进程,此外还有一下4种情况:
    <-1   which means to wait for any child process whose process group ID is equal to the absolute value of pid.
     -1     which means to wait for any child process; this is equivalent to calling wait3.
      0      which means to wait for any child process whose process group ID is equal to that of the calling process.
   > 0    which means to wait for the child whose process ID is equal to the value of pid.

      status子进程的返回状态,这是个用于描述进程返回状态的整数,有各种宏操作可以查看,如下:
WIFEXITED(status)
    is non-zero if the child exited normally.
WEXITSTATUS(status)
    evaluates to the least significant eight bits of the return code of the child which terminated, which may have been set as the argument to a call
to exit() or as the argument for a return statement in the main program. This macro can only be evaluated if WIFEXITED returned non-zero.
WIFSIGNALED(status)
    returns true if the child process exited because of a signal which was not caught.
WTERMSIG(status)
    returns the number of the signal that caused the child process to terminate. This macro can only be evaluated if WIFSIGNALED returned non-zero.
WIFSTOPPED(status)
    returns true if the child process which caused the return is currently stopped; this is only possible if the call was done using WUNTRACED.
WSTOPSIG(status)
    returns the number of the signal which caused the child to stop. This macro can only be evaluated if WIFSTOPPED returned non-zero.
options进程等待选项,当为WNOHANG表示立即返回,而当WUNTRACED表示等子进程状态发生变化后才返回。
   最后rusage记录死亡进程资源使用信息,这个数据结构定义如下:
 struct rusage {
    struct timeval ru_utime; /* user time used */
    struct timeval ru_stime; /* system time used */
    long   ru_maxrss;        /* maximum resident set size */
    long   ru_ixrss;         /* integral shared memory size */
    long   ru_idrss;         /* integral unshared data size */
    long   ru_isrss;         /* integral unshared stack size */
    long   ru_minflt;        /* page reclaims */
    long   ru_majflt;        /* page faults */
    long   ru_nswap;         /* swaps */
    long   ru_inblock;       /* block input operations */
    long   ru_oublock;       /* block output operations */
    long   ru_msgsnd;        /* messages sent */
    long   ru_msgrcv;        /* messages received */
    long   ru_nsignals;      /* signals received */
    long   ru_nvcsw;         /* voluntary context switches */
    long   ru_nivcsw;        /* involuntary context switches */
};

首先实现的功能是:根据给定的参数去守候子进程,收集子进程使用资源的记录信息,比回收子进程没有回收的资源,系统堆栈空间。

流程:某个进程调用了wait4函数,假设调用如:wait(要等待的子进程的pid,WUNTRACED,status,reus)。

wait第一个动作就是current->state = TASK_INTERRUPTIBLE;将当前进程的状态设置成TASK_INTERRUPTIBLE表示挂起,休眠,阻碍等等。接下来是一大堆的检查判断,判断通过的话就执行current->state = TASK_RUNNING;,将进程状态设置成可以运行,然后执行remove_wait_queue(&current->wait_chldexit,&wait);再返回,至于是什么判断这里先不管这些,最后执行schedule();意思就是进程从新调度。下面我们看看这么做的意义:

首先我们把进程状态改成了阻塞,如果判断条件没通过,意思就是说在调用schedule()后当前进程就被阻塞不会运行了。那什么时候会唤醒呢,前面我们讨论过exit函数,一个进程在exit时候就会唤醒他的父进程,这里就是他该唤醒的地方,唤醒后,父进程会循环继续回到current->state = TASK_INTERRUPTIBLE;继续运行,如此循环,那么退出循环就是以下几个条件之一被满足:

a.所等待的子进程状态变成了TASK_STOPPED或者TASK_ZOMBIE;

b.所等待的子进程存在但不是上面2种状态,而调用参数为WNOHANG,或者当前进程收到了其它的信号;

c.所等待的进程PID不存在,或者不是当前进程的子进程。

这几种条件判断正好适应以下几种情况:

1.等待子进程被跟踪,属于TASK_STOPPED,

2.等待子进程僵死,属于TASK_ZOMBIE,

3.参数为WNOHANG,正好符合我们wait4调用参数WNOHANG的意义,就是不等待子进程直接执行完毕。

4.进程收到其它信号,属于其它情况。

5.等待进程的PID不存在或者不是当前进程的子进程,代码写错了。

 参考:《linux内核架构》

              http://hi.baidu.com/andimeo/item/ae7dfef632b7f2dd6225d214

             http://memorymyann.iteye.com/blog/243142

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值