信號機制是Unix的一大特色,因爲是特色,所以很多同學在編程時,有些不能理解(超出理解範圍?)。
本文對Linux信號機制做一個分析。
常見signal使用如下:
void mysig(){
printf("got a sig!\n");
}
int main() {
printf("process id is %d !\n",getpid());
signal(SIGINT, mysig);
for (;;) ;
}
當我們在控制檯按Ctrl + C時,控制檯會打印出"got a sig!"。
這個過程到底發生了什麼?
如果你沒有深入思考過操作系統的工作原理,就算是寫過幾年的C程序,也是一頭霧水。
如果是初學C,都知道,C程序是從main函數開始,跑到最後一行,順序執行!signal的概念完全就是個怪胎!
signal的內核操作過程如下:
1,signal()系統調用,發生0x80中斷(陷阱),調用sys_signal()。
2,sys_signal()獲取到傳入的信號編號(SIGINT等宏定義),以及對應的handler,把它註冊到current宏的sigaction[signum-1],current宏指向了正在執行的task_struct,而sigaction是task_struct的一個成員。
3,中斷服務程序執行完畢之後,準備返回用戶程序,返回之前,檢查當前進程可以處理的信號——此時,信號可能(一般)還沒發生。
4,程序員按了Ctrl +C,內核接收到這個信號了,對應的sigaction的選項被標記。
5,內核又發生了中斷,返回用戶程序前,檢查可以處理的信號,發現有信號可以處理,do_signal(),跳轉到註冊的handler(),程序員感覺到穿越了(也就是最難理解的地方)
6,handler()執行完畢之後,執行特殊系統調用,返回內核態。
7,從內核態返回用戶模式,出棧,恢復到中斷髮生之前,接着執行之前的代碼。
所以,關鍵還是對中斷的理解——理解了中斷,linux內核就理解了三分之一!