轉載 :http://blog.csdn.net/budory/article/details/46803863
在POSIX下,每個程序有一個信号掩碼(signal mask)。簡單地說,信号掩碼是一個“位圖”,其中每一位都對應着一種信号。如果位圖中的某一位為1,就表示在執行目前信号的處理程式期間相應的信号暫時被“屏蔽”,使得在執行的過程中不會嵌套地響應那種信号。
為什麼對某一信号進行屏蔽呢?我們來看一下對CTRL+C的處理。大家知道,當一個程式正在運作時,在鍵盤上按一下CTRL+C,核心就會向相應的程序發出一個SIGINT信号,而對這個信号的預設操作就是通過do_exit()結束該程序的運作。但是,有些應用程式可能對CTRL+C有自己的處理,是以就要為SIGINT另行設定一個處理程式,使它指向應用程式中的一個函數,在那個函數中對CTRL+C這個事件作出響應。但是,在實踐中卻發現,兩次CTRL+C事件往往過于密集,有時候剛剛進入第一個信号的處理程式,第二個SIGINT信号就到達了,而第二個信号的預設操作是殺死程序,這樣一來第一個信号的處理程式根本沒有執行完。為了避免這種情況的出現,就在執行一個信号處理程式的過程中将該種信号自動屏蔽掉。所謂“屏蔽”,與将信号忽略是不同的,它隻是将信号暫時“遮蓋”一下,一旦屏蔽去掉,後續收到的該信号又繼續得到處理。
Linux核心中有一個專門的函數集合來執行設定和修改信号掩碼,它們放在kernel/signal.c中,其函數形式和功能如下:
函數形式 功能
int sigemptyset(sigset_t *mask) 清所有信号掩碼的阻塞标志
int sigfillset(sigset_t *mask, int signum) 設定所有信号掩碼的阻塞标志
int sigdelset(sigset_t *mask, int signum) 删除個别信号阻塞
int sigaddset(sigset_t *mask, int signum) 增加個别信号阻塞
int sigisnumber(sigset_t *mask, int signum) 确定特定的信号是否在掩碼中被标志為阻塞。
另外,程序也可以利用sigprocmask()系統調用改變和檢查自己的信号掩碼的值,其實作代碼在kernel/signal.c中,原型為:
int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
其中,set是指向信号掩碼的指針,程序的信号掩碼是根據參數how的取值設定成set;參數how的取值及含義如下:
SIG_BOLCK set規定附加的阻塞信号;
SIG_UNBOCK set規定一組不予阻塞的信号
SIG_SETBLOCK set變成新程序的信号掩碼
用一段代碼來說明這個問題
[cpp] view plain copy
switch (how)
{
case SIG_BLOCK:
current->blocked |= new_set;
break;
case SIG_UNBLOCK:
current->blocked &= ~new_set;
break;
case SIG_SETMASK:
current->blocked = new_set;
break;
default:
return -EINVAL;
}
其中current為指向目前程序task_struct結構的指針。
第三個參數oset也是指向信号掩碼的指針,它将包含以前的信号掩碼值,使得在必要的時候可以恢複它。
程序可以用sigpending()系統調用來檢查是否有挂起的阻塞信号。