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相容的作業系統中程序間通訊的一種有限制的方式。它是一種非同步的通知機制,用來提醒程序乙個事件已經發生。當乙個訊號傳送給乙個程序,作業系統中斷了程序正常的控制流程,此時,任何非原子操作都將被中斷。如果程序定義了訊號的處理函式,那麼它將被執行,否...