<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    wait函數返回值總結

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    之前在學習wait和waitpid函數的時候,就對使用宏WIFEXITED來檢查獲取的進程終止狀態產生過疑惑:一般我們在程序中是調用的exit或者_exit函數來退出的,那么wait和waitpid函數獲取的終止狀態直接就是我們傳遞給exit的參數不就OK了嗎?

        后來了解到是我考慮簡單了,因為程序退出不僅僅只有我們顯示地調用exit這么簡單,還會有異常退出等情況,本文就對wait函數獲取的狀態做個總結!

        先來對wait status做個整體總結,一般我們通過wait status可以判定子進程發生了以下事件:

       (1)子進程通過傳遞一個整形參數給exit(或者_exit)而正常退出

       (2)子進程被一個信號終止

       (3)子進程被一個信號暫停(調用waitpid時指定WUNTRACED標志)

       (4)暫停的子進程被信號SIGCONT恢復(調用waitpid時指定WCONTINUED標志)

        平時我們說的進程termination status指的只是前兩個wait status(可以通過$?來查看進程的termination status)。

        那么wait status是如何表示這些事件的呢? —— 具體如何表示的,不同的平臺有不同的定義,因為POSIX并沒有對實現做出詳細的定義,這也是為什么推薦使用宏來檢查wait status了,主要是考慮到程序可移植問題。本文針對x86平臺32位。

    RFID設備管理軟件

        通過上圖可以發現,雖然wait status是int型的,但實際上只使用了它的低2個字節。

        高8位用來記錄正常退出狀態,這也正解釋了為什么程序退出狀態的范圍總是0~255。

        低8位用來記錄信號。

     

        好了,現在來看看這些宏具體是如何實現的吧!

        在/usr/include/i386-linux-gnu/sys/wait.h中

    RFID設備管理軟件

    在/usr/include/i386-linux-gnu/bits/waitstatus.h中

    RFID設備管理軟件

     

    接下來我們簡單分析下這幾個宏:

    WIFEXITED/WEXITSTATUS:當程序是正常退出時則WIFEXITED(status)為真,這種情況下WEXITSTATUS(status)返回子進程的退出狀態。

    WIFEXITED最后可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WIFEXITED(status) (((status) & 0x7f) == 0)  

    當WIFEXITED(status)為真則表示((status) & 0x7f)為0,意思是:程序退出不是信號導致的退出,那么就是正常退出了。

    WEXITSTATUS(status)可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WEXITSTATUS(status) (((status) & 0xff00) >> 8)  

    先將低8位清零,然后右移8位,則取得高8位數值,即程序正常退出狀態。

     

    WIFSTOPPED/WSTOPSIG:當子進程是因為被一個信號暫停而返回時則WIFSTOPPED(status)為真,在這種情況下WSTOPSIG(status)返回這個暫停子進程信號的編號。

    WIFSTOPPED(status)可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)  

    當wait status低八位數值是0x7f時,則表明子進程是被信號暫停而返回的。

    WSTOPSIG(status)可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WSTOPSIG(status) (((status) & 0xff00) >> 8)  

    可以發現,在這種情況下,WSTOPSIG(status)與WEXITSTATUS(status)取值方式是一樣的。

     

    WIFCONTINUED:當一個暫停的子進程被信號SIGCONT喚醒而返回狀態,則WIFCONTINUED(status)為真,否則為假。

    WIFCONTINUED(status)可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WIFCONTINUED(status) ((status) == 0xffff)  

    當wait status低兩個字節數值為0xfff時,表明一個暫停的子進程被SIGCONT信號喚醒。

     

    WIFSIGNALED/WTERMSIG/WCOREDUMP:當程序異常終止時WIFSIGNALED(staus)為真,這種情況下WTERMSIG(status)返回終止進程的信號編號。并且程序異常終止時產生了core文件的話,則WCOREDUMP(status)為真,否者為假。

    WIFSIGNALED(status)可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #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 copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))   

    這樣就好理解了,既不是信號暫停,又不是正常退出,那么肯定也不是被信號SIGCONT喚醒,那就肯定是被信號終止的情況了,哈哈。


    WTERMSIG(status)可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WTERMSIG(status) ((status) & 0x7f)  

    這個就不用解釋了吧

     

    WCOREDUMP(status)可以簡寫為:

    [html] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #define WCOREDUMP(status) ((status) & 0x80)  

    這個也很好理解,就是檢測第8位是否為1,是1,則生成core文件,否則不生成。

     

    綜上,可以發現APUE的pr_exit函數實現的不夠全,下面給個全面的如下:

    [cpp] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <string.h>  
    4. #include <sys/wait.h>  
    5.   
    6. void pr_exit(const char *msg, int status)  
    7. {  
    8.     if (msg)  
    9.         printf("%s ", msg);  
    10.   
    11.     if (WIFEXITED(status)) {  
    12.         printf("normal termination, exit status = %d\n", WEXITSTATUS(status));  
    13.     } else if (WIFSIGNALED(status)) {  
    14.         printf("abnormal termination, signal number = %d(%s)%s\n",  
    15.                 WTERMSIG(status), strsignal(WTERMSIG(status)),  
    16. #ifdef  WCOREDUMP  
    17.                 WCOREDUMP(status) ? " (core file generated)" : "");  
    18. #else  
    19.                 "");  
    20. #endif  
    21.     } else if (WIFSTOPPED(status)) {  
    22.         printf("child stopped, signal number = %d(%s)\n",  
    23.                 WSTOPSIG(status), strsignal(WSTOPSIG(status)));  
    24.     }  
    25. #ifdef WIFCONTINUED  
    26.     else if (WIFCONTINUED(status)) {  
    27.         printf("child continued by SIGCONT signal\n");  
    28.     }  
    29. #endif  
    30.     else {             /* Should never happen */  
    31.         printf("what happened to this child? (status=%x)\n",  
    32.                                     (unsigned int) status);  
    33.     }  
    34. }  

     

    PS:C標準對一個有符號數值并且是負數時的右移操作的說明是未實現的,我試了gcc,結果還是負數,對這塊了解的不是很多,還請諒解。

    參考鏈接:

    http://tsecer.blog.163.com/blog/static/15018172012323975152/

    http://www.cs.virginia.edu/pipermail/splint-discuss/2008-March/001136.html

    參考書籍:

    《The Linux Programming Interface》

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全