APUE 3,APUE
訊號可以理解成一種軟體中斷。他提供了一種非同步處理事件的方式。每個訊號都有一個與之對應的訊號名,這些訊號名都帶有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)。除了可重新進入,他們會在函數運行期間阻塞任何會破壞連續性的訊號的下達。非同步訊號安全函數列表如下:
一些函數不被稱為非同步訊號安全的原因大致如下:
大多數標準I/O庫的實現使用了待用資料結構,他們都不是可重新進入函數。需要特別注意的一點是:即使我們在訊號處理函數中使用非同步訊號安全的函數,每個線程下也僅僅只有一個errno變數(在多線程環境下,多個線程共用進程地址空間。每個線程需要它自己的errno副本以阻止線程間的相互幹擾),而我們可能會潛在的修改掉errno的值。因此,有個通則:在訊號處理函數中調用非同步訊號安全函數前,應當儲存errno。