信號掩碼

類UNIX環境中,信號(signal)是通知進程已發生某種情況的一種技術。信號是軟體中斷。很多應用程式都需要處理信號。信號提供了一種處理異步事件的方法。例如,終端用戶鍵入中斷鍵(interrupt key,通常是Ctrl+C),則會通過信號機制停止一個程式,或及早終止管道中的下一個程式。

基本介紹

  • 中文名:信號掩碼
  • 外文名:signal mask
  • 別名:信號禁止字
簡介,舉例,信號集處理函式,

簡介

每個進程都有一個信號掩碼(signal mask),也稱為信號禁止字,它規定了當前要禁止或要阻塞遞送到該進程的信號集。對於每種可能的信號,該掩碼中都有一位與之對應。對於某種信號,若其對應位(bit)已設定,則它當前是被阻塞的。簡單地說,信號掩碼是一個“點陣圖”,其中每一位都對應著一種信號。如果點陣圖中的某一位為1,就表示在執行當前信號集的處理程式期間相應的信號暫時被“禁止”或“阻塞”,使得在執行的過程中不會嵌套地回響那個信號。

舉例

為什麼要對某一信號進行禁止呢?我們來看一下對Ctrl+C的處理。當一個程式正在運行時,在鍵盤上按下Ctrl+C,核心就會向相應的進程發出一個SIGINT信號(終端中斷符),對這個信號的默認操作就是通過do_exit()結束該進程的運行。但是,有些應用程式可能對Ctrl+C有自己的處理,所以就要為SIGINT另行設定一個處理程式,使它指向應用程式中的一個函式,在那個函式中對Ctrl+C這個事件做出回響。但是,在實踐中發現,兩次Ctrl+C事件往往過於密集,有時候剛剛進入第一個信號的處理程式,第二個SIGINT信號就到達了,而第二個信號的默認操作是殺死進程,這樣,第一個信號的處理程式根本沒有執行完。為了避免這種情況的出現,就在執行一個信號處理程式的過程中將該種信號自動禁止掉。所謂“禁止”,與將信號忽略是不同的,它只是將信號暫時“遮蓋”一下,一旦禁止去掉,已到達的信號又繼續得到處理。

信號集處理函式

POSIX.1定義了數據類型sigset_t來表示或保存多個信號——信號集(signal set),信號掩碼就存放在這些信號集中。POSIX定義了下列5個處理信號集的函式。
int sigemptyset(sigset_t *set) 初始化由set指向的信號集,清除其中所有信號,即設定所有信號掩碼的阻塞標誌
int sigfillset(sigset_t *set) 初始化由set指向的信號集,使其包括所有信號,即清除所有信號掩碼的阻塞標誌
int sigaddset(sigset_t *set, int signo) 將一個特定信號signo添加到set指向的信號集中,可用於增加個別信號阻塞
int sigdelset(sigset_t *set, int signo) 從set指向的信號集中刪除一個特定信號signo,可用於刪除個別信號阻塞
int sigismember(const sigset_t *set, int signo) 檢查某個信號是否在set指向的信號集中,可確定特定的信號是否在掩碼中被標誌為阻塞。
另外,進程也可以調用sigprocmask()來檢測和更改其當前的信號掩碼,以便告訴核心不允許觸發該信號集中的信號。其實現代碼在kernel/signal.c中,原型為:
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
首先,若oset是非空指針,那么進程的當前信號掩碼通過oset返回。
其次,若set是一個指向信號集的非空指針,則參數how指示如何修改當前進程的信號掩碼。參數how的取值及含義如下:
SIG_BLOCK 該進程新的信號掩碼是其當前信號掩碼和set所指向信號集的並集,即set規定了我們希望阻塞的附加信號。
SIG_UNBLOCK 該進程新的信號掩碼是其當前信號掩碼和set所指向信號集的補集的交集,即set包含了我們希望解除阻塞的信號。
SIG_SETMASK 該進程新的信號掩碼將被set指向的信號集代替,即set變成該進程新的信號掩碼。
如果set是空指針,則不改變該進程的信號掩碼,how的值也無意義。用一段代碼來說明這個邏輯:
switch (how) {
case SIG_BLOCK:
current->blocked |= set;
break;
case SIG_UNBLOCK:
current->blocked &= ~set;
break;
case SIG_SETMASK:
current->blocked = set;
break;
default:
return -EINVAL;
}
其中current表示指向當前進程結構的指針,其中包含當前進程的信號掩碼blocked。

相關詞條

熱門詞條

聯絡我們