sigprocmask

有2個函數 sigprocmask和sigsuspend

sigprocmask系統調用用於改變當前阻塞信號集,比如進程想阻塞SIGMIN+1信號。就把這個信號加入掩碼中,然後調用 sigprocmask具體參數見man手冊。

而sigsuspend是掛起進程,等待信號。等收到信號後,繼續執行進程。見如下程序:

sigemptyset(&zeromask); sigemptyset(&newmask);  
sigaddset(&newmask, SIGMIN+1); 
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {  //阻塞SIGMIN+1
fprintf(stderr, "call sigprocmask() error/n");
goto error;

if(sigsuspend(&zeromask) != -1) {  //等待信號到來(zeromask表示可以等待任何信號
fprintf(stderr, "sigsuspend() error/n");
goto error;   

有4個問題,1。如果前面SIGMIN+1被阻塞了,那後面則表示進程一直收不到,被suspend懸掛麼?2。這樣寫如何就有防止信號丟失的作用 呢?3。假設在sigsuspend運行之前收到SIGMIN+1,那麼sigsuspend會從sigqueue裏面取出來處理還是等待新的 SIGMIN+1到來?4。sigsuspend是否應該只放行SIGMIN+1而不是用空信號集?

1。其實sigsuspend是一個原子操作,包含4個步驟:

(1) 設置新的mask阻塞當前進程;
(2) 收到信號,恢復原先mask;
(3) 調用該進程設置的信號處理函數;
(4) 待信號處理函數返回後,sigsuspend返回。

所以第一步之後,進程是可以接受任何信號的。接收到SIGMIN+1,恢復之前阻塞信號集,並處理SIGMIN+1信號。

2。爲什麼有防止信號丟失的作用呢?

這個功能是sigsuspend 4步原子操作決定的。如果不用sigsuspend(&zeromask)而改用

sigprocmask(SIG_BLOCK,&emptyset,NULL); pause();
這2個函數不是原子操作,在2 個函數之間信號到來了,繼續pause,由於就沒有信號到來,則進程還會停在那裏等待新的SIGMIN+1到來。所以用sigsuspend來取代這2個 函數功能,就能保證在sigsuspend函數運行時收到的信號不會丟失,會被處理的。

3.第三個問題,按道理是從sigqueue裏面取,而不會重新等待新的SIGMIN+1信號的到來。不過我沒有從官方文檔找到這種說 法,sigsuspending是獲得當前已傳送到進程,卻被阻塞的所有信號,在set指向的信號集中保存未決(阻塞)的信號。認定 sigsuspending和sigsuspend有相似之處。再加上從不能丟失信號,答案偏向於前者。

4。這個我也想知道,道理嘛,就是爲了預防對其他信號也返回,並繼續執行進程。但是假設其他信號沒有處理函數也就是原子操作第三步沒完 成,sigsuspend不會繼續執行,這種做法就沒有意義了。所以還需要繼續看看source code.

這幾天的研究表明,在sigsuspend之所以置爲zeromask是爲了對之前阻塞的信號進行處理。不過對於apache module裏面的信號,可以以舊採取blocked mask+(SIGMIN+1).目的是不想影響apache對自己設定阻塞信號的處理。在進入module之前阻塞的,從module出來後依然保持阻 塞就是了。

 

------------------------------------------分割線--------------------------------------------------

對於sigprocmask這個函數,剛開始看也是不太瞭解這個函數究竟能做什麼,對於第一個參數有什麼作用。在網上找了不少的介紹,先來看看原 型: int sigprocmask(int how,const sigset_t *set,sigset_t *oldset); sigset_t是封裝的一種數據類型,實際上是一個unsigned long int __val[_SIGSET_NWORDS];在/usr/include/bits/sigset.h裏面定義,用來包含所有的信號集的。 每個進程都有一個用來描述哪些信號遞送到進程時將被阻塞的信號集,該信號集中的所有信號在遞送到進程後都將被阻塞。 sigprocmask是最爲關鍵的一個函數。在使用之前要先設置好信號集合set。這個函數的作用是將指定的信號集合set加入到進程的信號阻塞集合之 中去,如果提供了oldset那麼當前的進程信號阻塞集合將會保存在oldset裏面。參數how決定函數的操作方式。

SIG_BLOCK:增加一個信號集合到當前進程的阻塞集合之中。 每個進程有一個默認的信號阻塞集合,如果像下面: sigemptyset(set);/*定義信號集set*/ sigaddset(set,SIGINT);/*把信號SIGINT添加到信號集中*/ sigprocmask(SIG_BLOCK,set,NULL);/*把set設置爲信號阻塞集 則是把SIGINT加入到阻塞信號集合中。

SIG_UNBLOCK:從當前的阻塞集合之中刪除一個信號集合。

SIG_SETMASK:將當前的信號集合設置爲信號阻塞集合。

sigeprocmask函數通常和sigemptyset、sigfillset、sigaddset、sigdelset、 sigismember函數配合使用,主要有兩種用途: 1.我們不希望某些不太重要的信號來影響我們的進程,我們就可以把這些信號添加到信號屏蔽集中。使它們不打擾進程的執行。 2.如果系統現在很忙,沒有時間及時相應信號,進程可以先把信號阻塞掉,等系統有空閒時間在去相應,這也保證了信號的可靠性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章