外圍設備的速度遠低於CPU的速度,因此爲提升CPU計算效率,現代計算機變內核主動爲硬件主動,只在硬件須要的時候才發送信號,通知內核來處理數據。這樣外圍設備與內核的協做方式即爲中斷機制。而設備發送的信號即爲中斷,其本質爲一種特殊的電信號。html
一、各外圍設備與中斷管理器各輸入引腳相連;linux
二、中斷管理器與CPU之間只存在一條中斷管線;編程
三、設備發送一箇中斷到中斷管理器;數組
四、中斷管理器發送對應電信號給CPU。安全
五、CPU中斷當前工做,開始處理中斷,並通知操做系統。網絡
六、操做系統調用中斷處理程序。併發
一、不一樣的設備對應不一樣的中斷,並被用數字標識;異步
二、對應的設備須要對應的中斷處理程序;函數
三、中斷值即中斷請求線(IRQ),被關聯到不一樣的數值量,如IRQ 0,中斷亦可動態分配。性能
四、設備中斷信號可能在任意時刻到來,不與CPU時鐘同步,即異步硬件中斷。
糕富帥CPU來到女兒國,女兒國的妹子們(中斷集合)精心打扮,總在認爲打扮完美的時刻向糕富帥拋媚眼露大腿扮性感,引發糕富帥的注意。糕富帥玩弄妹子的手段高超,經驗豐富,與最靚的妹紙牽手,喜歡爲不一樣的妹子編號並制定不一樣的攻略策略,老是上半場激烈,下半場纏綿,中場偷腥不斷,並在膩味以後迴歸原始的浪蕩生活。妹紙們老是很傻很天真,屢敗屢戰,不停地打扮本身,完美本身,期待着與糕富帥的從新開始。
若是程序出現編碼錯誤、CPU自己故障和內存缺頁等反常狀況時,CPU將異常反饋給內核,調用異常處理程序進行處理。異常的產生必須與cpu時鐘同步,又叫同步中斷。
一、故障,執行處理函數後,恢復現場繼續執行;
二、陷阱,用於調試,陷阱命令執行完畢後,內核將控制權返回給用戶程序;
三、異常停止,用於報告嚴重錯誤,如硬件故障和系統表數值異常等,其異常處理函數將當即停止程序的執行;
四、編程異常,用於執行系統調用或向調試程序通報特定事件,即軟中斷,被當作陷阱處理。
內核在響應一箇中斷時,將調用對應的特定函數,這個函數就是中斷處理程序 。這個函數是按照特定類型聲明的C函數,運行與中斷上下文中。中斷隨時可能到來,爲保證儘快恢復被中斷代碼的執行,中斷處理程序必須保證快速執行。但中斷處理程序可能要完成大量非瞬時工做(好比將網絡數據拷貝到內存,並將預處理的數據轉交給特定的協議棧),因此中斷處理任務被兩部分,上半部--中斷處理程序實時響應中斷並執行,下半部--完成可被退出處理的工做,在合適的時機到來後,下半部將開中斷執行。
中斷程序是硬件驅動程序的重要組成部分。硬件的驅動程序在初始化加載時,必須爲其中斷線註冊對應的中斷處理程序。同一中斷線可能被對個設備共享,此時必須使用設備結構來區分。共享中斷線的各設備,註冊中斷程序時必須使用IRQF_SHARED標誌位。中斷程序能夠註銷,若某中斷線上全部診斷處理程序均已註銷,則此條中斷線被禁用。
內核在執行中斷處理程序時,即處於中斷上下文中。中斷上下文有嚴格的時間限制。中斷上下文時執行的代碼,必須迅速並簡潔,不適用循環處理繁雜任務,且不能睡眠或調用可能睡眠的函數(不然沒法從新調度),以迅速恢復中斷現場,防止打斷其餘代碼(甚至其餘中斷線的中斷程序)的執行。因此中斷程序的上半部必須力求簡約。
2.6版本以前的中斷程序共享被中斷進程的內核棧(無進程調度時,將使用空任務進程idle),2.6版本的linux爲每一個CPU均分配了一箇中斷棧。內核將中斷處理程序的入口點預約義在內存中,中斷到來,內核跳到中斷入口點,保存該中斷號和當前寄存器的值,接着執行do_IRQ()禁止該中斷線並屏蔽該CPU對任意中斷的響應(防止中斷的嵌套和重入問題),接着開始調用對應的中斷處理C代碼。
一、BH靜態全局鏈表:即bottom half,在全局範圍內同步,共32個bottom halves組成,用一個32位數標識那個BH可執行。簡單方便、死板、性能不夠;
二、任務隊列:即task queue,一組待處理函數組成的鏈表隊列,驅動程序將下半部註冊到隊列中,內核依照隊列循序處理。性能有提高,但不能徹底替換BH,沒法處理高性能子系統;
三、軟中斷、tasklet和工做隊列:2.3開發版本開始。軟中斷是靜態定義的32個下半部接口(結構體數組),可在全部處理器上同時運行;tasklet基於軟中斷實現,可動態建立和加載,不一樣類型的tasklet可同時在不一樣cpu上運行,但同類型tasklet只能同時運行一個,因爲其靈活性,tasklet是最多見的下半部實現;工做隊列將下半部任務排隊,在進程的上下文中執行,替代任務隊列(2.5)。2.5版本後,BH被完全廢棄。
四、內核定時器:將工做延期到某個肯定時間段去執行,適用於有時間要求的下半部。
信號是進程處理異步事件的方法,信號是進程與內核、進程與進程通訊的一種方式,是進程接受外部控制的一種方式,好比:接受內核執行除零計算返回的SIGSEGV信號,父進程接受子進程的SIGCHLD,接受鍵盤驅動產生的SIGINIT信號等。進程對信號的默認處理方式:終止進程、終止進程+生成core文件、忽略和暫停進程等。軟件編程人員能夠在程序中設置信號處理函數,以響應外部信號。
信號即軟件中斷,它與軟中斷不一樣,信號是軟件程序的中斷,軟中斷是內核的中斷,但它們有許多的共同點,都將中斷程序的運行並執行指定的函數,尤爲是在使用中必須注意的同步和互斥問題,必須謹慎的使用臨界區代碼。爲防止臨界區代碼對共享資源的併發訪問,必須保證臨界區代碼的原子性。信號中斷實際的中斷點是在某個系統調用後,而不是用戶函數。
當進程收到信號時,內核信號預處理函數do_singal()會將信號的處理句柄(對應信號處理函數)插入到用戶進程的程序堆棧中,在當前系統調用結束並返回後,信號處理函數纔會被pop並執行,最終返回執行用戶程序。
對於慢速系統調用,慢速系統調用將進程運行狀態置爲TASK_INTERRUPTIBLE,可能在其爲徹底執行完畢前,信號的到來將致使其提早返回(內核進程調度函數將進程運行狀態更新爲TASK_RUNNING,喚醒進程,直接將進程入可調度隊列並執行)。4.2BSD爲部分慢速系統調用設計了自動重啓動功能,詳細內容可參照APUE。
各種信號設置函數,支持的系統請參看APUE2.p304
一、signal
二、sigset
三、sigvec
四、sigaction(推薦)
舊signal提供的是不可靠的信號機制,sigaction提供的是可靠的信號機制,但當前大多數系統的signal均以sigaction實現,因此signal也是可靠的信號處理了。但依然建議只使用sigaction,除非系統不支持。
這些安裝信號處理程序的函數所有支持:保持已安裝的信號處理程序,並提供阻塞信號的功能。
早期UNIX版本的信號,可能會丟失,對信號的控制能力也很是弱,不能阻塞信號。好比:早期接收信號並處理時,該信號的處理復位爲默認,而從捕獲信號到執行信號處理函數之間會有一個時間窗,此時若是信號再次到來時,進程可能被終止。有時咱們只想暫時阻塞信號,可是不要忽略信號,在進程準備好是再去獲取並處理,可是早期的UNIX並不具有該功能。此時,信號處理是不可靠的。
在後期的4.2BSD和SVR3均提供了改進的信號處理機制,POSIX.1最終選擇了BSD的可靠信號方案做爲標準化的基礎。
注:不要有這樣的誤解:由sigqueue()發送、sigaction安裝的信號就是可靠的。事實上,可靠信號(實時信號)是指後來添加的新信號(信號值位於SIGRTMIN及SIGRTMAX之間);不可靠信號(非實時信號)是信號值小於SIGRTMIN的信號。信號的可靠與不可靠只與信號值有關,與信號的發送及安裝函數無關。signal()及sigaction()都不能把SIGRTMIN之前的信號變成可靠信號(都不支持排隊,仍有可能丟失,仍然是不可靠信號),並且對SIGRTMIN之後的信號都支持排隊。這兩個函數的最大區別在於,通過sigaction安裝的信號都能傳遞信息給信號處理函數(對全部信號這一點都成立),而通過signal安裝的信號卻不能向信號處理函數傳遞信息。對於信號發送函數來講也是同樣的。
信號機制具備如下三方面的功能:
(1 )發送信號。發送信號的主要函數有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort();
(2 )預置對信號的處理方式。接收信號的程序用 signal( ) 來實現對處理方式的預置;
(3 )收受信號的進程按事先的規定完成對相應事件的處理。
以下是一簡單的信號處理程序,sigaction設置信號SIGINT的處理方式,用戶經過按Crtl+C生成SIGINT信號給當前進程,程序收到信號後foo函數打印信息。
#include<stdio.h> #include<unistd.h> #include<signal.h> void foo(int signum) { printf("Hello signal(%d), i catch you!\n", signum); } int main() { struct sigaction act, oact; act.sa_handler = foo; sigemptyset(&act.sa_mask); act.sa_flags = 0; if(sigaction(SIGINT, &act, &oact) < 0) { return (-1); } while(1) { sleep(1); } return 0; }
一、int kill(pid_t pid, int signo)
二、int raise(int signo)
三、int sigqueque(pid_t pid, int signo, const union sigval val)
四、unsigned int alarm(unsigned int seconds)
五、int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue))
六、void abort(void)
關於軟中斷:http://www.ibm.com/developerworks/cn/linux/kernel/interrupt/index.html
信號入門與信號編程:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html 對信號相關的基礎知識介紹的很全面
http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index2.html 對信號編程作了較詳細說明
http://www.man7.org/linux/man-pages/man7/signal.7.html signal的man信息
http://linux.chinaunix.net/techdoc/system/2006/06/04/933746.shtml 對信號的內核處理以及信號編程作了比較詳細的描述
可重入、異步信號安全和線程安全:http://www.ibm.com/developerworks/cn/linux/l-cn-signalsec/ 提供了異步信號轉化爲同步信號的方法
http://www.ibm.com/developerworks/cn/linux/l-reent.html 使用可重入函數進行更安全的信號處理
http://blog.sina.com.cn/s/blog_8fa7dd4101015hi5.html 可重入、線程安全、異步信號安全小結
W. Richard Stevens, Advanced Programming in the UNIX Environment(2 Edition) 對信號編程有介紹
趙炯,Linux內核徹底剖析——基於0.12內核 詳細分析了0.12內核下的信號和中斷處理源碼
Robert Love, Linux Kernel Development(3 Edition) 有對Linux的中斷機制的闡述