萬盛學電腦網

 萬盛學電腦網 >> 服務器教程 >> linux中斷--中斷嵌套&中斷請求丟失

linux中斷--中斷嵌套&中斷請求丟失

   關於中斷嵌套:

  在linux內核裡,如果驅動在申請注冊中斷的時候沒有特別的指定,do_irq在做中斷響應的時候,是開啟中斷的,如果在驅動的中斷處理函數正在執行的過程中,出現同一設備的中斷或者不同設備的中斷,這時候新的中斷會被立即處理,還是被pending,等當前中斷處理完成後,再做處理。

  在2.4和2.6內核裡,關於這一塊是否有什麼不同。

  一般申請中斷的時候都允許開中斷,即不使用SA_INTERRUPT標志。如果允許共享則加上 SA_SHIRQ,如果可以為內核熵池提供熵值(譬如你寫的驅動是ide之類的驅動),則再加上 SA_SAMPLE_RANDOM標志。這是普通的中斷請求過程。對於這種一般情況,只要發生中斷,就可以搶占內核,即使內核正在執行其他中斷函數。這裡有兩點說明:一是因為linux不支持 中斷優先級,因此任何中斷都可以搶占其他中斷,但是同種類型的中斷(即定義使用同一個 中斷線的中斷)不會發生搶占,他們會在執行本類型中斷的時候依次被調用執行。二是所謂 “只要發生中斷,就可以搶占內核”這句是有一定限制的,因為當中斷發生的時候系統由中斷門 進入時自動關中斷(對於x86平台就是將eflags寄存器的if位置為0),只有當中斷函數被執行 (handle_IRQ_event)的過程中開中斷之後才能有搶占。 對於同種類型的中斷,由於其使用同樣的idt表項,通過其狀態標志(IRQ_PENDING和 IRQ_INPROGRESS)可以防止同種類型的中斷函數執行(注意:是防止handle_IRQ_event被重入, 而不是防止do_IRQ函數被重入),對於不同的中斷,則可以自由的嵌套。因此,所謂中斷嵌套, 對於不同的中斷是可以自由嵌套的,而對於同種類型的中斷,是不可以嵌套執行的。

  以下簡單解釋一下如何利用狀態標志來防止同種類型中斷的重入:

  當某種類型的中斷第一次發生時,首先其idt表項的狀態位上被賦予IRQ_PENDING標志,表示有待處理。 然後將中斷處理函數action置為null,然後由於其狀態沒有IRQ_INPROGRESS標志(第一次),故將其狀態置上IRQ_INPROGRESS並去處IRQ_PENDING標志,同時將action賦予相應的中斷處理函數指針(這裡是一個重點,linux很巧妙的用法,隨後說明)。這樣,後面就可以順利執行handle_IRQ_event進行中斷處理,當在handle_IRQ_event中開中斷後,如果有同種類型的中斷發生,則再次進入do_IRQ函數,然後其狀態位上加上IRQ_PENDING標志,但是由於前一次中斷處理中加上的IRQ_INPROGRESS沒有被清除,因此這裡無法清除IRQ_PENDING標志,因此action還是為null,這樣就無法再次執行handle_IRQ_event函數。從而退出本次中斷處理,返回上一次的中斷處理函數中,即繼續執行handle_IRQ_event函數。當handle_IRQ_event返回時檢查IRQ_PENDING標志,發現存在這個標志,說明handle_IRQ_event執行過程中被中斷過,存在未處理的同類中斷,因此再次循環執行handle_IRQ_event函數。直到不存在IRQ_PENDING標志為止。

  2.4和2.6的差別,就我來看,主要是在2.6中一進入do_IRQ,多了一個關閉內核搶占的動作,同時在處理中多了一種對IRQ_PER_CPU類型的中斷的處理,其他沒有什麼太大的改變。這類IRQ_PER_CPU的中斷主要用在smp環境下將中斷綁定在某一個指定的cpu上。例如arch/ppc/syslib/open_pic.c中的openpic_init中初始化ipi中斷的時候。

  其實簡單的說,中斷可以嵌套,但是同種類型的中斷是不可以嵌套的,因為在IRQ上發生中斷,在中斷響應的過程中,這個IRQ是屏蔽的,也就是這個IRQ的中斷是不能被發現的。

  同時在內核的臨界區內,中斷是被禁止的

  關於do_IRQ可能會丟失中斷請求:

  do_IRQ函數是通過在執行完handle_IRQ_event函數之後判斷status是否被設置了IRQ_PENDING標志來判斷是否還有沒有被處理的同一通道的中斷請求。 但是這種方法只能判斷是否有,而不能知道有多少個未處理的統一通道中斷請求。也就是說,假如在第一個中斷請求執行handle_IRQ_event函數的過程中來了同一通道的兩個或更多中斷請求,而這些中斷不會再來,那麼僅僅通過判斷status是否設置了IRQ_PENDING標志不知道到底有多少個未處理的中斷,handle_IRQ_event只會被再執行一次。

  這算不算是個bug呢? 不算,只要知道有中斷沒有處理就OK了,知道1個和知道N個,本質上都是一樣的。作為外設,應當能夠處理自己中斷未被處理的情況。

  不可能丟失的,在每一個中斷描述符的結構體內,都有一個鏈表,鏈表中存放著服務例程序

  關於中斷中使用的幾個重要概念和關系:

  一、基本概念

  1.

  產生的位置發生的時刻時序

  中斷CPU外部隨機異步

  異常CPU正在執行的程序一條指令終止執行後同步

  2.由中斷或異常執行的代碼不是一個進程,而是一個內核控制路徑,代表中斷發生時正在運行的進程的執行

  中斷處理程序與正在運行的程序無關

  引起異常處理程序的進程正是異常處理程序運行時的當前進程

  二、特點

  1.(1)盡可能快

  (2)能以嵌套的方式執行,但是同種類型的中斷不可以嵌套

  (3)盡可能地限制臨界區,因為在臨界區中,中斷被禁止

  2.大部分異常發生在用戶態,缺頁異常是唯一發生於內核態能觸發的異常

  缺頁異常意味著進程切換,因此中斷處理程序從不執行可以導致缺頁的操作

  3.中斷處理程序運行於內核態

  中斷發生於用戶態時,要把進程的用戶空間堆棧切換到進程的系統空間堆棧,剛切換時,內核堆棧是空的

  中斷發生於內核態時, 不需要堆棧空間的切換

  三、分類

  1.中斷的分類:可屏蔽中斷、不可屏蔽中斷

  2.異常的分類:

  分類解決異常的方法舉例

  故障那條指令會被重新執行缺頁異常處理程序

  陷阱會從下一條指令開始執行調試程序

  異常中止強制受影響的進程終止發生了一個嚴重的錯誤

  四、IRQ

  1.硬件設備控制器通過IRQ線向CPU發出中斷,可以通過禁用某條IRQ線來屏蔽中斷。

  2.被禁止的中斷不會丟失,激活IRQ後,中斷還會被發到CPU

  3.激活/禁止IRQ線 != 可屏蔽中斷的 全局屏蔽/非屏蔽

  可以有選擇地禁止每條IRQ線。因此,可以對PIC編程從而禁止IRQ,也就是說,可以告訴PIC停止對給定的IRQ線發布中斷,或者激活它們。禁止的中斷時丟失不了的,它們一旦被激活,PIC就又把它們發送到CPU。這個特點被大多數中斷處理程序使用,因為這允許中斷處理程序逐次地處理同一類型的IRQ

  假定CPU有一條激活的IRQ線。一個硬件設備出現在這條IRQ線程上,且多APIC系統選擇我們的CPU處理中斷。在CPU應答中斷前,這條IRQ線被另一個CPU屏蔽掉;結果,IRQ_DISABLED標志被設置。隨後,我們的CPU開始處理掛起的中斷;因此,do_IRQ()函數應答這個中斷,然後返回,但沒有執行中斷服務例程,因為它發現IRQ_DISABLED標志被設置了,因此,在IRQ線禁用之前出現的中斷丟失了。

  為了應付這種局面,內核用來激活IRQ線的enable_irq()函數先檢查是否發生了中斷丟失,如果是,該函數就強迫硬件讓丟失的中斷再產生一次

  它們最大的不同是上半部分不可中斷,而下半部分可中斷

  五、中斷描述符表IDT

  1.基本概念

  中斷描述符表是一個系統表,它與每一個中斷或異常向量相聯系,每一個向量在表中有相應的中斷或異常處理程序入口地址。

  在允許發生中斷以前,必須適當地初始化IDT

  TSS只能位於GDT中,IDT能位於內存的任何的地方

  2.中斷描述符

  硬件提供的中斷描述符:

  (1)任務門:中斷信號發生時,必須取代當前進程的那個進程的TSS選擇符存放在任務門中

  (2)中斷門:包含段選擇符和中斷處理程序的段內偏移

  (3)陷阱門:與中斷門的唯一區別是,通過中斷門進入服務程序後,自動關中斷,而通過陷阱門進入服務程序不自動關中斷

  Linux中使用的中斷描述符:

  中斷描述符的類型用戶態能否訪問用戶態的訪問方式能激活的程序

  中斷門否 所有的Linux中斷處理程序

  系統門是into、bound、int $0x80向量號為4,5,128的三個Linux異常處理程序

  系統中斷門是int 3與向量3相關的異常處理程序

  陷阱門否 大部分Linux異常處理程序

  任務門否 Linux對Double fault異常的處理程序

  Linux中的系統門、系統中斷門、陷阱門使用的都是硬件中的陷阱門

  Linux利用中斷門處理中斷,利用陷阱門處理異常

  Double fault是唯一用任務處理的異常

  3.中斷向量與中斷和異常的關系

  (1)每個中斷和異常是由0-255之間的一個數來標識的,這個數就是1中的中斷向量

  (2)大約有20種異常,內核為每一個異常分配了一種中斷/異常向量分別是0-19

  (3)0x80是系統調用的中斷向量

  (4)32-255是內核為什麼中斷分配的中斷向量。然而,224個中斷向量顯然不夠,因此系統為每個中斷向量設置一個隊列,根據每個中斷源所使用的中斷向量,將其中斷服務程序掛到相應的隊列中。中斷發生時,先執行與中斷向量相對應的一段總服務程序,再根據具體的中斷源設備號在其所屬的隊列找到特定的中斷服務程序加以執行。

  4.中斷向量、與中斷向量相對應的總服務程序、某個中斷源的中斷服務程序之間的關系如圖所示:

  (1)irq_desc是中斷向量描述符隊列(中斷描述符是INT的一項,中斷向量描述符是一個數據結構,用於描述與中斷向量相關的服務程序)

  (2)irq_desc_t是中斷向量描述符的數據結構

  (3)irqaction

copyright © 萬盛學電腦網 all rights reserved