http://www./forum.php/forum.php?mod=viewthread&tid=543 今天在ChinaUnix論壇內(nèi)核源碼版上與linuxfellow網(wǎng)友討論到hardirq和softirq的問題,雖然在《深入Linux設(shè)備驅(qū)動程序內(nèi)核機制》(以下簡稱“ILDD”)第5章“中斷處理”對此已有詳細(xì)的解讀,但是我覺得還是有必要再花點時間深入探討一下這兩者的區(qū)別。因為此前關(guān)于ARM上的中斷處理我已經(jīng)在另一篇帖子解密ARM based Linux內(nèi)核中斷處理框架 中討論過,所以下面的討論只限于x86 32位系統(tǒng)。 首先給出一個ILDD書中的一個插圖,關(guān)于中斷處理的整體框架: ![]() (圖1) 接下來的一個插圖顯示了內(nèi)核用于標(biāo)識中斷上下文(in_interrupt())的變量preempt_count的布局: ![]() (圖2) 按照x86處理器在外部中斷發(fā)生時的硬件邏輯,在do_IRQ被調(diào)用時,處理器已經(jīng)屏蔽了對外部中斷的響應(yīng)。在圖中我們看到中斷的處理大體上被分成兩部分HARDIRQ和SOFTIRQ,對應(yīng)到代碼層面,do_IRQ()中調(diào)用irq_enter函數(shù)可以看做hardirq 部分的開始,而irq_exit函數(shù)的調(diào)用則標(biāo)志著softirq部分的開始: <arch/x86/kernel/irq.c>
irq_enter()函數(shù)的核心調(diào)用是__irq_enter(),后者的主要作用是在圖2的 preempt_count變量的HARDIRQ部分+1,即標(biāo)識一個hardirq的上下文,所以可以認(rèn)為do_IRQ()調(diào)用irq_enter函數(shù)意味著中斷處理進入hardirq階段。此時處理器響應(yīng)外部中斷的能力依然是被disable掉的(EFLAG.IF=0),因為ISR基本上屬于設(shè)備驅(qū)動程序涉足的領(lǐng)域,內(nèi)核無法保證在設(shè)備驅(qū)動程序的ISR中會否將EFLAG.IF置1(此處涉及可能的中斷嵌套以及中斷棧溢出問題,可以參考ARM中斷處理的那個帖子),所以我們會在內(nèi)核代碼中看到內(nèi)核開發(fā)者為了盡可能避免非受控的ISR部分給系統(tǒng)帶來的損害所做的努力。按照現(xiàn)在內(nèi)核的設(shè)計理念,在 hardirq部分最好不要打開中斷,所以處在hardirq上下文中的設(shè)備驅(qū)動程序的ISR應(yīng)該盡可能快地返回(所謂只完成最關(guān)鍵的任務(wù)),而將耗時的中斷處理善后工作留到softirq部分,因為在softirq部分,內(nèi)核會使EFLAG.IF=1,所以也意味著softirq部分可以隨時被外部中斷所打斷。 下面我們重點討論一下softirq部分的實現(xiàn)原理,do_IRQ()中調(diào)用irq_exit函數(shù)標(biāo)志softirq部分的開始。 irq_exit()函數(shù)會首先在圖2的preempt_count變量的HARDIRQ部分-1,目的是清除hardirq的上下文標(biāo)記。然后它有個關(guān)鍵的調(diào)用invoke_softirq,用于實際的softirq處理工作: <kernel/softirq.c>
第一個條件,主要用來防止softirq部分的重入,因為一旦有pending的softirq需要處理,那么invoke_softirq()的調(diào)用 (實際的工作發(fā)生在__do_softirq函數(shù)中)首先會將圖2中SOFTIRQ部分+1,這樣若在當(dāng)前正在處理softirq過程中發(fā)生了外部中斷,hardirq部分標(biāo)識了一個pending softirq,那么在irq_exit函數(shù)中將直接返回,而不會調(diào)用到invoke_softirq。 softirq部分的核心代碼段如下: <kernel/softirq.c>
對每個類型的softirq的處理發(fā)生在上面的do...while...循環(huán)中,原理其實非常簡單,為節(jié)省文字,用下面一個草圖來做說明(圖3): ![]() 所以do...while...循環(huán)實際上是從bit 0遍歷__softirq_pending變量,目前該變量的0~9分別對應(yīng)10個不同類型的softirq,每個softirq對應(yīng)不同的處理函數(shù),比如HI_SOFTIRQ對應(yīng)的action為tasklet_hi_action,它與TASKLET_SOFTIRQ的action的原理完全一樣,也就是我們平常所說的tasklet。__softirq_pending是個per-CPU型的變量,因為SMP系統(tǒng)中每個處理器都可以獨立處理各自到來的外部中斷,也都對應(yīng)有各自的hardirq棧和softirq棧,詳見Linux內(nèi)核中的中斷棧與內(nèi)核棧的補充說明一貼。另外,在前面的帖子中我們一直說hardirq部分標(biāo)識一個softirq,何謂標(biāo)識一個softirq?其實就是調(diào)用tasklet_schedule()來把TASKLET_SOFTIRQ位置1. 在ILDD一書中實際上將tasklet分成兩部分,分別放在第5章”中斷處理“和第6章”延遲操作“,第5章側(cè)重討論softirq的機制,而第6章則重點討論tasklet。 (原帖首發(fā):http://www./forum.php/forum.php?mod=viewthread&tid=543) |
|