關(guān)于中斷嵌套:
在linux內(nèi)核里,如果驅(qū)動(dòng)在申請(qǐng)注冊(cè)中斷的時(shí)候沒(méi)有特別的指定,do_irq在做中斷響應(yīng)的時(shí)候,是開(kāi)啟中斷的,如果在驅(qū)動(dòng)的中斷處理函數(shù)正在執(zhí)行的過(guò)程中,出現(xiàn)同一設(shè)備的中斷或者不同設(shè)備的中斷,這時(shí)候新的中斷會(huì)被立即處理,還是被pending,等當(dāng)前中斷處理完成后,再做處理,
linux中斷中斷嵌套&中斷請(qǐng)求丟失
。在2.4和2.6內(nèi)核里,關(guān)于這一塊是否有什么不同。
一般申請(qǐng)中斷的時(shí)候都允許開(kāi)中斷,即不使用SA_INTERRUPT標(biāo)志。如果允許共享則加上 SA_SHIRQ,如果可以為內(nèi)核熵池提供熵值(譬如你寫(xiě)的驅(qū)動(dòng)是ide之類(lèi)的驅(qū)動(dòng)),則再加上 SA_SAMPLE_RANDOM標(biāo)志。這是普通的中斷請(qǐng)求過(guò)程。對(duì)于這種一般情況,只要發(fā)生中斷,就可以搶占內(nèi)核,即使內(nèi)核正在執(zhí)行其他中斷函數(shù)。這里有兩點(diǎn)說(shuō)明:一是因?yàn)閘inux不支持 中斷優(yōu)先級(jí),因此任何中斷都可以搶占其他中斷,但是同種類(lèi)型的中斷(即定義使用同一個(gè) 中斷線的中斷)不會(huì)發(fā)生搶占,他們會(huì)在執(zhí)行本類(lèi)型中斷的時(shí)候依次被調(diào)用執(zhí)行。二是所謂 “只要發(fā)生中斷,就可以搶占內(nèi)核”這句是有一定限制的,因?yàn)楫?dāng)中斷發(fā)生的時(shí)候系統(tǒng)由中斷門(mén) 進(jìn)入時(shí)自動(dòng)關(guān)中斷(對(duì)于x86平臺(tái)就是將eflags寄存器的if位置為0),只有當(dāng)中斷函數(shù)被執(zhí)行 (handle_IRQ_event)的過(guò)程中開(kāi)中斷之后才能有搶占。 對(duì)于同種類(lèi)型的中斷,由于其使用同樣的idt表項(xiàng),通過(guò)其狀態(tài)標(biāo)志(IRQ_PENDING和 IRQ_INPROGRESS)可以防止同種類(lèi)型的中斷函數(shù)執(zhí)行(注意:是防止handle_IRQ_event被重入, 而不是防止do_IRQ函數(shù)被重入),對(duì)于不同的中斷,則可以自由的嵌套。因此,所謂中斷嵌套, 對(duì)于不同的中斷是可以自由嵌套的,而對(duì)于同種類(lèi)型的中斷,是不可以嵌套執(zhí)行的。
以下簡(jiǎn)單解釋一下如何利用狀態(tài)標(biāo)志來(lái)防止同種類(lèi)型中斷的重入:
當(dāng)某種類(lèi)型的中斷第一次發(fā)生時(shí),首先其idt表項(xiàng)的狀態(tài)位上被賦予IRQ_PENDING標(biāo)志,表示有待處理。 然后將中斷處理函數(shù)action置為null,然后由于其狀態(tài)沒(méi)有IRQ_INPROGRESS標(biāo)志(第一次),故將其狀態(tài)置上IRQ_INPROGRESS并去處IRQ_PENDING標(biāo)志,同時(shí)將action賦予相應(yīng)的中斷處理函數(shù)指針(這里是一個(gè)重點(diǎn),linux很巧妙的用法,隨后說(shuō)明)。這樣,后面就可以順利執(zhí)行handle_IRQ_event進(jìn)行中斷處理,當(dāng)在handle_IRQ_event中開(kāi)中斷后,如果有同種類(lèi)型的中斷發(fā)生,則再次進(jìn)入do_IRQ函數(shù),然后其狀態(tài)位上加上IRQ_PENDING標(biāo)志,但是由于前一次中斷處理中加上的IRQ_INPROGRESS沒(méi)有被清除,因此這里無(wú)法清除IRQ_PENDING標(biāo)志,因此action還是為null,這樣就無(wú)法再次執(zhí)行handle_IRQ_event函數(shù)。從而退出本次中斷處理,返回上一次的中斷處理函數(shù)中,即繼續(xù)執(zhí)行handle_IRQ_event函數(shù)。當(dāng)handle_IRQ_event返回時(shí)檢查IRQ_PENDING標(biāo)志,發(fā)現(xiàn)存在這個(gè)標(biāo)志,說(shuō)明handle_IRQ_event執(zhí)行過(guò)程中被中斷過(guò),存在未處理的同類(lèi)中斷,因此再次循環(huán)執(zhí)行handle_IRQ_event函數(shù)。直到不存在IRQ_PENDING標(biāo)志為止。
2.4和2.6的差別,就我來(lái)看,主要是在2.6中一進(jìn)入do_IRQ,多了一個(gè)關(guān)閉內(nèi)核搶占的動(dòng)作,同時(shí)在處理中多了一種對(duì)IRQ_PER_CPU類(lèi)型的中斷的處理,其他沒(méi)有什么太大的改變。這類(lèi)IRQ_PER_CPU的中斷主要用在smp環(huán)境下將中斷綁定在某一個(gè)指定的cpu上。例如arch/ppc/syslib/open_pic.c中的openpic_init中初始化ipi中斷的時(shí)候。
其實(shí)簡(jiǎn)單的說(shuō),中斷可以嵌套,但是同種類(lèi)型的中斷是不可以嵌套的,因?yàn)樵贗RQ上發(fā)生中斷,在中斷響應(yīng)的過(guò)程中,這個(gè)IRQ是屏蔽的,也就是這個(gè)IRQ的中斷是不能被發(fā)現(xiàn)的。
同時(shí)在內(nèi)核的臨界區(qū)內(nèi),中斷是被禁止的
關(guān)于do_IRQ可能會(huì)丟失中斷請(qǐng)求:
do_IRQ函數(shù)是通過(guò)在執(zhí)行完handle_IRQ_event函數(shù)之后判斷status是否被設(shè)置了IRQ_PENDING標(biāo)志來(lái)判斷是否還有沒(méi)有被處理的同一通道的中斷請(qǐng)求,
電腦資料
《linux中斷中斷嵌套&中斷請(qǐng)求丟失》(http://www.ishadingyu.com)。 但是這種方法只能判斷是否有,而不能知道有多少個(gè)未處理的統(tǒng)一通道中斷請(qǐng)求。也就是說(shuō),假如在第一個(gè)中斷請(qǐng)求執(zhí)行handle_IRQ_event函數(shù)的過(guò)程中來(lái)了同一通道的兩個(gè)或更多中斷請(qǐng)求,而這些中斷不會(huì)再來(lái),那么僅僅通過(guò)判斷status是否設(shè)置了IRQ_PENDING標(biāo)志不知道到底有多少個(gè)未處理的中斷,handle_IRQ_event只會(huì)被再執(zhí)行一次。這算不算是個(gè)bug呢? 不算,只要知道有中斷沒(méi)有處理就OK了,知道1個(gè)和知道N個(gè),本質(zhì)上都是一樣的。作為外設(shè),應(yīng)當(dāng)能夠處理自己中斷未被處理的情況。
不可能丟失的,在每一個(gè)中斷描述符的結(jié)構(gòu)體內(nèi),都有一個(gè)鏈表,鏈表中存放著服務(wù)例程序
關(guān)于中斷中使用的幾個(gè)重要概念和關(guān)系:
一、基本概念
1.
產(chǎn)生的位置發(fā)生的時(shí)刻時(shí)序中斷CPU外部隨機(jī)異步異常CPU正在執(zhí)行的程序一條指令終止執(zhí)行后同步2.由中斷或異常執(zhí)行的代碼不是一個(gè)進(jìn)程,而是一個(gè)內(nèi)核控制路徑,代表中斷發(fā)生時(shí)正在運(yùn)行的進(jìn)程的執(zhí)行
中斷處理程序與正在運(yùn)行的程序無(wú)關(guān)
引起異常處理程序的進(jìn)程正是異常處理程序運(yùn)行時(shí)的當(dāng)前進(jìn)程
二、特點(diǎn)
1.(1)盡可能快
(2)能以嵌套的方式執(zhí)行,但是同種類(lèi)型的中斷不可以嵌套
(3)盡可能地限制臨界區(qū),因?yàn)樵谂R界區(qū)中,中斷被禁止
2.大部分異常發(fā)生在用戶態(tài),缺頁(yè)異常是唯一發(fā)生于內(nèi)核態(tài)能觸發(fā)的異常
缺頁(yè)異常意味著進(jìn)程切換,因此中斷處理程序從不執(zhí)行可以導(dǎo)致缺頁(yè)的操作
3.中斷處理程序運(yùn)行于內(nèi)核態(tài)
中斷發(fā)生于用戶態(tài)時(shí),要把進(jìn)程的用戶空間堆棧切換到進(jìn)程的系統(tǒng)空間堆棧,剛切換時(shí),內(nèi)核堆棧是空的
中斷發(fā)生于內(nèi)核態(tài)時(shí), 不需要堆?臻g的切換
三、分類(lèi)
1.中斷的分類(lèi):可屏蔽中斷、不可屏蔽中斷
2.異常的分類(lèi):
分類(lèi)解決異常的方法舉例故障那條指令會(huì)被重新執(zhí)行缺頁(yè)異常處理程序陷阱會(huì)從下一條指令開(kāi)始執(zhí)行調(diào)試程序異常中止強(qiáng)制受影響的進(jìn)程終止發(fā)生了一個(gè)嚴(yán)重的錯(cuò)誤四、IRQ
1.硬件設(shè)備控制器通過(guò)IRQ線向CPU發(fā)出中斷,可以通過(guò)禁用某條IRQ線來(lái)屏蔽中斷。
2.被禁止的中斷不會(huì)丟失,激活I(lǐng)RQ后,中斷還會(huì)被發(fā)到CPU
3.激活/禁止IRQ線 != 可屏蔽中斷的 全局屏蔽/非屏蔽
可以有選擇地禁止每條IRQ線。因此,可以對(duì)PIC編程從而禁止IRQ,也就是說(shuō),可以告訴PIC停止對(duì)給定的IRQ線發(fā)布中斷,或者激活它們。禁止的中斷時(shí)丟失不了的,它們一旦被激活,PIC就又把它們發(fā)送到CPU。這個(gè)特點(diǎn)被大多數(shù)中斷處理程序使用,因?yàn)檫@允許中斷處理程序逐次地處理同一類(lèi)型的IRQ
假定CPU有一條激活的IRQ線。一個(gè)硬件設(shè)備出現(xiàn)在這條IRQ線程上,且多APIC系統(tǒng)選擇我們的CPU處理中斷。在CPU應(yīng)答中斷前,這條IRQ線被另一個(gè)CPU屏蔽掉;結(jié)果,IRQ_DISABLED標(biāo)志被設(shè)置。隨后,我們的CPU開(kāi)始處理掛起的中斷;因此,do_IRQ()函數(shù)應(yīng)答這個(gè)中斷,然后返回,但沒(méi)有執(zhí)行中斷服務(wù)例程,因?yàn)樗l(fā)現(xiàn)IRQ_DISABLED標(biāo)志被設(shè)置了,因此,在IRQ線禁用之前出現(xiàn)的中斷丟失了。
為了應(yīng)付這種局面,內(nèi)核用來(lái)激活I(lǐng)RQ線的enable_irq()函數(shù)先檢查是否發(fā)生了中斷丟失,如果是,該函數(shù)就強(qiáng)迫硬件讓丟失的中斷再產(chǎn)生一次
它們最大的不同是上半部分不可中斷,而下半部分可中斷