2011-05-16 181 views
15

我已經寫了一個應用程序,其中我已經註冊了不同信號在linux的信號處理程序的數量。 過程收到信號後,控制權被轉移到我已註冊的信號處理程序。在這個信號處理程序中,我做了一些我需要做的工作,然後我想調用默認的信號處理程序,例如SIF_DFLSIG_IGN。 然而,SIG_DFLSIG_ING都是宏分別擴展到數值0和1,它們是無效的函數的地址。執行默認信號處理程序

有什麼辦法,我可以叫即SIG_DFLSIG_IGN默認動作?

爲了達到SIG_DFLSIG_ING的效果,我分別調用exit(1)和什麼都不做。但對於像SIGSEGV這樣的信號,我也想要核心轉儲。 一般來說,我會想我的默認行爲是一樣SIG_DFL和忽略行爲相同SIG_IGN,途中操作系統會做。

+0

[顯式調用Linux上的SIG \ _DFL/SIG \ _IGN處理程序]的可能重複(http://stackoverflow.com/questions/3147840/explicitly-invoke-sig-dfl-sig-ign-handlers-on-linux ) – pilcrow 2014-12-21 04:31:35

回答

2

賦予的信號處理內核中實現,我看到的唯一的辦法就是

  • 重置處理程序和
  • raise()的信號再次
4

通常的做法是重置信號處理程序,然後再raise()信號:

下面是一個例子SIGINT處理程序:

void sigint_handler(int num) 
{ 
    /* handle SIGINT */ 

    // call default handler 
    signal(SIGINT, SIG_DFL); 
    raise(SIGINT); 
} 
+0

但是如何在不改變處理程序的情況下調用默認處理程序?在你的代碼中'sigint_handler'將不再被用作'SIGINT'處理程序。並且沒有清楚的地方將其設置回'sigint_handler'。 – 2014-11-10 11:12:39

+0

@AdamBadura - 那麼SIGINT的默認處理程序將終止該進程。在默認處理程序執行後,進程將不再運行的事實確實會使信號處理程序恢復成爲有點爭議的一點。 – CubicleSoft 2016-05-14 17:33:29

+0

@CubicleSoft在這種情況下你是對的。但一般情況下,當你不知道默認處理程序是什麼時候。雖然原來的問題似乎並不限於'SIGINT'。 – 2016-05-14 21:41:25

9

您可以保存以前的處理程序,然後在時間正確時調用它。

安裝處理程序。請務必保存舊處理器

static struct sigaction new_sa, old_sa; 

new_sa.handler = my_handler; 
sigemptyset(&new_handler.sa_mask); 

if (sigaction(signo, &new_sa, &old_sa) == -1) { 
    /* handle sigaction error */ 
} 

在新的處理程序,調用舊處理

(*old_sa.sa_handler)(signo) 

你並不需要再次提高,或做任何雜亂的東西;只需調用舊的處理程序(當然,因爲您保存了sigaction,您可以使用舊的處理程序等)。

+0

您是否還需要查看'sa_flags'中的'SA_SIGINFO'位,並調用'sa_sigaction'或'sa_handler'? – 2011-08-04 04:44:07

+0

@Greg Hewgill您應該:-) – cnicutar 2011-08-04 06:48:22

+0

今天我學習的東西比我想的要多,我需要了解Linux信號處理(請參閱http://stackoverflow.com/questions/6935988/how-to-provide-extend-on -write-功能換內存映射-文件合的Linux)。 – 2011-08-04 08:48:48

13

The GNU C Library Reference Manual有一整章解釋有關的信號處理一切。

當您安裝您自己的處理程序時,您總是會獲得先前設置的信號處理程序(函數指針)(請參閱signal()sigaction()的聯機幫助頁)。

previous_handler = signal(SIGINT, myhandler); 

一般的規則是,你可以總是重置到前面的處理程序和raise()的信號。

void myhandler(int sig) { 
    /* own stuff .. */ 
    signal(sig, previous_handler); 
    raise(sig); 
    /* when it returns here .. set our signal handler again */ 
    signal(sig, myhandler); 
} 

有一個的一般規則的缺點:被映射到信號的硬件異常通常被分配給一個特定的指令,該指令引起異常。所以,當你再次發出信號時,相關的指令與原來的不一樣。這可以但不應該傷害其他信號處理程序。

另一個缺點是,每個提出的信號造成了大量的處理時間。爲了防止過度使用raise()您可以使用下列選項:

  1. SIG_DFL函數指針點的情況下,解決0(這顯然是沒有有效的地址)。因此,你必須重新設置處理程序和raise()的信號。

    if (previous_handler == SIG_DFL) 
    { 
        signal(sig, SIG_DFL); 
        raise(sig); 
        signal(sig, myhandler); 
    }
  2. SIG_IGN具有值1(也無效地址)。在這裏,你可以返回(什麼也不做)。

    else if (previous_handler == SIG_IGN) 
    { 
        return; 
    }
  3. 否則(既不SIG_IGN也不SIG_DFL)你收到了一個有效的函數指針,你可以直接調用處理程序,

    else 
    { 
        previous_handler(sig); 
    }

當然,你必須要考慮的不同的API(請參閱signal()sigaction()的聯機幫助頁)。

+0

我會強烈考慮是否值得通過直接調用處理函數來進行優化。這不是「面向未來」的。如果一個系統來創建另一個特殊處理程序('SIG_FUN'),那麼上面的優化將失敗,因爲它將嘗試實際調用它作爲函數,而它不是一個有效的指針... – 2014-11-10 10:57:22

+7

也你確定這將工作?GNU C庫參考聲明(例如在24.7.5中),當該信號的處理程序執行時信號的傳遞被阻塞。所以你的'raise'只會發送信號,但不會調用處理程序。然後您將重置回處理程序。在你的處理程序存在後,來自'raise'的信號將被傳遞,但會找到你自己的處理程序。 – 2014-11-10 11:09:25

+0

您提供的鏈接已死亡。 – 2015-06-03 20:01:24