信號可以理解成一種軟體中斷。他提供了一種非同步處理事件的方式。每個信號都有一個與之對應的信號名,這些信號名都帶有SIG首碼,如:SIGABRT,SIGALARM。頭文件signal.h 中定義了所有的信號名,他們值為正整數常量。事實上,實現將個別信號定義在不同的頭文件中,只不過這些頭文件又被包含在了s ...
信號可以理解成一種軟體中斷。他提供了一種非同步處理事件的方式。每個信號都有一個與之對應的信號名,這些信號名都帶有SIG首碼,如:SIGABRT,SIGALARM。頭文件signal.h 中定義了所有的信號名,他們值為正整數常量。事實上,實現將個別信號定義在不同的頭文件中,只不過這些頭文件又被包含在了signal.h中;這是因為內核不可能去包含應用於用戶級別程式的頭文件!因此,當用戶程式與內核同時需要某信息的定義時,通常的做法是把這個定義放到內核頭文件中,然後在用戶頭文件中包含這個內核頭文件。
unix系統信號列表:
當信號列表中的預設action為“terminal+core”時,他意味著進程的記憶體映像會留在進程目錄下的core文件中。core文件可以幫助大多數UNIX系統調試者來檢查進程終止時的狀態。但是,如果 a)進程設置了set-user-ID而且當前用戶不是進程文件的擁有者;或者 b)進程設置了 set-group-ID 而且當前用戶不是進程文件的用戶組擁有者;或者 c) 當前用戶下該用戶沒有寫入權;或者d) 此文件已存在而且當前用戶沒有寫入權;或者e)文件太大時core文件不會被創建。
程式啟動
當一個程式被執行的時候,所有的信號的裝填要麼是預設方式處理要麼是忽略信號。通常,信號被設置為它們的預設處理方法,除非調用exec的進程忽略了這個信號。詳細來說exec函數會將調用exec進程捕獲的信號的狀態更改為信號的預設處理方式而保留其他信號的處理方式,因為exec執行的新程式中不包含捕獲信號的函數地址,所以這些處理方式在新程式中是無意義的。
進程創建
當一個進程調用fork時,子進程繼承父進程的信號處理方式。在這裡,子進程是由父進程的記憶體鏡像的副本開始的,因此信號捕獲函數的地址是有意義的。
可重入函數
當一個信號一個進程的信號處理函數捕獲,此進程的正常指令執行順序會被此信號處理短暫的中斷,處理完信號後進程從之前被中斷的地方繼續執行。但是在信號處理函數中,我們是無法識別出當信號被捕獲是進程執行到了哪一步。如果當收到信號時進程正在通過malloc從堆上分配一塊額外的記憶體時,我們應該怎麼辦呢,在信號處理函數中調用malloc嗎?亦或是當收到某個信號時我們正在調用某個函數,比如getpwnam,這個函數將他的返回值存儲在一個靜態區域,這種情況下我們應該在信號處理函數中調用同樣的函數嗎?在上面malloc的情景中那樣做會對進程產生災難性的後果,因為malloc通常包含一個它所有分配過的區域的鏈接表,也許當時它正處於更新這個鏈接表的狀態中。在getpwnam的情境下,存儲在靜態區的getpwnam的返回值會被信號處理函數中的調用結果重寫!
因此, The Single UNIX Specification 要求信號處理函數中的函數調用必須是安全的,即可重入的(Reentrant functions)。這些函數被 The Single Unix Specification稱為非同步信號安全函數(async-signal safe)。除了可重入,他們會在函數運行期間阻塞任何會破壞連續性的信號的下達。非同步信號安全函數列表如下:
一些函數不被稱為非同步信號安全的原因大致如下:
- 使用了靜態數據結構
- 調用了malloc或free
- 屬於標準I/O庫的一部分
大多數標準I/O庫的實現使用了靜態數據結構,他們都不是可重入函數。需要特別註意的一點是:即使我們在信號處理函數中使用非同步信號安全的函數,每個線程下也僅僅只有一個errno變數(在多線程環境下,多個線程共用進程地址空間。每個線程需要它自己的errno副本以阻止線程間的相互干擾),而我們可能會潛在的修改掉errno的值。因此,有個通則:在信號處理函數中調用非同步信號安全函數前,應當保存errno。