3.2 信號集及其操作
信號集的操作函數, sigsetops
============================================================= #include
int sigemptyset (sigset_t *set);
int sigfillset (sigset_t *set);
int sigaddset (sigset_t *set, int signum);
int sigdelset (sigset_t *set, int signum);
int sigismember (const sigset_t *set, int signum);
-------------------------------------------------------------------------------
上述函數的一種實現:
#define sigemptyset (ptr) ( *(ptr) = 0 )
#define sigfillset (ptr) ( *(ptr) = ~(sigset_t)0, 0 )
/* C 語言的逗號運算符: 返回右邊的值作為表達式的返回值 */
#include
#include
#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 (sigset_t *set, int signo)
{
if (SIGBAD (signo)) {errno = EINVAL; return -1;}
return ((*set & (1<< (signo - 1))) != 0);
}
=============================================================
7.3.3 可靠信號系統調用
sigaction, sigprocmask, sigpending, sigsuspend
============================================================= #include
int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact);
int sigprocmask (int how, const sigset_t *set, sigset_t *oldset);
int sigpending (sigset_t *set);
int sigsuspend (const sigset_t *mask);
-------------------------------------------------------------------------------
struct sigaction {
void (*sa_handler) (int);
void (*sa_sigaction) (int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void); // 廢棄的元素, 不應使用
}
-------------------------------------------------------------------------------
sigaction:
* sigaction 用於改變進程在接收到信號時的動作.
* sigaction 可指定除 SIGKILL 和 SIGSTOP 之外的信號的動作 (act->sa_handler),
可取 SIG_DFL, SIG_IGN 和用戶定義函數.
* sigaction 可指定在處理 signum 信號時, 應該阻塞的信號集 (act->sa_mask).
* sigaction 可指定信號處理過程中的行為 (act->sa_flags), 下述標誌 "或" 的結果:
o SA_NOCLDSTOP: 子進程停止時不接收 SIGCHLD.
o SA_ONESHOT 或 SA_RESETHAND: 重置信號動作為默認值.
o SA_RESTART: 如果該信號中斷慢系統調用, 則重新啟動系統調用.
o SA_NOMASK 或 SA_NODEFER: 不要避免在信號處理函數中接收同一信號.
o SA_SIGINFO: 信號處理函數接受三個參數. 這時, 必須設置 act->sa_sigaction
元素, 其中 siginfo_t 是內核傳遞到信號處理函數中的發生信號時進程的狀態
信息. 詳細信息, 可參閱 sigaction(2) 手冊頁.
* oldact 非空時, 可返回先前的設置.
* 利用 SA_SIGINFO 和 siginfo_t 實現有效的存儲管理.
-------------------------------------------------------------------------------
sigprocmask:
* sigprocmask 用於改變進程的當前阻塞信號集.
* how 可取 SIG_BLOCK, SIG_UNBLOCK 和 SIG_MASKSET. 前兩個動作分別在當前阻塞
信號集中添加或刪除由 set 指定的信號集, SIG_MASK 用於完全設置阻塞信號集.
* oldset 非空時, 可返回先前的設置.
-------------------------------------------------------------------------------
sigpending:
* sigpending 用於檢驗掛起的信號.
-------------------------------------------------------------------------------
sigsuspend:
* sigsuspend 用於在接收到某個信號之前, 臨時用 mask 替換進程的信號掩碼, 並
暫停進程執行.
* sigsuspend 返回後將恢復調用之前的信號掩碼.
* 該系統調用始終返回 -1, 並將 errno 設置為 EINTR.
* 該系統調用實際是阻塞並暫停兩個動作的原子操作.
=============================================================保護關鍵代碼段示例
============================================================= #include
#include
#include
#include
#include
#include
static void sig_int (int);
void err_sys (const char* info)
{
perror (info);
exit (1);
}
void pr_mask (const char* str)
{
sigset_t sigset;
int errno_save;
errno_save = errno; /* this function may be called by signal handler */
if (sigprocmask (0, NULL, &sigset) < 0)
err_sys ("sigprocmask error");
printf ("%s", str);
if (sigismember (&sigset, SIGINT)) printf ("SIGINT ");
if (sigismember (&sigset, SIGQUIT)) printf ("SIGQUIT ");
if (sigismember (&sigset, SIGUSR1)) printf ("SIGUSR1 ");
if (sigismember (&sigset, SIGALRM)) printf ("SIGALRM ");
printf ("\n");
errno = errno_save;
}
int main (void)
{
sigset_t newmask, oldmask, zeromask;
if (signal (SIGINT, sig_int) == SIG_ERR)
err_sys ("signal (SIGINT) error");
sigemptyset (&zeromask);
sigemptyset (&newmask);
sigaddset (&newmask, SIGINT);
/* block SIGINT and save current signal mask */
if (sigprocmask (SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys ("SIG_BLOCK error");
/* critical region of code */
pr_mask ("in critical region: ");
/* allow all signals and pause */
if (sigsuspend (&zeromask) != -1)
err_sys ("sigsuspend error");
pr_mask ("after return from sigsuspend: ");
/* reset signal mask whick unblocks SIGINT */
if (sigprocmask (SIG_SETMASK, &oldmask, NULL) < 0)
err_sys ("SIG_SETMASK error");
/* and continue processing ... */
exit (0);
}
static void sig_int (int signo)
{
pr_mask ("\nin sig_int: ");
return;
}
-------------------------------------------------------------------------------
* 在 Linux 下, 必須包含頭文件:
#include
以便使用可靠的 signal 函數. 或者使用 sigaction 函數.
=============================================================7.3.4 sigsetjmp 和 siglongjmp
sigsetjmp 和 siglongjmp 專用於從信號處理函數中進行遠跳轉
並能夠明確指定是否保存信號掩碼
============================================================= #include
int sigsetjmp (sigjmp_buf env, int savesigs);
void siglongjmp (sigjmp_buf env, int val);
-------------------------------------------------------------------------------
* 如果 savesigs 非零, 則 siglongjmp 在跳轉之後將恢復保存的信號掩碼.
=============================================================
沒有留言:
張貼留言