LINUX 下異常信號收藏

我們介紹一些標準信號的名稱以及它們代表的事件。每一個信號名稱是一個代表正整數的宏,但是你不要試圖去推測宏代表的具體數值,而是直接使用名稱。這是因爲這個數值會隨不同的系統或同樣系統的不同版本而不同,但是名稱還算是標準化和統一的。
   這些名稱定義在signal.h中。
   int NSIG是一個定義的宏,它描述了定義的信號的數量。由於信號的數值是從0開始連續分配的,所以,NSIG比系統中所定義的最大的信號數值大1。

11.2.1 程序出錯信號
   下面介紹的信號是有程序的錯誤造成的。這些嚴重的錯誤會被計算機或操作系統檢測出來。一般情況下,產生了這種信號表明你的程序遭到嚴重的破壞,沒有辦法繼續完成產生錯誤的計算。
   很多程序要控制這些信號是要在程序退出前進行一些清理工作。比如,關閉臨時文件,清理緩衝區等。程序可以註冊一個函數句柄來完成這些工作,然後在讓系統執 行缺省的操作來結束進程的執行。終止可能是產生這類錯誤的程序的最後的操作,但也有例外,比如一些在解釋環境中執行的程序,產生錯誤時需要返回解釋環境本 身。
   這類信號的缺省動作就是終止程序的執行。如果你定義了自己的處理,而沒有最後調用終止進程,或者阻塞或忽略了該信號,那麼你的程序可能會造成極其嚴重的後果。除非這個信號本身並不是出錯產生的,而是通過調用kill函數或raise函數直接通過系統發送的。
   當這些信號結束進程時,系統會產生一個內核轉儲文件,用來記錄發生錯誤退出前程序的狀態。內核轉儲文件的文件名是core,它會被寫到當前進程的當前目錄 中。在Linux系統中,你也可以通過環境變量COREFILE來設定產生內核轉儲文件的文件名。產生內核轉儲文件的目的是幫助你事後利用調試器查明產生 錯誤的原因。
   下面逐一介紹這類信號的名稱:
   int SIGFPE
   這個信號表明產生了一個致命的算術運算錯誤。儘管該信號的名稱來源於“浮點異常(floating-point exception)”,但是,它實際上包含了所有的算術指令錯誤,包括除數是0和溢出等。
   int SIGILL
   這個信號的名稱來源於“非法的指令(illegal instrution)”,它往往意味着你的程序要執行根本無法譯碼的指令或你無權執行的特權指令。既然C語言只能編譯產生有效的合法的指令,所以 SIGILL信號很多情況下表明可執行文件破壞了,或者正在把數據當作代碼來執行。後一種情況往往是由於把一個指針錯當成函數指針傳遞,或者數組越界破壞 了堆棧段的數據,使其中的函數返回地址錯誤等。SIGILL也可以由堆棧溢出,或者系統無法執行傳遞給系統的信號響應函數的句柄引起。
   int SIGSEGV
   當程序試圖讀或寫系統分配給它的內存以外的存儲器,或者寫只有讀權限的存儲器時會發生這個信號。實際上,由於操作系統檢測機制的限制,對程序的檢測並不是 那麼及時,往往只有當超出範圍很遠時系統纔會檢測出來。信號的名稱來源於“段變異(segmentation violation)”。這個信號的發生往往是由於引用沒有初始化或空的指針,或者用指針引用數組時由於疏於檢查而越界。
   int SIGBUS
   這個信號由於引用無效的指針產生。和SIGSEGV相似,典型情況下,它也是由於沒有正確初始化指針引起的。它們的區別是,SIGSEGV是用無效的指針 引用了有效的內存地址,而SIGBUS是引用了無效的內存地址。SIGBUS通常的產生是因爲沒有正確初始化指針變量,比如,指針指向8字節對齊的變量而 引用的地址是奇數。該信號的名稱是“總線錯誤(bus error)”的縮寫。
   int SIGABRT
   這個信號是程序調用函數abort()產生的。關於函數abort()的用法,參見前面的有關章節。
   int SIGIOT
   在Linux系統中,它是SIGABRT的另一個名稱。
   int SIGTRAP
   該信號是由計算機的斷點指令產生的。調試程序使用該信號。當程序執行到設置斷點的指令,引起發送該信號,同時調試程序捕獲該信號,獲得控制權,進行程序的調試。因此,你的程序是無法看到該信號的。
   int SIGEMT
   模擬自陷信號。它是由系統未能實現,必須由軟件模擬的指令引起的。截獲該信號,並在軟件中模擬引起信號的指令的執行。
   int SIGSYS
   錯誤的系統調用。就是說,程序進行了系統調用,但是傳遞給系統的調用號是錯誤的,系統無法完成調用。


11.2.2 程序終止信號
   這些信號都是用來告訴程序通過某種方式結束。它們之所以有各種不同的名稱,是因爲它們使用的目的稍有不同,或者程序希望用稍微不同的方式處理它們。雖然這 些信號對程序的後果都是相同的,都是結束程序的執行,但還是有理由處理這些信號。通常是因爲程序希望在結束之前能夠清理一下,比如,能夠紀錄下某中狀態, 等等。
   缺省的處理(目前)是結束進程的執行。
   int SIGTERM
   該信號是一個最普通的讓程序結束的信號。進程可以阻塞、控制和忽略該信號,它是禮貌的要求一個程序結束的普通的方法,比如,通過shell命令kill在缺省情況下就發送該信號結束進程。
   int SIGINT
   該名稱是program interrupt的縮寫,當用戶從控制檯輸入終止字符(通常是Ctrl-c)時發送給進程的信號。
   int SIGQUIT
   該信號和SIGINT相似,區別是它通過用戶輸入退出字符(通常是Ctrl-/)來產生,進程處理退出外,還要產生內核轉儲,就象接收到了錯誤信號一樣。 對於這個信號,你可以認爲是用戶發現了程序錯誤而通知程序的一種方法。在處理該信號時,某些退出清理最好不要做,這樣能夠讓用戶可以通過轉儲的內核來察看 當時的狀態。
   int SIGKILL
   SIGKILL信號用來讓進程立即終止,它不能被控制和忽略,總是致命的,也不能阻塞。該信號通常只能通過特定的命令直接產生,既然它是不可忽略的,你應 該把它作爲最後的手段使用,而首先使用不太激烈的手段,如Ctrl-c或者SIGTERM等方法。如果一個進程對其它結束信號沒有響應,則採用 SIGKILL信號,總是能讓程序結束。事實上,如果SIGKILL信號也不起作用的話,你就應該報告一個內核錯誤。當一個進程由於某中原因不能在進行下 去的時候,系統也能夠發送該消息結束進程的執行。
   int SIGHUP
   SIGHUP信號(hang up)報告用戶的終端已經從系統中斷開,或者用來作爲作業控制的手段。


11.2.3 鬧鐘信號
   這類信號用來表明定時器激活,信號的缺省行爲是讓進程結束。雖然這種缺省行爲通常是沒有什麼用處的,但是沒有其它的缺省行爲可用。因此,往往需要程序用自己的函數控制該類信號的行爲。
   int SIGALRM
   該信號被使用實際時間或時鐘數的定時器使用,比如,alarm()函數。
   int SIGVTALRM
   該函數被使用當前進程使用的CPU時間的函數使用。
   int SIGPROF
   該信號用來表明當前進程使用的CPU時間和爲當前進程服務的系統消耗的CPU時間的綜合,一般用來生成代碼的簡略概括。


11.2.4 異步I/O信號
   這類信號和異步I/O操作有關,你必須通過直接調用fcntl()函數才能使某些文件描述符產生該信號。該信號的缺省動作是忽略該信號的作用。
   int SIGIO
   SIGIO信號是當某個打開的文件描述符已經準備好輸入輸出時纔會發送該信號。在許多系統上,只有終端和套接口才可能發送這個信號,而普通的文件不會發送這個信號。在GNU系統上,任何文件,只要你說明它是異步打開,就可能發送這個信號。
   int SIGURG
   這個信號只用來表示套接口接受到緊急或者帶外數據時使用,參看後面的網絡編程的部分。
   int SIGPOLL
   系統v的信號,和SIGIO相似,只是爲了兼容的目的才設立。


11.2.5 作業控制信號
   這一組信號用來支持作業控制,一般情況下,你可以不用管這些信號,採用系統缺省的行爲就可以了,除非你確切知道該怎樣控制作業系統的工作。
   int SIGCHLD
   當一個子進程結束時,就會向父進程發送該信號。該信號的缺省行爲是忽略,當進程建立起一個處理該信號的函數句柄,並且這是已經有zombie進程存在,那麼是否產生該信號由系統決定。
   int SIGCLD
   信號SIGCHLD的舊名稱。
   int SIGCONT
   這個信號的作用是當進程被停止後使進程繼續執行,而不做任何其他的工作。你不能阻塞該信號,但是你可以爲該信號設置一個處理函數句柄,它總是使進程無條件 的執行下去。大多數程序沒有理由控制該信號,它們只是簡單的繼續被中斷的操作。你可以利用該處理函數的句柄完成一些你需要的特殊工作,比如,重新打印一些 提示信息,如果程序是因爲等待輸入而被掛起的話。
   int SIGSTOP
   該信號停止一個進程,它不能被控制、忽略和阻塞。
   int SIGTSTP
   這是一個交互式的停止信號。不象SIGSTOP,它可以被控制或忽略。當你從控制檯輸入SUSP字符(Ctrl-z)時,就會產生該信號。
   int SIGTTIN
   當一個進程在後臺執行時,它不能從用戶的終端中讀入任何輸入。當一個後臺進程試圖從用戶終端讀時,所有進程都會接受到一個SIGTTIN信號。該信號的缺省操作是停止進程,從而讓需要輸入的後臺進程能夠到前臺讀入需要的輸入信息。
   int SIGTTOU
   它和SIGTTIN相似,只是發生在後臺進程寫終端時。
 
   當一個進程停止時,任何信號都不會再傳遞給它,除了SIGKILL和SIGCONT信號(顯然),所有給它的信號標記爲未定的(pending),並且只 有當進程重新進入執行狀態時纔得到最終傳遞。SIGKILL信號總是迫使進程結束,而且不能阻塞、忽略和控制。你可以忽略SIGCONT信號,但是它總是 能夠使被停止的進程繼續執行。一個SIGCONT信號可以讓所有未定的停止信號被丟棄,類似的,一個停止信號能讓未定的SIGCONT信號丟棄。


11.2.6 操作錯誤信號
   這組信號都是由進程的操作錯誤引起的,他們不必是程序的錯誤,而是任何阻止操作完成的錯誤。這些信號的缺省操作是中止進程的執行。
   int SIGPIPE
   如果你使用管道或者FIFO進行進程間的通訊,你必須讓你的應用程序在寫入一個管道之前先有一個程序已經打開了該管道並且已經開始讀取數據。如果這時沒有 開始,或者讀管道的進程意外退出了,那麼寫操作就會產生一個SIGPIPE信號。如果SIGPIPE信號被阻塞、控制或忽略,那麼寫操作將返回錯誤,錯誤 代碼是EPIPE。更進一步的信息參見後面的相關章節。
   int SIGLOST
   該信號表明資源的丟失,在GNU系統中,通常任何提供服務的服務器意外死機,都能引起該信號。一般忽略該信號並無不妥,因爲和這種操作相關的錯誤都能使相關函數返回錯誤。
   int SIGXCPU
   CPU時間限制到。該信號表明對進程使用的CPU時間的限制已經達到。
   int SIGXFSZ
   該信號表明進程試圖增長文件超過系統對文件長度的限制。


11.2.7 外圍信號
   這組信號用於各種各樣的目的,一般不會影響進程的執行。
   int SIGUSR1
   int SIGUSR2
   這兩個信號可以用來完成你希望的任何目的,通常用來進行網絡通訊。如果你在一個進程裏有用來接受該信號的程序,你的另外的進程就可以發送信號給相應的進程。這個信號的缺省操作是終止進程的執行。
   int SIGWINCH
   系統終端的每屏行數和列數發生改變時發送該信號。它的缺省操作是忽略。如果是一個全屏幕輸出的程序則需要控制該信號,根據新的每屏行和列數重新初始化輸出。
   int SIGINFO
   該信號可以由控制檯通過鍵盤發送給所有前臺進程組的進程。如果接收信號的進程是領頭進程,那麼它一般會打印一些系統信息和進程的一些當前信息,如果是其他進程,那麼缺省情況下不會做任何事情。


11.2.7 信號消息
   我們上面提到的標準信號都可以用一個系統提供的字符串描述。我們用函數strsignal()和psignal()來獲取相關的字符串。
   char * strsignal(int signum)
   該函數返回一個已經分配好的靜態字符串,用來描述signum信號相關的文字信息。你無權修改這個返回的字符串,並且,既然在另外的調用中能夠重寫該字符 串,如果你需要在後面的程序中使用,必須自己保存該字符串的備份。該函數是GNU系統的擴充,它的原型包含在string.h頭文件中。
   void psignal(int signum, const char *message)
   該函數輸出一個描述signum信號的消息到標準錯誤輸出。如果傳遞該函數的message是一個NULL指針或空串,這個函數只打印和信號相關的標準的 消息。如果你傳遞給函數非空的message參數,那麼系統會先輸出message字符串,然後輸出相關消息。該函數在signal.h文件中聲明。

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