linux0 11訊號機制

2021-12-30 03:18:49 字數 2790 閱讀 4085

linux0.11訊號機制

本文簡單描述linux0.11訊號機制的實現

www.2cto.com  

一:有關訊號

當程序收到乙個訊號後,程序根據相關設定呼叫訊號處理函式。

有三類訊號處理方式:預設處理方式、忽略訊號方式、執行使用者設定的訊號處理函式。

傳送訊號的方式:按下相應的鍵(如ctrl+c)、使用kill命令或函式向指定程序傳送訊號。

typedef void sig_func(int);

sig_func *signal(int signr, sig_func *handler);

當在程序中呼叫signal(signo, handler)之後,

如果程序收到訊號signo,則程序會執行handler指向的函式。

假設有程序a和程序b,當程序a給程序b傳送了乙個訊號後,那程序b的訊號處理函式什麼時候執行?

若要執行程序b的訊號處理函式,則程序b必須處於執行狀態。也就是說只有當排程程式排程到了程序b後,

才可能執行程序b的訊號處理函式。否則程序b不處於可執行狀態,收到了訊號也沒用。

若程序b自己呼叫kill函式,給自己傳送了乙個訊號,我們會假定這個訊號處理函式會立即執行。

因此在執行系統函式kill之後會立即處理程序b的訊號。

從這兩點可以意識到,核心需要在時鐘中斷和系統呼叫後對當前程序的訊號進行處理。

需要在時鐘中斷時是因為時鐘中斷會呼叫schedule函式,因為這是分時系統,

如果程序a給b發了訊號,而且現在排程到了b,那理所當然要執行b的訊號處理函式。

二:linux0.11的訊號機制

以 kill 函式為例來簡單說明大致流程, 下面再來詳細描述核心中的do_signal函式。

當以kill函式給當前程序傳送乙個訊號之後。

因為這是個系統函式,因此會執行int 0x80進入system_call的入口點

_system_call:

cmpl $nr_system_calls-1, %eax # %eax儲存kill函式的呼叫號

ja bad_sys_call # 無效的系統呼叫

push %ds

push %es

push %fs

push %edx

push %ecx

push %ebx # 相關資料入棧

.....................

call _sys_call_table(,%eax,4)   # 執行系統呼叫, 這裡就是 sys_kill 函式了

pushl %eax # 系統呼叫的返回值入棧,也即是 sys_kill 的返回值

......................

ret_from_sys_call:

.....

pushl %ecx  # %ecx中儲存了訊號的訊號值。

call _do_signal  # 對訊號進行處理

popl %eax #  將訊號值出棧  

popl %eax  #  將系統呼叫返回值出棧,  也就是sys_kill的返回值存入%eax暫存器

popl %ebx

popl %ecx

popl %edx

pop %fs

pop %es

pop %ds

iret

可見每次系統呼叫之後,可能會執行ret_from_sys_call,進而對訊號進行處理。

除了在_system_call裡會這樣, 在一些中斷下也會呼叫ret_from_sys_call,時鐘中斷就是其中之一。

現在已經知道核心是「何時」來處理程序的訊號了。

三:do_signal函式。

do_signal的功能主要是設定了核心的堆疊和應用的使用者堆疊,設定好堆疊後,

當執行ret_from_sys_call最下面的iret指令的時候,去自動執行程序的訊號處理函式。當訊號處理函式執行完成後,又會接著程序的下一條指令去執行。

下圖是《linux0.11核心完全注釋》一書裡的,很好的顯示呼叫do_signal前後的堆疊變化。

左邊的為核心態堆疊,就是在執行call _do_signal之前的堆疊內容。

do_signal執行如下操作

1:將堆疊中的eip值,儲存到old_eip中,old_eip就指向了使用者程式中即將執行**

2:將eip執行訊號處理函式。這樣當執行ret_from_sys_call中的iret時,會執行cs:eip指向的**,也就是訊號處理函式。

3:將使用者態堆疊的esp的值,向下移7或8個長字(32位)

4:然後將sa_resotrer, signr等值放入堆疊, 見圖右邊的使用者堆疊。

完成上述操作後,do_signal執行完畢,返回到ret_from_sys_call中,

ret_from_sys_call執行一些pop操作後執行iret指令, 這時會跳轉到訊號處理函式去執行。

當訊號處理函式執行完後,會執行ret操作(函式的返回使用ret,中斷的返回使用iret),這時會將sa_restorer存入eip,

因此接下來就會執行sa_restorer

sa_restorer會恢復使用者堆疊

__sig_restore:

addl $4, %esp

popl %eax  # 將系統呼叫的返回值存入eax

popl %ecx

popl %edx

popfl

ret 

當執行完popfl之後,明顯使用者堆疊裡面只剩下old_eip了, 因此執行ret,程式就會跳轉到cs:old_eip去執行,也就是系統呼叫的下一條使用者指令了。

至此訊號處理函式已經執行,系統呼叫也已返回,使用者程式無憂無慮的繼續執行。

Linux 信 號 機 制

前面介紹了訊號的基本概念,在這一節中,我們將介紹核心如何實現訊號機制。即核心如何向乙個程序傳送訊號 程序如何接收乙個訊號 程序怎樣控制自己對訊號的反應 核心在什麼時機處理和怎樣處理程序收到的訊號。還要介紹一下setjmp和longjmp在訊號中起到的作用。1 核心對訊號的基本處理方法 核心給乙個程序...

linux 訊號機制

本文旨在弄懂linux中的訊號工作原理 kill l 命令可以檢視linux下所有訊號 2.1 使用者在終端按下某些鍵時,終端驅動程式會傳送訊號給前台程序 例如ctrl c產生sigint訊號,ctrl 產生sigquit訊號,ctrl z產生sigtstp訊號 2.2 硬體異常產生訊號,這些條件由...

LINUX訊號機制

在電腦科學中,訊號是unix 類unix以及其他posix相容的作業系統中程序間通訊的一種有限制的方式。它是一種非同步的通知機制,用來提醒程序乙個事件已經發生。當乙個訊號傳送給乙個程序,作業系統中斷了程序正常的控制流程,此時,任何非原子操作都將被中斷。如果程序定義了訊號的處理函式,那麼它將被執行,否...