訊號集給我們提供了一個能表示多個訊號的是資料類型(sigset_t), 它將在sigprocmask, sigpending, sigsuspend之類的函數中用到, 這些函數我會在以後的文章中介紹.
1. 訊號集相關函數:
#include <signal.h>
int sigemptyset(sigset_t *set);
成功則返回0, 出錯則返回-1.
這個函數用作初始化set指向的訊號集, 清空其中的所有訊號.
#include <signal.h>
int sigfillset(sigset_t *set);
成功則返回0, 出錯則返回-1.
這個函數用作初始化set指向的訊號集, 填充其中的所有訊號.
#include <signal.h>
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
成功則返回0, 出錯則返回-1.
這兩個函數用作向set指向的訊號集中, 增加/刪除一個signo代表的訊號.
#include <signal.h>
int sigismember(const sigset_t *set, int signo);
真則返回1, 假則返回0, 出錯則返回-1.
這個函數用作判斷signo訊號是否在set指向的訊號集中.
2. 宏:
在signal.h中有兩個宏:
#define sigemptyset(ptr) (*(ptr) = 0)
#define sigfillset(ptr) (*ptr = ~(sigset_t)0, 0)
這兩個宏分別定義了sigemptyset和sigfillset兩個函數的行為.
- sigemptyset: 把ptr指向的地址的內容設為0.
- sigfillset: 這是一個逗號運算式, 把0轉換為sigset_t類型, 然後按位取反, 並返回0.
通過以上兩個宏, 我們可以確切地說, sigset_t是用多位(比訊號總數更多的位元)來表示訊號集概念的.
因此,
sigaddset: 將某一位設定為1.
sigdelset: 將某一位設定為0.
sigismember: 測試某一個指定位.
下面我們來實現這些函數.
3. 執行個體:
#include <signal.h>
#include <errno.h>
/* NSIG defined in <signal.h> */
#define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG)
int sigaddset(sigset_t *set, int signo)
{
if (SIGBAD(signo))
{
errno = EINVAL;
return (-1);
}
*set |= 1 << (signo -1);
return 0;
}
int sigdelset(sigset_t *set, int signo)
{
if (SIGBAD(signo))
{
errno = EINVAL;
return (-1);
}
*set &= ~(1 << (signo -1));
return 0;
}
int sigismember(const sigset_t *set, int signo)
{
if (SIGBAD(signo))
{
errno = EINVAL;
return (-1);
}
return ((*set & (1 << (signo -1))) != 0);
}
說明一下裡面的幾個細節:
signo - 1: 因為不存在編號為0的訊號, 也就是第0位與編號為1的訊號是對應的, 所以減1.
SIGBAD: 小於等於0, 或者大於最大訊號編號NSIG.
1 << : 1的左移位操作, 右邊補0, 所以執行或操作時直接實現添加; 執行與操作時需要先取反, 以保證本位為0, 其他位不變, 這樣來實現刪除.
sigismember: 最後一個return語句看上去有些複雜. 想起來很難想到, 但看起來應該不難. 執行移位後的與操作, 當存在時使本位保持不變, 其他位清零; 當不存在時, 全部清零. 然後判斷是否為0, 這樣來實現判斷存在性.