漫畫-Linux中斷子系統綜述
1、中斷引發的面試教訓
2、什麼是中斷?
中斷: (英語:Interrupt)指當出現需要時,CPU暫時停止當前程序的執行轉而執行處理新情況的程序和執行過程。
即在程序運行過程中,系統出現了一個必須由CPU立即處理的情況,此時,CPU暫時中止程序的執行轉而處理這個新的情況的過程就叫做中斷。中斷 在嵌入式軟體中幾乎不能離開它,你看到的幾乎所有的晶元都有中斷功能,不管是裸機程序STC89C51還是嵌入式Linux系統,還是其他的RTOS系統都有中斷。每個外接設備申請一個唯一的中斷號,讓外設發生中斷時,向CPU報告自己的中斷號,CPU知道是哪個設備發生中斷,然後執行相對應的操作。3、為什麼要用中斷?
4、Linux中斷子系統
4.1、中斷系統相關硬體描述
4.1.1、多個Interrupt controller和多個cpu之間的拓撲結構
- 第一種,就是有一個Root GIC(Generic Interrupt Controller)連接多個CPU,然後second GIC 接在 Root GIC上,Sencond GIC只負責上報中斷信息給Root GIC,Root GIC負責接收Second GIC中斷信息然後給CPU彙報中斷信息。
- 第二種就是Root GIC 負責給cpu0-cpu4彙報工作,Second GIC負責給cpu3-cpu7彙報工作。這樣設計的弊端就是Second GIC上的中斷信號不能傳給Cpu0-Cpu3,這樣的設計理論上不是很完美。
4.1.2、Interrupt controller把中斷事件送給哪個CPU?
在 SMP 體系結構中(cpu三大架構 numa smp mpp 之一),我們可以通過調用系統調用和一組相關的宏來設置 CPU 親和力(CPU affinity),將一個或多個進程綁定到一個或多個處理器上運行。
中斷在這方面也毫不示弱,也具有相同的特性。中斷親和力是指將一個或多個中斷源綁定到特定的 CPU 上運行。中斷親和力最初由 Ingo Molnar 設計並實現。
在 /proc/irq 目錄中,對於已經註冊中斷處理程序的硬體設備,都會在該目錄下存在一個以該中斷號命名的目錄 IRQ# ,IRQ# 目錄下有一個 smp_affinity 文件(SMP 體系結構才有該文件),它是一個 CPU 的位掩碼,可以用來設置該中斷的親和力, 默認值為 0xffffffff,表明把中斷髮送到所有的 CPU 上去處理。如果中斷控制器不支持 IRQ affinity,不能改變此默認值,同時也不能關閉所有的 CPU 位掩碼,即不能設置成 0x0。
舉個栗子
我們以網卡(eth1,中斷號 44 )為例,在具有 8 個 CPU 的伺服器上來設置網卡中斷的親和力(以下數據出自內核源碼 DocumentationIRQ-affinity.txt):[root@moon 44]# cat smp_affinity
ffffffff
[root@moon 44]# echo 0f > smp_affinity
[root@moon 44]# cat smp_affinity
0000000f
[root@moon 44]# ping -f h
PING hell (195.4.7.3): 56 data bytes
...
--- hell ping statistics ---
6029 packets transmitted, 6027 packets received, 0% packet loss
round-trip min/avg/max = 0.1/0.1/0.4 ms
[root@moon 44]# cat /proc/interrupts | grep 44:
44: 0 1785 1785 1783 1783 1 1 0 IO-APIC-level eth1
[root@moon 44]# echo f0 > smp_affinity
[root@moon 44]# ping -f h
PING hell (195.4.7.3): 56 data bytes
..
--- hell ping statistics ---
2779 packets transmitted, 2777 packets received, 0% packet loss
round-trip min/avg/max = 0.1/0.5/585.4 ms
[root@moon 44]# cat /proc/interrupts | grep 44:
44: 1068 1785 1785 1784 1784 1069 1070 1069 IO-APIC-level eth1
[root@moon 44]#
在上例中,我們首先只允許在 CPU0-3 上處理網卡中斷,接著運行 ping 程序,不難發現在 CPU4-7 上並沒有對網卡中斷進行處理。然後只在 CPU4-7 上對網卡中斷進行處理, CPU0-3 不對網卡中斷進行任何處理,運行 ping 程序之後,再次查看 /proc/interrupts 文件時,不難發現 CPU4~7 上的中斷次數明顯增加,而 CPU0~3 上的中斷次數沒有太大的變化。
4.2、中斷子系統相關的軟體框架
4.2.1、中斷上半部分和下半部分
中斷處理程序的這兩個目標相互衝突:
- 快點執行
- 執行大量工作
由於這些競爭目標,中斷的處理分為兩部分或一半:
- 上半部分。中斷處理程序是上半部分。上半部分在收到中斷後立即運行,僅執行對時間要求嚴格的工作,例如確認收到中斷或重置硬體。
- 下半部分。可以在以後執行的工作推遲到下半部分。下半部分將在更方便的時間運行,並啟用所有中斷。
4.2.2、中斷分類
中斷如果分為兩大類,那就是同步中斷和非同步中斷,如果根據中斷原因來分,可以分為四種。具體如下圖
4.2.3、中斷上下文
執行中斷處理程序時,內核處於中斷上下文中。
與進程上下文的區別:進程上下文是內核在代表進程執行時所處的操作模式,例如執行系統調用或運行內核線程。
在進程上下文中,current宏(在內核中,可以通過current宏來獲得當前執行進程的task_struct指針)指向關聯的任務。由於進程在進程上下文中耦合到內核,因此進程上下文可以休眠或以其他方式調用調度程序。current宏在發生中斷的時候,它指向中斷的進程。
沒有後備進程,中斷上下文無法休眠,無法重新安排。因此,您無法從中斷上下文中調用某些函數。如果函數休眠,則不能從中斷處理程序中使用它:這限制了可以從中斷處理程序調用的函數。中斷上下文是時間關鍵的,因為中斷處理程序會中斷其他代碼。應該記住,中斷處理程序已經中斷了其他代碼(可能甚至是另一行上的另一個中斷處理程序)。由於非同步性質,所有中斷處理程序必須儘可能快速和簡單。應儘可能地將工作從中斷處理程序中推出,並在下半部分執行,後者在更方便的時間運行。4.2.4、linux kernel的中斷子系統相關的軟體框
架圖如下所示:
由上面的block圖,我們可知linux kernel的中斷子系統分成4個部分:
- (1)硬體無關的代碼,我們稱之Linux kernel通用中斷處理模塊。無論是哪種CPU,哪種controller,其中斷處理的過程都有一些相同的內容,這些相同的內容被抽象出來,和HW無關。此外,各個外設的驅動代碼中,也希望能用一個統一的介面實現irq相關的管理(不和具體的中斷硬體系統以及CPU體系結構相關)這些「通用」的代碼組成了linux kernel interrupt subsystem的核心部分。
- (2)CPU architecture相關的中斷處理。 和系統使用的具體的CPU architecture相關。
- (3)Interrupt controller驅動代碼 。和系統使用的Interrupt controller相關。
- (4)普通外設的驅動。這些驅動將使用Linux kernel通用中斷處理模塊的API來實現自己的驅動邏輯。
4.2.5、中斷調試
- 用示波器查看硬體是否真實產生了中斷
- cat /proc/interrupts 裡面列舉了系統申請的所有中斷,查看自己註冊的中斷是否在裡面
- cat cat /proc/irq/[num]/ 裡面很多可以查看和調試的參數
4.2.6、Linux中斷是否可以嵌套嗎?
它的commit log清晰地解釋中斷嵌套可能引入的一些risk,比如stack溢出等。也就是說,從這個commit開始,實際Linux已經不再支持中斷的嵌套, 也沒有快慢中斷的概念了,IRQF_DISABLED標記也作廢了。在IRQ HANDLER裡面,無論一個中斷設置還是不設置IRQF_DISABLED, 內核都不會開啟CPU對中斷的響應
具體查看鏈接:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e58aa3d2d0cc
5、後續
6、參考
http://www.wowotech.net/irq_subsystem/interrupt_subsystem_architecture.html/comment-page-2
https://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/index.htmlhttps://notes.shichao.io/lkd/ch7/#interrupt-control推薦閱讀: