參考了這篇文章:http://blog.csdn.net/zhangskd/article/details/21992933
從本質上來講,中斷是一種電信號,當設備有某種事件發生時,它就會產生中斷,通過總線把電信號發送給中斷控制器(如 8259A)。
如果中斷的線是激活的,中斷控制器就把電信號發送給處理器的某個特定引腳。處理器於是立即停止自己正在做的事,
跳到中斷處理程序的入口點,進行中斷處理。
常見的中斷控制器有兩種:可編程中斷控制器 8259A 和高級可編程中斷控制器(APIC),中斷控制器應該在大學的硬件接口和計算機體系結構的相關課程中都學過。傳統的 8259A 只適合單 CPU 的情況,現在都是多 CPU 多核的 SMP 體系,所以為了充分利用 SMP 體系結構、把中斷傳遞給系統上的每個 CPU 以便更好實現並行和提高性能,Intel 引入了高級可編程中斷控制器(APIC)。
光有高級可編程中斷控制器的硬件支持還不夠,Linux 內核還必須能利用到這些硬件特質,所以只有 kernel 2.4 以后的版本才支持把不同的硬件中斷請求(IRQs)分配到特定的 CPU 上,這個綁定技術被稱為 SMP IRQ Affinity.
IRQ
http://blog.csdn.net/skyflying2012/article/details/7850674
中斷處理程序比一個進程要“輕”(中斷的上下文很少,建立或終止中斷處理需要的時間也很少)
中斷處理是由內核執行的最敏感的任務之一,因為它必須滿足下列約束:
◎ 當內核正打算去完成一些別的事情時,中斷隨時會到來。因此,內核的目標就是讓中斷盡可能快地處理完,盡其所能把更多的處理向后推遲。因此,內核響應中斷后需要進行的操作分為兩部分:關鍵而緊急的部分,內核立即執行;其余推遲的部分,內核隨后執行。 ◎ 因為中斷隨時會到來,所以內核可能正在處理其中的一個中斷時,另一個不同類型的中斷又發生了。內核應該盡可能地允許這種情況發生,因為這能維持更多的I/O設備得到處理的機會。因此,中斷處理程序必須編寫成使相應的內核控制路徑能以嵌套的方式執行。當最后一個內核控制路徑終止時,內核必須能恢復被中斷進程的執行,或者,如果中斷信號已導致了重新調度,內核也應能切換到另外的進程。 ◎ 盡管內核在處理前一個中斷時可以接受一個新的中斷,但在內核代碼中還是存在一些臨界區,在臨界區中,中斷必須被禁止。必須盡可能地限制這樣的臨界區,因為根據以前的要求,內核,尤其是中斷處理程序,應該在大部分時間內以開中斷的方式運行。
因為外部設備不能直接發出中斷,而必須通過中斷控制器的標准組件來請求中斷,所以這種請求更正確的叫法是IRQ,或中斷請求(Interrupt Request)。
中斷不能由處理器外部的外設直接產生,而必須借助於一個稱為可編程中斷控制器(programmable interrupt controller, PIC)的標准組件來請求,該組件存在於每個系統中。
外部設備,會有電路連接到用於向中斷控制器發送中斷請求的組件。控制器在執行了各種電工任務之后,將中斷請求轉發到CPU的中斷輸入中。
每個能夠發出中斷請求的硬件設備控制器都有這么一條名為IRQ的輸出線。所有現有的IRQ線都會與這個中斷控制器(PIC)的硬件電路的輸入引腳相連。下面來看看這種中斷控制器執行下列動作:
1) 監視IRQ線,檢查產生的信號 。如果有一條或兩條以上的IRQ線上產生信號,就選擇引腳編號較小的IRQ線。
2) 如果一個引發信號出現在IRQ線上:
a) 把接收到的引發信號轉換成對應的向量(索引)。
b) 把這個向量存放在中斷控器的一個I/O端口,從而允許CPU通過數據總線讀取此向量。
c) 把引發信號發送到處理器的INTR引腳,即產生一個中斷。
d) 等待,直到CPU通過把這個中斷信號寫進可編程中斷控制器的一個I/O端口來確認它;當這種情況發生時,清INTR線。
3) 返回到第一步。
IRQ線是從0開始順序編號的,因此,第一條IRQ線通常表示成IRQ0。與IRQn關聯的Intel缺省向量是n+32。如前所述,通過向中斷控制器端口發布合適的指令,就可以修改IRQ和向量之間的映射。
可以有選擇地禁止每條IRQ線。因此,可以對PIC編程從而禁止IRQ,也就是說,可以告訴PIC停止對給定的IRQ線發布中斷,或者激活它們,禁止的中斷是丟失不了的,它們一旦激活,PIC就又把它們發送到CPU。這個特點被大多數中斷處理程序使用,因為這允許中斷處理程序逐次地處理同一類型的IRQ。
中斷通常分為同步中斷和異步中斷:
同步中斷是當指令執行時由CPU控制單元產生的,之所以稱為同步,是因為只有在一條指令終止執行后CPU才會發出中斷。
異步中斷是由其他硬件設備依照CPU時鍾信號隨機產生的。
在Intel微處理器手冊中:
◎ 把同步中斷稱為異常(exception)
◎ 把異步中斷稱為中斷(interrupt)
這兩類中斷的共同特點是什么?如果CPU當前不處於核心態,則發起從用戶態到核心態的切換。接下來,在內核中執行一個專門的例程,稱為中斷服務例程(interrupt service routine)。或中斷處理程序(interrupthandler)
另一方面,異常是由程序的錯誤產生的,或者是由內核必須處理的異常條件產生的。第一種情況下,內核通過發送一個每個Unix/Linux程序員都熟悉的信號來處理異常。第二種情況下,內核執行恢復異常需要的所有步驟,例如缺頁異常等。
Intel處理器,好像把前32個中斷向量,用來處理異常。另外還有0x80用來處理系統調用。
術語中斷處理程序的使用可能引起岐義。因為它是用於指代CPU對ISR(中斷服務程序)的調用,包括了進入/退出路徑和ISR本身。當然,如果只指代在進入路徑和退出路徑之間進行由C語言實現的例程,將更為准確。
中斷技術上的實現有兩方面:
1) 匯編語言代碼:與處理器高度相關,用於處理特定平台上相關的底層細節;
2) 抽象接口:是設備驅動程序及其他內核代碼安裝和管理IRQ處理程序所需的。
回到 http://blog.csdn.net/zhangskd/article/details/21992933
(1) 硬中斷
由與系統相連的外設(比如網卡、硬盤)自動產生的。主要是用來通知操作系統系統外設狀態的變化。比如當網卡收到數據包
的時候,就會發出一個中斷。我們通常所說的中斷指的是硬中斷(hardirq)。
(2) 軟中斷
為了滿足實時系統的要求,中斷處理應該是越快越好。linux為了實現這個特點,當中斷發生的時候,硬中斷處理那些短時間
就可以完成的工作,而將那些處理事件比較長的工作,放到中斷之后來完成,也就是軟中斷(softirq)來完成。
(注:也就是bottom-half)
軟中斷指令
int是軟中斷指令。
中斷向量表是中斷號和中斷處理函數地址的對應表。
int n - 觸發軟中斷n。相應的中斷處理函數的地址為:中斷向量表地址 + 4 * n。
硬中斷和軟中斷的區別
軟中斷是執行中斷指令產生的,而硬中斷是由外設引發的。
硬中斷的中斷號是由中斷控制器提供的,軟中斷的中斷號由指令直接指出,無需使用中斷控制器。
硬中斷是可屏蔽的,軟中斷不可屏蔽。(下面講到,處理一種硬中斷的時候,屏蔽所有同類型中斷)
硬中斷處理程序要確保它能快速地完成任務,這樣程序執行時才不會等待較長時間,稱為上半部。
軟中斷處理硬中斷未完成的工作,是一種推后執行的機制,屬於下半部。
開關

(1) 硬中斷的開關 簡單禁止和激活當前處理器上的本地中斷: local_irq_disable(); local_irq_enable(); 保存本地中斷系統狀態下的禁止和激活: unsigned long flags; local_irq_save(flags); local_irq_restore(flags); (2) 軟中斷的開關 禁止下半部,如softirq、tasklet和workqueue等: local_bh_disable(); local_bh_enable(); 需要注意的是,禁止下半部時仍然可以被硬中斷搶占。 (3) 判斷中斷狀態 #define in_interrupt() (irq_count()) // 是否處於中斷狀態(硬中斷或軟中斷) #define in_irq() (hardirq_count()) // 是否處於硬中斷 #define in_softirq() (softirq_count()) // 是否處於軟中斷
軟中斷
(1) 定義
軟中斷是一組靜態定義的下半部接口,可以在所有處理器上同時執行,即使兩個類型相同也可以。
但一個軟中斷不會搶占另一個軟中斷,唯一可以搶占軟中斷的是硬中斷。
軟中斷由softirq_action結構體表示:
struct softirq_action { void (*action) (struct softirq_action *); /* 軟中斷的處理函數 */ };
目前已注冊的軟中斷有10種,定義為一個全局數組:
static struct softirq_action softirq_vec[NR_SOFTIRQS]; enum { HI_SOFTIRQ = 0, /* 優先級高的tasklets */ TIMER_SOFTIRQ, /* 定時器的下半部 */ NET_TX_SOFTIRQ, /* 發送網絡數據包 */ NET_RX_SOFTIRQ, /* 接收網絡數據包 */ BLOCK_SOFTIRQ, /* BLOCK裝置 */ BLOCK_IOPOLL_SOFTIRQ, TASKLET_SOFTIRQ, /* 正常優先級的tasklets */ SCHED_SOFTIRQ, /* 調度程序 */ HRTIMER_SOFTIRQ, /* 高分辨率定時器 */ RCU_SOFTIRQ, /* RCU鎖定 */ NR_SOFTIRQS /* 10 */ };
(3) 觸發軟中斷
調用raise_softirq()來觸發軟中斷。
在下列地方,待處理的軟中斷會被檢查和執行:
1. 從一個硬件中斷代碼處返回時
2. 在ksoftirqd內核線程中
3. 在那些顯示檢查和執行待處理的軟中斷的代碼中,如網絡子系統中
而不管是用什么方法喚起,軟中斷都要在do_softirq()中執行。如果有待處理的軟中斷,
do_softirq()會循環遍歷每一個,調用它們的相應的處理程序。
在中斷處理程序中觸發軟中斷是最常見的形式。中斷處理程序執行硬件設備的相關操作,
然后觸發相應的軟中斷,最后退出。內核在執行完中斷處理程序以后,馬上就會調用
do_softirq(),於是軟中斷開始執行中斷處理程序完成剩余的任務。
(4) ksoftirqd內核線程
內核不會立即處理重新觸發的軟中斷。
當大量軟中斷出現的時候,內核會喚醒一組內核線程來處理。
這些線程的優先級最低(nice值為19),這能避免它們跟其它重要的任務搶奪資源。
但它們最終肯定會被執行,所以這個折中的方案能夠保證在軟中斷很多時用戶程序不會
因為得不到處理時間而處於飢餓狀態,同時也保證過量的軟中斷最終會得到處理。
每個處理器都有一個這樣的線程,名字為ksoftirqd/n,n為處理器的編號。
中斷嵌套
http://blog.chinaunix.net/uid-28111044-id-3398997.html
linux中的中斷處理程序是無需重入的。當一個給定的中斷處理程序正在執行時,相應的中斷線在所有處理器上都會被屏蔽掉, 以防止在同一中斷線上接收另一個新的中斷。 通常情況下,所有其他的中斷都是打開的,所以這些不同中斷線上的其他中斷都能被處理 ,但當前中斷線總是被禁止的。由此可以看出,同一個中斷處理程序絕對不會被同時調用以處理嵌套的中斷這極大的簡化了中斷處理 程序的編寫。
搶占
http://blog.csdn.net/vividonly/article/details/6609053
硬中斷可以被另一個優先級比自己高的硬中斷“中斷”,不能被同級(同一種硬中斷)或低級的硬中斷“中斷”,更不能被軟中斷“中斷”。
軟中斷可以被硬中斷“中斷”,但是不會被另一個軟中斷“中斷”。在一個CPU上,軟中斷總是串行執行。所以在單處理器上,對軟中斷的數據結構進行訪問不需要加任何同步原語。
按照Intel的微處理器手冊,同步中斷和異步中斷也分別稱為異常(或者軟件中斷)和中斷。
硬中斷和軟中斷都可以搶占(或者稱為中斷)異常(最典型的是系統調用),但是異常不能搶占硬中斷和軟中斷。
硬中斷和軟中斷(只要是中斷上下文)執行的時候都不允許內核搶占,換句話說,中斷上下文中永遠不允許進程切換。(個人理解,由於中斷處理程序都需要較快地完成,而且中斷處理程序可以嵌套,因此中斷處理程序必須不能阻塞,否則性能就非常不能保證了。