信號狀態:
信號的”未決“是一種狀態,指的是從信號的產生到信號被處理前的這一段時間;信號的”阻塞“是一個開關動作,指的是阻止信號被處理,但不是阻止信號產生。
APUE例題在sleep前用sigprocmask阻塞了退出信號,然後sleep,然後在sleep的過程中產生一個退出信號,但是此時退出信號被阻塞過,(中文的”阻塞”在這裡容易被誤解為一種狀態,實際上是一種類似於開關的動作,所以說“被阻塞過”,而不是“被阻塞”)所以處於“未決”狀態,在 sleep後又用sigprocmask關掉退出信號的阻塞開關,因為之前產生的退出信號一直處於未決狀態,當關上阻塞開關後,馬上退出“未決”狀態,得到處理,這一切發生在sigprocmask返回之前。
總結:信號被阻塞並不是被丟棄,只是沒有被處理。這種狀態叫未決狀態。
解除阻塞後,處於“未決狀態”的信號會繼續被處理。
解除阻塞要調用sigprocmask,但在sigprocmask返回之前,解決阻塞動作就已經完畢。
所在在解除阻塞的函數sigprocmask返回之前,就要進行未決信號的處理了。
int sigpend(sigset_t *set);---獲取未決的信號.
int sigprocmask(int how,const sigset_t *set,sigset_t *oset);
----根據how的值來決是完成的動作,阻塞、解除阻塞等.
注意:未決信號中不可能有相同的。如果信號產生
了一次且未決,又產生一次時會被丟棄。
當然如果是實時信號,就另當別論了。因為實時信號可以多個相同的未決信號的。
信號生命周期:
對於一個完整的信號生命周期(從信號發送到相應的處理函數執行完畢)來說,可以分為三個重要的階段,這三個階段由四個重要事件來刻畫:1.信號誕生;2. 信號在進程中注冊完畢;3.信號在進程中的注銷完畢;4.信號處理函數執行完畢。相鄰兩個事件的時間間隔構成信號生命周期的一個階段。
下面闡述四個事件的實際意義:
1.信號"誕生"。信號的誕生指的是觸發信號的事件發生(如檢測到硬件異常、定時器超時以及調用信號發送函數kill()或sigqueue()等)。
2.信號在目標進程中"注冊";
進程的task_struct結構中有關於本進程中未決信號的數據成員:
struct sigpending pending;
struct sigpending
{
struct sigqueue *head, **tail;
sigset_t signal;
};
第一、第二個成員分別指向一個sigqueue類型的結構鏈(稱之為"未決信號信息鏈")的首尾,第三個成員是進程中所有未決信號集,信息鏈中的每個sigqueue結構體刻畫一個特定信號所攜帶的信息,並指向下一個sigqueue結構:
struct sigqueue
{
struct sigqueue *next;
siginfo_t info;
};
信號在進程中注冊指的就是信號值加入到進程的未決信號集中(sigpending結構的第二個成員sigset_t signal),並且信號所攜帶的信息被保留到未決信號信息鏈的某個sigqueue結構中。只要信號在進程的未決信號集中,表明進程已經知道這些信號的存在,但還沒來得及處理,或者該信號被進程阻塞。
注:
當一個實時信號發送給一個進程時,不管該信號是否已經在進程中注冊,都會被再注冊一次,因此,信號不會丟失,因此,實時信號又叫做"可靠信號"。這意味著同一個實時信號可以在同一個進程的未決信號信息鏈中占有多個sigqueue結構(進程每收到一個實時信號,都會為它分配一個結構來登記該信號信息,並把該結構添加在未決信號鏈尾,即所有誕生的實時信號都會在目標進程中注冊);
當一個非實時信號發送給一個進程時,如果該信號已經在進程中注冊,則該信號將被丟棄,造成信號丟失。因此,非實時信號又叫做"不可靠信號"。這意味著同一個非實時信號在進程的未決信號信息鏈中,至多占有一個sigqueue結構(一個非實時信號誕生後,(1)、如果發現相同的信號已經在目標結構中注冊,則不再注冊,對於進程來說,相當於不知道本次信號發生,信號丟失;(2)、如果進程的未決信號中沒有相同信號,則在進程中注冊自己)。
3.信號在進程中的注銷。在目標進程執行過程中,會檢測是否有信號等待處理(每次從系統空間返回到用戶空間時都做這樣的檢查)。如果存在未決信號等待處理且該信號沒有被進程阻塞,則在運行相應的信號處理函數前,進程會把信號在未決信號鏈中占有的結構卸掉。是否將信號從進程未決信號集中刪除對於實時與非實時信號是不同的。對於非實時信號來說,由於在未決信號信息鏈中最多只占用一個sigqueue結構,因此該結構被釋放後,應該把信號在進程未決信號集中刪除(信號注銷完畢);而對於實時信號來說,可能在未決信號信息鏈中占用多個sigqueue結構,因此應該針對占用gqueue結構的數目區別對待:如果只占用一個sigqueue結構(進程只收到該信號一次),則應該把信號在進程的未決信號集中刪除(信號注銷完畢)。否則,不在進程的未決信號集中刪除該信號(信號注銷完畢)。進程在執行信號相應處理函數之前,首先要把信號在進程中注銷。
4.信號生命終止。進程注銷信號後,立即執行相應的信號處理函數,執行完畢後,信號的本次發送對進程的影響徹底結束。
注:
1)信號注冊與否,與發送信號的函數(如kill()或sigqueue()等)以及信號安裝函數(signal()及sigaction())無關,只與信號值有關(信號值小於SIGRTMIN的信號最多只注冊一次,信號值在SIGRTMIN及SIGRTMAX之間的信號,只要被進程接收到就被注冊)。
2)在信號被注銷到相應的信號處理函數執行完畢這段時間內,如果進程又收到同一信號多次,則對實時信號來說,每一次都會在進程中注冊;而對於非實時信號來說,無論收到多少次信號,都會視為只收到一個信號,只在進程中注冊一次。