漫畫-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對中斷的響應

具體查看鏈接:

git.kernel.org/pub/scm/

5、後續

6、參考

wowotech.net/irq_subsys

ibm.com/developerworks/

notes.shichao.io/lkd/ch

推薦閱讀:

TAG:Linux內核 | Linux開發 | Linux |