Linux的信號處理

轉自:http://blog.csdn.net/guosha/archive/2008/09/17/2943615.aspx

 

Linux爲實現信號處理提供了比較多的接口,看似紛雜,但理清信號的關係後還是很有條理的。主要分爲以下四組,怎麼發送一個信號,收到一個信號後做什麼樣的處理,主動等待一個信號的發生,對特定信號只記錄是否發生供以後再處理;四組的API如下(不考慮多線程):
發送信號 kill, alarm, arise;
安裝信號 signal, sigaction;
等待信號 sigsuspend, sigwait,pause;
阻塞信號 sigfillset, sigemptyset, sigaddset, sigdelset, sigismember, sigprocmask;

 

發送信號, kill, alarm, arise
這是唯一一組由信號發送方調用的API,其中alarm, arise都是給自己進程產生信號,而kill是可以從一個進程發送一個信號到另一個進程,因爲信號的接收方一般都不做權限檢查,所以發送方要有權限給的接收方發送信號信號才能被髮送,要不然我就可以寫個非法程序,直接使用kill給進程1發送一個SIGKILL信號的話,你的系統基本也就OVER了。這個權限檢查的指導原則按我的理解是,發送方的有效用戶是否有權限給接收方的實際用戶發送信號來決定。因爲,當你運行一個seteuid程序,這個程序運行時的euid可能不再是ruid了,但是你仍然可以kill它。arise()的實現我猜就是用kill(getpid(), signo)來實現。另外系統內核檢測到一些異常或是狀態改變時也會給進程發送信號,如SIGINTR,SIGCHILD等等。

 

安裝信號, signal, sigaction
這組API是決定收到一個信號號的處理方法。如果不顯示的安裝一個信號的處理方法,系統都有對應的默認處理方法,大多數都是直接終止程序本身. 在richard stevens的APUE中說signal的信號處理需要重新安裝信號處理方法,但我在FC5下測試,不重新安裝也是可以的,並且正在進行信號處理時,發送一個信號過去,該信號也不會丟失,只是暫時阻塞,等前面的信號處理完後再處理。當然當正在信號處理時發送多個信號過去,信號處理完後,可能傳遞一個信號過去,其它的信號會丟失。至於直接使用signal安裝信號,等信號處理完後是否會重啓被該信號中斷的慢速系統調用,我沒有測試,不得而知。 當然你可以使用sigaction來安裝信號,並顯示的指明restart標誌,這樣被該信號中斷的系統調用就會自動重啓。sigaction這個API更復雜,功能也更多靈活,可以隨意定製,通過siginfo_t的結構,可以得到很多信號相關的信息。我猜現在的linux的signal都是用sigaction封裝來實現的。跟sigaction相比,signal簡單多了,沒理由不用它,當然,你得保證signal的語義不會對你的程序造成衝突。

 

等待信號 pause, sigsuspend, sigwait
這組API都是等待信號的發生,可以根據程序的實際需求來選取。pause只要接收到信號就會返回,sigsuspend跟sigwait都是隻等待某些特定的信號發生,但sigsuspend是把參數裏的信號集給阻塞,而sigwait一般是先調用sigprocmask把所有的信號都阻塞,然後再等待sigwait參數裏指定的信號。通常sigwait用在多線程程序裏,主線程把所有信號都mask掉,然後不同的線程用sigwait來等待自己感興趣的信號。

 

阻塞信號 sigfillset, sigemptyset, sigaddset, sigdelset, sigismember, sigprocmask
這一組API最多也最簡單,前面五個API都是對信號集的操作,用它用得到一個你想要的信號集後就可以調用sigprocmaks的設置程序的信號掩碼了。

 

另外, siglongjmp, sigsetjmp是安全的在信號處理程序裏跑轉的兩個接口。

 

最後一些跟信號處理程序裏的一些注意事項
1、因爲信號會中斷慢速的系統調用,所以當系統調用失敗時,一定要檢查失敗原因,當被信號中斷時做出重啓系統調用的動作;
2、因爲信號處理有異步性,所以任何在信號處理程序裏調用了不具可重入性的函數都要小心了。這裏的不具可重入性的函數據括了系統調用跟自己定義的函數。
3、在信號處理程序裏任何可能導致對全局變理的修改也要小心了,一個經常被人忽視的就是在信號處理程序裏調用了一個系統調用後可能導致errno的修改。

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