2011年12月7日 星期三

Linux Signal 4

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 在跳轉之後將恢復保存的信號掩碼.
=============================================================

沒有留言: