首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

wait函数返回值总结(2)

wait函数返回值总结(2)

接下来我们简单分析下这几个宏:
WIFEXITED/WEXITSTATUS:当程序是正常退出时则WIFEXITED(status)为真,这种情况下WEXITSTATUS(status)返回子进程的退出状态。
WIFEXITED最后可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WIFEXITED(status) (((status) & 0x7f) == 0)  
当WIFEXITED(status)为真则表示((status) & 0x7f)为0,意思是:程序退出不是信号导致的退出,那么就是正常退出了。
WEXITSTATUS(status)可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)  
先将低8位清零,然后右移8位,则取得高8位数值,即程序正常退出状态。

WIFSTOPPED/WSTOPSIG:当子进程是因为被一个信号暂停而返回时则WIFSTOPPED(status)为真,在这种情况下WSTOPSIG(status)返回这个暂停子进程信号的编号。
WIFSTOPPED(status)可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)  
当wait status低八位数值是0x7f时,则表明子进程是被信号暂停而返回的。
WSTOPSIG(status)可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WSTOPSIG(status) (((status) & 0xff00) >> 8)  
可以发现,在这种情况下,WSTOPSIG(status)与WEXITSTATUS(status)取值方式是一样的。

WIFCONTINUED:当一个暂停的子进程被信号SIGCONT唤醒而返回状态,则WIFCONTINUED(status)为真,否则为假。
WIFCONTINUED(status)可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WIFCONTINUED(status) ((status) == 0xffff)  
当wait status低两个字节数值为0xfff时,表明一个暂停的子进程被SIGCONT信号唤醒。

WIFSIGNALED/WTERMSIG/WCOREDUMP:当程序异常终止时WIFSIGNALED(staus)为真,这种情况下WTERMSIG(status)返回终止进程的信号编号。并且程序异常终止时产生了core文件的话,则WCOREDUMP(status)为真,否者为假。
WIFSIGNALED(status)可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WIFSIGNALED(status) (((signed char)((status) & 0x7f + 1) >> 1) > 0)  
这个宏的写法是这些宏当中最难理解的一个,以下是我的简单分析过程,对错还请批评指正!
(status) & 0x7f 的范围是0 ~ 127
(status) & 0x7f + 1 的范围是0 ~ 128
那么(signed char)((status) & 0x7f + 1) 的范围是1 ~ 127 和一个-128
由此推出:(signed char)((status) & 0x7f + 1) >> 1的范围是0 ~ 63 和一个-64
由此得出当wait status的低7位数值是0x7f时是不符合要求的,即宏WIFSIGNALED(status)的这种写法其实是排除了wait status的低7位数值是0x7f的。因为当低7位是0x7f(第8位为0)时表示的是子进程被信号暂停。其实现有的平台的信号编号也没有达到127的。
我们知道信号编号是从1开始的(kill函数对信号编号0有特殊的处理)。右移一位相当于除以2的操作,1除以2在程序中是等于0的,所有其中的加1操作其实很有技巧性,既利用了信号编号从1开始这个特性,又排除了127这个数值。
这个宏还可以如下实现:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))   
这样就好理解了,既不是信号暂停,又不是正常退出,那么肯定也不是被信号SIGCONT唤醒,那就肯定是被信号终止的情况了,哈哈。

WTERMSIG(status)可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WTERMSIG(status) ((status) & 0x7f)  
这个就不用解释了吧

WCOREDUMP(status)可以简写为:
[html] view plain copyprint?在CODE上查看代码片派生到我的代码片
#define WCOREDUMP(status) ((status) & 0x80)  
这个也很好理解,就是检测第8位是否为1,是1,则生成core文件,否则不生成。

综上,可以发现APUE的pr_exit函数实现的不够全,下面给个全面的如下:
[cpp] view plain copyprint?在CODE上查看代码片派生到我的代码片
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/wait.h>  
  
void pr_exit(const char *msg, int status)  
{  
    if (msg)  
        printf("%s ", msg);  
  
    if (WIFEXITED(status)) {  
        printf("normal termination, exit status = %d\n", WEXITSTATUS(status));  
    } else if (WIFSIGNALED(status)) {  
        printf("abnormal termination, signal number = %d(%s)%s\n",  
                WTERMSIG(status), strsignal(WTERMSIG(status)),  
#ifdef  WCOREDUMP  
                WCOREDUMP(status) ? " (core file generated)" : "");  
#else  
                "");  
#endif  
    } else if (WIFSTOPPED(status)) {  
        printf("child stopped, signal number = %d(%s)\n",  
                WSTOPSIG(status), strsignal(WSTOPSIG(status)));  
    }  
#ifdef WIFCONTINUED  
    else if (WIFCONTINUED(status)) {  
        printf("child continued by SIGCONT signal\n");  
    }  
#endif  
    else {             /* Should never happen */  
        printf("what happened to this child? (status=%x)\n",  
                                    (unsigned int) status);  
    }  
}  

PS:C标准对一个有符号数值并且是负数时的右移操作的说明是未实现的,我试了gcc,结果还是负数,对这块了解的不是很多,还请谅解。
继承事业,薪火相传
返回列表