信號之sigsetjmp和siglongjmp函數


在信號處理程序中經常調用longjmp函數以返回到程序的主循環中,而不是從該處理程序返回。

但是,調用longjmp有一個問題。當捕捉到一個信號時,進入信號捕捉函數,此時當前信號被自動地加到進程的信號屏蔽字中。這阻止了后來產生的這種信號中斷該信號處理程序。(僅當從信號捕捉函數返回時再將進程的信號屏蔽字復位為原先值:http://www.cnblogs.com/nufangrensheng/p/3515945.html如果用longjmp跳出信號處理程序,那么,對此進程的信號屏蔽字會發生什么呢()?(setjmp和longjmp保存和恢復信號屏蔽字,還是不保存和恢復,不同的實現各有不同。)

為了允許兩種形式的行為並存,POSIX.1並沒有說明setjmp和longjmp對信號屏蔽字的作用,而是定義了兩個新函數sigsetjmp和siglongjmp。在信號處理程序中進行非局部轉移時使用這兩個函數。

#include <setjmp.h>

int sigsetjmp(sigjmp_buf env, int savemask);
返回值:若直接調用則返回0,若從siglongjmp調用返回則返回非0值

void siglongjmp(sigjmp_buf env, int val);

這兩個函數與setjmp和longjmp之間的唯一區別是sigsetjmp增加了一個參數。如果savemask非0,則sigsetjmp在env中保存進程的當前信號屏蔽字調用siglongjmp時,如果帶 非0 savemask的sigsetjmp調用已經保存了env,則siglongjmp從其中恢復保存的信號屏蔽字

 

實例

程序清單10-14演示了在信號處理程序被調用時,系統所設置的信號屏蔽字如果自動地包括剛被捕捉到的信號。該程序也通過實例說明了如何使用sigsetjmp和siglongjmp函數。

程序清單10-14 信號屏蔽字、sigsetjmp和siglongjmp實例

#include "apue.h"
#include <setjmp.h>
#include <time.h>

static void            sig_usr1(int), sig_alrm(int);
static sigjmp_buf        jmpbuf;
static volatile sig_atomic_t     canjump;

int
main(void)
{
    if (signal(SIGUSR1, sig_usr1) == SIG_ERR)
        err_sys("signal(SIGUSR1) error");

    if (signal(SIGALRM, sig_alrm) == SIG_ERR)
        err_sys("signal(SIGALRM) error");
    
    pr_mask("starting main: ");

    if (sigsetjmp(jmpbuf, 1))
    {
        pr_mask("ending main: ");
        exit(0);
    }
    canjump = 1;    /* now sigsetjmp() is OK */

    for(; ;)
        pause();
}

static void
sig_usr1(int signo)
{    
    time_t starttime;

    if (canjump == 0)
        return;        /* unexpected signal, ignore */

    pr_mask("starting sig_usr1: ");
    alarm(3);        /* SIGALRM in 3 seconds */
    starttime = time(NULL);
    for(; ;)        /* busy wait for 5 seconds */
        if (time(NULL) > starttime + 5)
            break;
    pr_mask("finishing sig_usr1: ");
    
    canjump = 0;
    siglongjmp(jmpbuf, 1);    /* jump back to main, don't return */
}


static void 
sig_alrm(int signo)
{
    pr_mask("in sig_alrm: ");
}

pr_mask函數參見:http://www.cnblogs.com/nufangrensheng/p/3515257.html中程序清單10-10

此程序演示了另一種技術,只要在信號處理程序中調用siglongjmp,就應使用這種技術:僅在調用sigsetjmp之后才將變量canjump設置為非0值。在信號處理程序中檢測此變量,僅當它為非0值時才調用siglongjmp。這提供了一種保護機制,使得在jmpbuf(跳轉緩沖)尚未由sigsetjmp初始化時,防止調用信號處理程序。在一般的C代碼中(不是信號處理程序),對於longjmp並不需要這種保護措施。但是,因為信號可能在任何時候發生,所以在信號處理程序中,需要這種保護措施。

在程序中使用了數據類型sig_atomic_t,這是由ISO C標准定義的變量類型,在寫這種類型的變量時不會被中斷。這種類型的變量總是包括ISO類型修飾符voaltile。

在RedHat Linux 2.6.18版本中執行程序清單10-14並沒有出現我們所預期的結果:當調用一個信號處理程序時,被捕捉到的信號加到進程的當前信號屏蔽字中。當從信號處理程序返回時,恢復原來的屏蔽字。不知為何???

未命名

從上面運行結果可以看出,信號屏蔽字始終都是空。本來應該是在調用一個信號處理程序時,被捕捉到的信號加到進程的當前信號屏蔽字中。為啥沒有加進去呢?還是加進去了沒有更新信號屏蔽字呢?

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關於本書可參考:http://www.apuebook.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM