1. 程式人生 > >Linux訊號機制分析和訊號處理函式

Linux訊號機制分析和訊號處理函式

【摘要】本文分析了Linux核心對於訊號的實現機制和應用層的相關處理。首先介紹了軟中斷訊號的本質及訊號的兩種不同分類方法尤其是不可靠訊號的原理。接著分析了核心對於訊號的處理流程包括訊號的觸發/註冊/執行及登出等。最後介紹了應用層的相關處理,主要包括訊號處理函式的安裝、訊號的傳送、遮蔽阻塞等,最後給了幾個簡單的應用例項。

1.訊號本質

軟中斷訊號(signal,又簡稱為訊號)用來通知程序發生了非同步事件。在軟體層次上是對中斷機制的一種模擬,在原理上,一個程序收到一個訊號與處理器收到一箇中斷請求可以說是一樣的。訊號是程序間通訊機制中唯一的非同步通訊機制一個程序不必通過任何操作來等待訊號的到達,事實上,程序也不知道訊號到底什麼時候到達。程序之間可以互相通過系統呼叫kill傳送軟中斷訊號。核心也可以因為內部事件而給程序傳送訊號,通知程序發生了某個事件。訊號機制除了基本通知功能外,

還可以傳遞附加資訊。

收到訊號的程序對各種訊號有不同的處理方法。處理方法可以分為三類:

第一種是類似中斷的處理程式,對於需要處理的訊號,程序可以指定處理函數,由該函式來處理。

第二種方法是,忽略某個訊號,對該訊號不做任何處理,就象未發生過一樣。

第三種方法是,對該訊號的處理保留系統的預設值,這種預設操作,對大部分的訊號的預設操作是使得程序終止。程序通過系統呼叫signal來指定程序對某個訊號的處理行為。

2.訊號的來源

訊號的來源可以有很多種試,按照產生條件的不同可以分為硬體和軟體兩種。

1、  硬體方式

當用戶在終端上按下某鍵時,將產生訊號。如按下組合鍵後將產生一個SIGINT訊號。

硬體異常產生訊號:除資料、無效的儲存訪問等。這些事件通常由硬體(如:CPU)檢測到,並將其通知給Linux作業系統核心,然後核心生成相應的訊號,並把訊號傳送給該事件發生時正在進行的程式。

2、  軟體方式

使用者在終端下呼叫kill命令向程序傳送任務訊號。

程序呼叫kill或sigqueue函式傳送訊號。

當檢測到某種軟體條件已經具備時發出訊號,如由alarm或settimer設定的定時器超時時將生成SIGALRM訊號。

3.訊號的種類,以及處理流程

可以從兩個不同的分類角度對訊號進行分類:

可靠性方面:可靠訊號與不可靠訊號;

與時間的關係上:實時訊號與非實時訊號。

3.1可靠訊號與不可靠訊號

Linux訊號機制基本上是從Unix系統中繼承過來的。早期Unix系統中的訊號機制比較簡單和原始,訊號值小於SIGRTMIN的訊號都是不可靠訊號。這就是"不可靠訊號"的來源。它的主要問題是訊號可能丟失。

隨著時間的發展,實踐證明了有必要對訊號的原始機制加以改進和擴充。由於原來定義的訊號已有許多應用,不好再做改動,最終只好又新增加了一些訊號,並在一開始就把它們定義為可靠訊號,這些訊號支援排隊,不會丟失

訊號值位於SIGRTMIN和SIGRTMAX之間的訊號都是可靠訊號,可靠訊號克服了訊號可能丟失的問題。Linux在支援新版本的訊號安裝函式sigation()以及訊號傳送函式sigqueue()的同時,仍然支援早期的signal()訊號安裝函式,支援訊號傳送函式kill()。

訊號的可靠與不可靠只與訊號值有關,與訊號的傳送及安裝函式無關。目前linux中的signal()是通過sigation()函式實現的,因此,即使通過signal()安裝的訊號,在訊號處理函式的結尾也不必再呼叫一次訊號安裝函式。同時,由signal()安裝的實時訊號支援排隊,同樣不會丟失。

對於目前linux的兩個訊號安裝函式:signal()及sigaction()來說,它們都不能把SIGRTMIN以前的訊號變成可靠訊號(都不支援排隊,仍有可能丟失,仍然是不可靠訊號),而且對SIGRTMIN以後的訊號都支援排隊。這兩個函式的最大區別在於,經過sigaction安裝的訊號都能傳遞資訊給訊號處理函式,而經過signal安裝的訊號不能向訊號處理函式傳遞資訊。對於訊號傳送函式來說也是一樣的。

3.2實時訊號與非實時訊號

早期Unix系統只定義了32種訊號,前32種訊號已經有了預定義值,每個訊號有了確定的用途及含義,並且每種訊號都有各自的預設動作。如按鍵盤的CTRL ^C時,會產生SIGINT訊號,對該訊號的預設反應就是程序終止。後32個訊號表示實時訊號,等同於前面闡述的可靠訊號。這保證了傳送的多個實時訊號都被接收。

非實時訊號都不支援排隊,都是不可靠訊號;實時訊號都支援排隊,都是可靠訊號。

3.3訊號的優先順序

訊號實質上是軟中斷,中斷有優先順序,訊號也有優先順序。如果一個程序有多個未決訊號,則對於同一個未決的實時訊號,核心將按照發送的順序來遞送訊號。如果存在多個未決訊號,則值(或者說編號)越小的越先被遞送。如果即存在不可靠訊號,又存在可靠訊號(實時訊號),雖然POSIX對這一情況沒有明確規定,但Linux系統和大多數遵循POSIX標準的作業系統一樣,將優先遞送不可靠訊號。

3.4訊號列表

在Shell下輸入kill –l 可顯示Linux 系統支援的全部依賴,訊號列表如下:

1) SIGHUP         2) SIGINT            3) SIGQUIT        4) SIGILL
5) SIGTRAP        6) SIGABRT          7) SIGBUS         8) SIGFPE
9) SIGKILL        10) SIGUSR1         11) SIGSEGV       12) SIGUSR2
13) SIGPIPE       14) SIGALRM         15) SIGTERM       16) SIGSTKFLT
17) SIGCHLD       18) SIGCONT         19) SIGSTOP       20) SIGTSTP
21) SIGTTIN       22) SIGTTOU         23) SIGURG        24) SIGXCPU
25) SIGXFSZ       26) SIGVTALRM       27) SIGPROF       28) SIGWINCH
29) SIGIO         30) SIGPWR          31) SIGSYS        34) SIGRTMIN
35) SIGRTMIN+1     36) SIGRTMIN+2      37) SIGRTMIN+3    38) SIGRTMIN+4
39) SIGRTMIN+5     40) SIGRTMIN+6      41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9     44) SIGRTMIN+10     45) SIGRTMIN+11   46) SIGRTMIN+12
47) SIGRTMIN+13    48) SIGRTMIN+14     49) SIGRTMIN+15   50) SIGRTMAX-14
51) SIGRTMAX-13    52) SIGRTMAX-12     53) SIGRTMAX-11   54) SIGRTMAX-10
55) SIGRTMAX-9     56) SIGRTMAX-8      57) SIGRTMAX-7    58) SIGRTMAX-6
59) SIGRTMAX-5     60) SIGRTMAX-4      61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1     64) SIGRTMAX   

訊號的值定義在signal.h中,在Linux中沒有16和32這兩個訊號。上面訊號的含義如下:

(1) SIGHUP:當用戶退出Shell時,由該Shell啟的發所有程序都退接收到這個訊號,預設動作為終止程序。

(2) SIGINT:使用者按下組合鍵時,使用者端時向正在執行中的由該終端啟動的程式發出此訊號。預設動作為終止程序。

(3) SIGQUIT:當用戶按下組合鍵時產生該訊號,使用者終端向正在執行中的由該終端啟動的程式發出此訊號。預設動作為終止程序併產生core檔案。

(4) SIGILL :CPU檢測到某程序執行了非法指令。預設動作為終止程序併產生core檔案。

(5) SIGTRAP:該訊號由斷點指令或其他trap指令產生。預設動作為終止程序併產生core檔案。

(6) SIGABRT:呼叫abort函式時產生該訊號。預設動作為終止程序併產生core檔案。

(7) SIGBUS:非法訪問記憶體地址,包括記憶體地址對齊(alignment)出錯,預設動作為終止程序併產生core檔案。

(8) SIGFPE:在發生致命的算術錯誤時產生。不僅包括浮點執行錯誤,還包括溢位及除數為0等所有的算術錯誤。預設動作為終止程序併產生core檔案。

(9) SIGKILL:無條件終止程序。本訊號不能被忽略、處理和阻塞。預設動作為終止程序。它向系統管理員提供了一種可以殺死任何程序的方法。

(10) SIGUSR1:使用者定義的訊號,即程式可以在程式中定義並使用該訊號。預設動作為終止程序。

(11) SIGSEGV:指示程序進行了無效的記憶體訪問。預設動作為終止程序並使用該訊號。預設動作為終止程序。

(12) SIGUSR2:這是另外一個使用者定義訊號,程式設計師可以在程式中定義並使用該訊號。預設動作為終止程序。

(13) SIGPIPE:Broken pipe:向一個沒有讀端的管道寫資料。預設動作為終止程序。

(14) SIGALRM:定時器超時,超時的時間由系統呼叫alarm設定。預設動作為終止程序。

(15) SIGTERM:程式結束(terminate)訊號,與SIGKILL不同的是,該訊號可以被阻塞和處理。通常用來要求程式正常退出。執行Shell命令kill時,缺少產生這個訊號。預設動作為終止程序。

(16) SIGCHLD:子程式結束時,父程序會收到這個訊號。預設動作為忽略該訊號。

(17) SIGCONT:讓一個暫停的程序繼續執行。

(18) SIGSTOP:停止(stopped)程序的執行。注意它和SIGTERM以及SIGINT的區別:該程序還未結束,只是暫停執行。本訊號不能被忽略、處理和阻塞。預設作為暫停程序。

(19) SIGTSTP:停止程序的動作,但該訊號可以被處理和忽略。按下組合鍵時發出該訊號。預設動作為暫停程序。

(20) SIGTTIN:當後臺程序要從使用者終端讀資料時,該終端中的所有程序會收到SIGTTIN訊號。預設動作為暫停程序。

(21) SIGTTOU:該訊號類似於SIGTIN,在後臺程序要向終端輸出資料時產生。預設動作為暫停程序。

(22) SIGURG:套接字(socket)上有緊急資料時,向當前正在執行的程序發出此訊號,報告有緊急資料到達。預設動作為忽略該訊號。

(23) SIGXCPU:程序執行時間超過了分配給該程序的CPU時間,系統產生該訊號併發送給該程序。預設動作為終止程序。

(24) SIGXFSZ:超過檔案最大長度的限制。預設動作為yl終止程序併產生core檔案。

(25) SIGVTALRM:虛擬時鐘超時時產生該訊號。類似於SIGALRM,但是它只計算該程序佔有用的CPU時間。預設動作為終止程序。

(26) SIGPROF:類似於SIGVTALRM,它不僅包括該程序佔用的CPU時間還抱括執行系統呼叫的時間。預設動作為終止程序。

(27) SIGWINCH:視窗大小改變時發出。預設動作為忽略該訊號。

(28) SIGIO:此訊號向程序指示發出一個非同步IO事件。預設動作為忽略。

(29) SIGPWR:關機。預設動作為終止程序。

(30) SIGRTMIN~SIGRTMAX:Linux的實時訊號,它沒有固定的含義(或者說可以由使用者自由使用)。注意,Linux執行緒機制使用了前3個實時訊號。所有的實時訊號的預設動作都是終止程序。

這裡有另一種簡單明瞭的解釋:

這裡按發出訊號的原因簡單分類,以瞭解各種訊號:

(1) 與程序終止相關的訊號。當程序退出,或者子程序終止時,發出這類訊號。

(2) 與程序例外事件相關的訊號。如程序越界,或企圖寫一個只讀的記憶體區域(如程式正文區),或執行一個特權指令及其他各種硬體錯誤。

(3) 與在系統呼叫期間遇到不可恢復條件相關的訊號。如執行系統呼叫exec時,原有資源已經釋放,而目前系統資源又已經耗盡。

(4) 與執行系統呼叫時遇到非預測錯誤條件相關的訊號。如執行一個並不存在的系統呼叫。

(5) 在使用者態下的程序發出的訊號。如程序呼叫系統呼叫kill向其他程序傳送訊號

(6) 與終端互動相關的訊號。如使用者關閉一個終端,或按下break鍵等情況。

(7) 跟蹤程序執行的訊號。

Linux支援的訊號列表如下。很多訊號是與機器的體系結構相關的

訊號值 預設處理動作 發出訊號的原因

SIGHUP 1 A 終端掛起或者控制程序終止

SIGINT 2 A 鍵盤中斷(如break鍵被按下)

SIGQUIT 3 C 鍵盤的退出鍵被按下

SIGILL 4 C 非法指令

SIGABRT 6 C 由abort(3)發出的退出指令

SIGFPE 8 C 浮點異常

SIGKILL 9 AEF Kill訊號

SIGSEGV 11 C 無效的記憶體引用

SIGPIPE 13 A 管道破裂: 寫一個沒有讀埠的管道

SIGALRM 14 A 由alarm(2)發出的訊號

SIGTERM 15 A 終止訊號

SIGUSR1 30,10,16 A 使用者自定義訊號1

SIGUSR2 31,12,17 A 使用者自定義訊號2

SIGCHLD 20,17,18 B 子程序結束訊號

SIGCONT 19,18,25 程序繼續(曾被停止的程序)

SIGSTOP 17,19,23 DEF 終止程序

SIGTSTP 18,20,24 D 控制終端(tty)上按下停止鍵

SIGTTIN 21,21,26 D 後臺程序企圖從控制終端讀

SIGTTOU 22,22,27 D 後臺程序企圖從控制終端寫

處理動作一項中的字母含義如下

A 預設的動作是終止程序

B 預設的動作是忽略此訊號,將該訊號丟棄,不做處理

C 預設的動作是終止程序並進行核心映像轉儲(dump core),核心映像轉儲是指將程序資料在記憶體的映像和程序在核心結構中的部分內容以一定格式轉儲到檔案系統,並且程序退出執行,這樣做的好處是為程式設計師提供了方便,使得他們可以得到程序當時執行時的資料值,允許他們確定轉儲的原因,並且可以除錯他們的程式。

D 預設的動作是停止程序,進入停止狀況以後還能重新進行下去,一般是在除錯的過程中(例如ptrace系統呼叫)

E 訊號不能被捕獲

F 訊號不能被忽略

3.5訊號在目標程序中註冊

程序表的表項中有一個軟中斷訊號域,該域中每一位對應一個訊號。核心給一個程序傳送軟中斷訊號的方法,是在程序所在的程序表項的訊號域設定對應於該訊號的位。如果訊號傳送給一個正在睡眠的程序,如果程序睡眠在可被中斷的優先順序上,則喚醒程序;否則僅設定程序表中訊號域相應的位,而不喚醒程序。如果傳送給一個處於可執行狀態的程序,則只置相應的域即可。

程序的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;

}

訊號在程序中註冊指的就是訊號值加入到程序的未決訊號集sigset_t signal(每個訊號佔用一位)中,並且訊號所攜帶的資訊被保留到未決訊號資訊鏈的某個sigqueue結構中。只要訊號在程序的未決訊號集中,表明程序已經知道這些訊號的存在,但還沒來得及處理,或者該訊號被程序阻塞。

當一個實時訊號傳送給一個程序時,不管該訊號是否已經在程序中註冊,都會被再註冊一次,因此,訊號不會丟失,因此,實時訊號又叫做"可靠訊號"。這意味著同一個實時訊號可以在同一個程序的未決訊號資訊鏈中佔有多個sigqueue結構(程序每收到一個實時訊號,都會為它分配一個結構來登記該訊號資訊,並把該結構新增在未決訊號鏈尾,即所有誕生的實時訊號都會在目標程序中註冊)。

當一個非實時訊號傳送給一個程序時,如果該訊號已經在程序中註冊(通過sigset_t signal指示),則該訊號將被丟棄,造成訊號丟失。因此,非實時訊號又叫做"不可靠訊號"。這意味著同一個非實時訊號在程序的未決訊號資訊鏈中,至多佔有一個sigqueue結構

總之訊號註冊與否,與傳送訊號的函式(如kill()或sigqueue()等)以及訊號安裝函式(signal()及sigaction())無關,只與訊號值有關(訊號值小於SIGRTMIN的訊號最多隻註冊一次,訊號值在SIGRTMIN及SIGRTMAX之間的訊號,只要被程序接收到就被註冊)

3.6訊號的執行和登出

核心處理一個程序收到的軟中斷訊號是在該程序的上下文中,因此,程序必須處於執行狀態。當其由於被訊號喚醒或者正常排程重新獲得CPU時,在其從核心空間返回到使用者空間時會檢測是否有訊號等待處理。如果存在未決訊號等待處理且該訊號沒有被程序阻塞,則在執行相應的訊號處理函式前,程序會把訊號在未決訊號鏈中佔有的結構卸掉。

對於非實時訊號來說,由於在未決訊號資訊鏈中最多隻佔用一個sigqueue結構,因此該結構被釋放後,應該把訊號在程序未決訊號集中刪除(訊號登出完畢);而對於實時訊號來說,可能在未決訊號資訊鏈中佔用多個sigqueue結構,因此應該針對佔用sigqueue結構的數目區別對待:如果只佔用一個sigqueue結構(程序只收到該訊號一次),則執行完相應的處理函式後應該把訊號在程序的未決訊號集中刪除(訊號登出完畢)。否則待該訊號的所有sigqueue處理完畢後再在程序的未決訊號集中刪除該訊號。

當所有未被遮蔽的訊號都處理完畢後,即可返回使用者空間。對於被遮蔽的訊號,當取消遮蔽後,在返回到使用者空間時會再次執行上述檢查處理的一套流程。

核心處理一個程序收到的訊號的時機是在一個程序從核心態返回使用者態時。所以,當一個程序在核心態下執行時,軟中斷訊號並不立即起作用,要等到將返回使用者態時才處理。程序只有處理完訊號才會返回使用者態,程序在使用者態下不會有未處理完的訊號

處理訊號有三種類型:程序接收到訊號後退出;程序忽略該訊號;程序收到訊號後執行使用者設定用系統呼叫signal的函式。當程序接收到一個它忽略的訊號時,程序丟棄該訊號,就象沒有收到該訊號似的繼續執行。如果程序收到一個要捕捉的訊號,那麼程序從核心態返回使用者態時執行使用者定義的函式。而且執行使用者定義的函式的方法很巧妙,核心是在使用者棧上建立一個新的層,該層中將返回地址的值設定成使用者定義的處理函式的地址,這樣程序從核心返回彈出棧頂時就返回到使用者定義的函式處,從函式返回再彈出棧頂時,才返回原先進入核心的地方。這樣做的原因是使用者定義的處理函式不能且不允許在核心態下執行(如果使用者定義的函式在核心態下執行的話,使用者就可以獲得任何許可權)。

4       訊號的安裝

如果程序要處理某一訊號,那麼就要在程序中安裝該訊號。安裝訊號主要用來確定訊號值及程序針對該訊號值的動作之間的對映關係,即程序將要處理哪個訊號;該訊號被傳遞給程序時,將執行何種操作。

linux主要有兩個函式實現訊號的安裝:signal()、sigaction()。其中signal()只有兩個引數,不支援訊號傳遞資訊,主要是用於前32種非實時訊號的安裝;而sigaction()是較新的函式(由兩個系統呼叫實現:sys_signal以及sys_rt_sigaction),有三個引數,支援訊號傳遞資訊,主要用來與 sigqueue() 系統呼叫配合使用,當然,sigaction()同樣支援非實時訊號的安裝。sigaction()優於signal()主要體現在支援訊號帶有引數。

4.1signal()

#include <signal.h>

void (*signal(int signum, void (*handler))(int)))(int);

如果該函式原型不容易理解的話,可以參考下面的分解方式來理解:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler));

第一個引數指定訊號的值,第二個引數指定針對前面訊號值的處理,可以忽略該訊號(引數設為SIG_IGN);可以採用系統預設方式處理訊號(引數設為SIG_DFL);也可以自己實現處理方式(引數指定一個函式地址)。

如果signal()呼叫成功,返回最後一次為安裝訊號signum而呼叫signal()時的handler值;失敗則返回SIG_ERR。

傳遞給訊號處理例程的整數引數是訊號值,這樣可以使得一個訊號處理例程處理多個訊號。

#include <signal.h>

#include <unistd.h>

#include <stdio.h>

void sigroutine(int dunno)

{ /* 訊號處理例程,其中dunno將會得到訊號的值 */

        switch (dunno) {

        case 1:

        printf("Get a signal -- SIGHUP ");

        break;

        case 2:

        printf("Get a signal -- SIGINT ");

        break;

        case 3:

        printf("Get a signal -- SIGQUIT ");

        break;

        }

        return;

}

int main() {

        printf("process id is %d ",getpid());

        signal(SIGHUP, sigroutine); //* 下面設定三個訊號的處理方法

        signal(SIGINT, sigroutine);

        signal(SIGQUIT, sigroutine);

        for (;;) ;

}

其中訊號SIGINT由按下Ctrl-C發出,訊號SIGQUIT由按下Ctrl-發出。該程式執行的結果如下:

localhost:~$ ./sig_test

process id is 463

Get a signal -SIGINT //按下Ctrl-C得到的結果

Get a signal -SIGQUIT //按下Ctrl-得到的結果

//按下Ctrl-z將程序置於後臺

 [1]+ Stopped ./sig_test

localhost:~$ bg

 [1]+ ./sig_test &

localhost:~$ kill -HUP 463 //向程序傳送SIGHUP訊號

localhost:~$ Get a signal – SIGHUP

kill -9 463 //向程序傳送SIGKILL訊號,終止程序

localhost:~$

4.2sigaction()

#include <signal.h>

int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

sigaction函式用於改變程序接收到特定訊號後的行為。該函式的第一個引數為訊號的值,可以為除SIGKILL及SIGSTOP外的任何一個特定有效的訊號(為這兩個訊號定義自己的處理函式,將導致訊號安裝錯誤)。第二個引數是指向結構sigaction的一個例項的指標,在結構sigaction的例項中,指定了對特定訊號的處理,可以為空,程序會以預設方式對訊號處理;第三個引數oldact指向的物件用來儲存返回的原來對相應訊號的處理,可指定oldact為NULL如果把第二、第三個引數都設為NULL,那麼該函式可用於檢查訊號的有效性

第二個引數最為重要,其中包含了對指定訊號的處理、訊號所傳遞的資訊、訊號處理函式執行過程中應遮蔽掉哪些訊號等等。

sigaction結構定義如下:

struct sigaction {

                       union{

__sighandler_t _sa_handler;

                               void (*_sa_sigaction)(int,struct siginfo *, void *);

                       }_u

            sigset_t sa_mask;

            unsigned long sa_flags;

}

1、聯合資料結構中的兩個元素_sa_handler以及*_sa_sigaction指定訊號關聯函式,即使用者指定的訊號處理函式。除了可以是使用者自定義的處理函式外,還可以為SIG_DFL(採用預設的處理方式),也可以為SIG_IGN(忽略訊號)。

2、由_sa_sigaction是指定的訊號處理函式帶有三個引數,是為實時訊號而設的(當然同樣支援非實時訊號),它指定一個3引數訊號處理函式。第一個引數為訊號值,第三個引數沒有使用,第二個引數是指向siginfo_t結構的指標,結構中包含訊號攜帶的資料值,引數所指向的結構如下:

siginfo_t {

                  int      si_signo;  /* 訊號值,對所有訊號有意義*/

                  int      si_errno;  /* errno值,對所有訊號有意義*/

                  int      si_code;   /* 訊號產生的原因,對所有訊號有意義*/

                               union{                               /* 聯合資料結構,不同成員適應不同訊號 */

                                       //確保分配足夠大的儲存空間

                                       int _pad[SI_PAD_SIZE];

                                       //對SIGKILL有意義的結構

                                       struct{

                                                      ...

                                                 }...

                                               ... ...

                                               ... ...                               

                                       //對SIGILL, SIGFPE, SIGSEGV, SIGBUS有意義的結構

                                  struct{

                                                      ...

                                                 }...

                                               ... ...

                                         }

}

前面在討論系統呼叫sigqueue傳送訊號時,sigqueue的第三個引數就是sigval聯合資料結構,當呼叫sigqueue時,該資料結構中的資料就將拷貝到訊號處理函式的第二個引數中。這樣,在傳送訊號同時,就可以讓訊號傳遞一些附加資訊。訊號可以傳遞資訊對程式開發是非常有意義的。

3、sa_mask指定在訊號處理程式執行過程中,哪些訊號應當被阻塞。預設情況下當前訊號本身被阻塞,防止訊號的巢狀傳送,除非指定SA_NODEFER或者SA_NOMASK標誌位。

注:請注意sa_mask指定的訊號阻塞的前提條件,是在由sigaction()安裝訊號的處理函式執行過程中由sa_mask指定的訊號才被阻塞

4、sa_flags中包含了許多標誌位,包括剛剛提到的SA_NODEFER及SA_NOMASK標誌位。另一個比較重要的標誌位是SA_SIGINFO,當設定了該標誌位時,表示訊號附帶的引數可以被傳遞到訊號處理函式中,因此,應該為sigaction結構中的sa_sigaction指定處理函式,而不應該為sa_handler指定訊號處理函式,否則,設定該標誌變得毫無意義。即使為sa_sigaction指定了訊號處理函式,如果不設定SA_SIGINFO,訊號處理函式同樣不能得到訊號傳遞過來的資料,在訊號處理函式中對這些資訊的訪問都將導致段錯誤(Segmentation fault)。

5       訊號的傳送

傳送訊號的主要函式有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()。

5.1kill()

#include <sys/types.h>

#include <signal.h>

int kill(pid_t pid,int signo)

該系統呼叫可以用來向任何程序或程序組傳送任何訊號。引數pid的值為訊號的接收程序

pid>0 程序ID為pid的程序

pid=0 同一個程序組的程序

pid<0 pid!=-1 程序組ID為 -pid的所有程序

pid=-1 除傳送程序自身外,所有程序ID大於1的程序

Sinno是訊號值,當為0(即空訊號),實際不傳送任何訊號,但照常進行錯誤檢查,因此,可用於檢查目標程序是否存在,以及當前程序是否具有向目標傳送訊號的許可權root許可權的程序可以向任何程序傳送訊號,非root許可權的程序只能向屬於同一個session或者同一個使用者的程序傳送訊號)。

Kill()最常用於pid>0時的訊號傳送。該呼叫執行成功時,返回值為0;錯誤時,返回-1,並設定相應的錯誤程式碼errno。下面是一些可能返回的錯誤程式碼:

EINVAL:指定的訊號sig無效。

ESRCH:引數pid指定的程序或程序組不存在。注意,在程序表項中存在的程序,可能是一個還沒有被wait收回,但已經終止執行的僵死程序。

相關推薦

Linux訊號機制分析訊號處理函式

【摘要】本文分析了Linux核心對於訊號的實現機制和應用層的相關處理。首先介紹了軟中斷訊號的本質及訊號的兩種不同分類方法尤其是不可靠訊號的原理。接著分析了核心對於訊號的處理流程包括訊號的觸發/註冊/執行及登出等。最後介紹了應用層的相關處理,主要包括訊號處理函式的安裝、訊號

Linux中訊息佇列訊號量集合的理解

訊息佇列和訊號量集合同樣作為程序間通訊的重要手段,是LInux程式設計必需理解的內容,但兩者類似的操作和檔案結構讓很多人不能理解其中的原理。下面我來介紹下我的理解: 在使用訊息佇列和訊號量集合前都必須使用的一個函式Key_t ftok(char *pathname,char

Java代理動態代理機制分析應用

一、概述        代理是一種常用的設計模式,其目的就是為其他物件提供一個代理以控制對某個物件的訪問。代理類負責為委託類預處理訊息,過濾訊息並轉發訊息,以及進行訊息被委託類執行後的後續處理。根據代理類的生成時間不同可以將代理分為靜態代理和動態代理兩

C語言字元字串處理函式(二)strchr,strpbrk,strstr

查詢字元或者字串 查詢一個字元:和和和strchr()。 函式返回一個指向STR中CH首次出現的位置,當沒有在STR中找CH就報道檢視NULL。 查詢任意字元:strpbrk()  函式返回一個指標,它指向字串STR2中任意字元在字串STR1首次出現的位置,如果不存在返

linux的日誌監控定期處理指令碼

具體場景:伺服器產生的日誌量非常大,每天將近100M+的日誌量,所以博主寫了一個日誌的分隔指令碼;每隔2小時執行一次,當日志文件超過6M時,將日誌進行轉存,命名格式為20180917-12.log,這

VC++檔案路徑檔名處理函式

轉自:http://blog.csdn.net/hehe6378/article/details/18990739 路徑截斷與合併函式 GetModuleFileName 得到模組路徑名 PathRemoveArgs 去除路徑的引數 PathRe

js中三種事件繫結之間的關係事件處理函式裡的this值

<!DOCTYPE HTML> <html > <head>     <meta charset="UTF-8"> </head> <body> <div id="b" onclick="cons

訊號取樣頻率訊號頻率的關係

對於一個256hz取樣頻率的訊號,每個4個取一個點;消去的頻率是64hz;;原理是,:取樣頻率是256,對應訊號的最大頻率是128hz,在原訊號中每隔4個點取一個,在128hz中對應的就是每隔兩個點去

mysql常用函式----日期時間處理函式

對於每個型別擁有的值範圍以及並且指定日期何時間值的有效格式的描述見7.3.6 日期和時間型別。 這裡是一個使用日期函式的例子。下面的查詢選擇了所有記錄,其date_col的值是在最後30天以內: mysql> SELECT something FROM table

linux系能分析瓶頸查詢

 何為負載?  1.在top裡輸出loadaverage aa  bb  cc或者 cat /proc/loadavg,在一定時間內程序平均等待時間,如果這個引數值高,說明系能負載高.  2.程序為什麼會等待執行?     多工的OS,程序執行都是分時被排程  A-B-核心

Linux cgroup機制分析之框架分析

八:cgroup中檔案的操作 接下來,就來看cgroup檔案的操作.在上面曾分析到:檔案對應的操作集為cgroup_file_operations.如下所示: static struct file_operations cgroup_file_operations = {     .read = c

訊號掩碼訊號集進行操作

每個程序都有一個訊號掩碼,它給出了當前程序想要阻塞的訊號的集合,訊號掩碼的型別為sigset_t。注意,阻塞訊號與忽略訊號的概念是不同的,程序阻塞訊號時,作業系統會在程序解除對該訊號的阻塞之前不會將訊號傳遞出去,但解除阻塞之後,程序還是會收到該訊號的。但是程序忽略訊號時,作

Linux核心實現中斷中斷處理(一)

Linux實現中斷處理 核心是怎麼知道應用程式要呼叫系統呼叫的呢?或者說應用程式怎麼通知系統核心自己需要執行一個系統呼叫,這是通過軟中斷實現的,通過引發一個異常來促使系統切換到核心態去執行異常處理程式

【原創】Linux Mutex機制分析

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex-A53,雙核 3. 使用工具:S

linux程序訊號處理函式signalsigaction

Linux中signal函式說明: NAME        signal - ANSI C signal handling SYNOPSIS        #include <signal.h>        typedef void (*sighandler_

Linux 訊號訊號處理函式傳遞資料

1.Linux 訊號是一種非同步機制,程序可以接收一個訊號,並有相應的處理操作,如果我們需要改變當該訊號發生時的預設行為,我們就需要捕捉該訊號,並且自己書寫訊號處理函式。 2.這種訊號處理函式就跟中斷差不多,當一個程序接收到一個訊號時,程序會暫停當前的執行流,轉而呼叫訊號處理函式,訊號處理函

Linux訊號(signal) 機制分析

【摘要】本文分析了Linux核心對於訊號的實現機制和應用層的相關處理。首先介紹了軟中斷訊號的本質及訊號的兩種不同分類方法尤其是不可靠訊號的原理。接著分析了核心對於訊號的處理流程包括訊號的觸發/註冊/執行及登出等。最後介紹了應用層的相關處理,主要包括訊號處理函式的安裝、訊號的傳送、遮蔽阻塞等,最後給了幾個簡單的

Linux訊號訊號處理函式註冊

每一個訊號都有一個訊號處理函式,可以是SIG_IGN, SIG_DFL或者是使用者自定義的處理函式。使用使用者自定義的處理函式需要註冊,註冊介面有如下兩種。 第一種是signal呼叫 #include <signal.h> /** * sighandle

非常好的一篇對linux訊號(signal)的解析 (轉載)【轉】 Linux訊號(signal) 機制分析

轉自:https://blog.csdn.net/return_cc/article/details/78845346 Linux訊號(signal) 機制分析 轉載至:https://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html

三十一、Linux 程序與訊號——SIGCHLD 訊號、killraise函式以及alarm函式

31.1 SIGCHLD 訊號 子程序狀態發生變化(子程序結束)產生該訊號,父程序需要使用 wait 呼叫來等待子程序結束並回收它。 避免殭屍程序 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include