最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

理解內(nèi)核的硬軟中斷(詳細(xì)講解~)

2022-10-12 21:38 作者:補給站Linux內(nèi)核  | 我要投稿

(一)硬中斷

中斷基礎(chǔ)

關(guān)于中斷的概念,很多人還停留在書本上,我們結(jié)合實際的操作系統(tǒng)來理解。先給出硬中斷和軟中斷的介紹:

硬中斷:外設(shè)處理過程中產(chǎn)生的,通過硬件控制器通知cpu自己的狀態(tài)變化。

軟中斷:硬中斷應(yīng)該很快完成,才能有快的響應(yīng),所以將一部分可以延遲的處理從硬中斷里獨立出來,當(dāng)硬中斷處理完之后再處理這部分,就是軟中斷。

下面,我們以linux為例,分析一下中斷的嵌套情況。


硬中斷的嵌套

《深入理解linux內(nèi)核》中講過,linux下的硬中斷處理是可以嵌套的,并且沒有優(yōu)先級。也就是說,一個中斷可以打斷正在執(zhí)行的中斷(同種中斷除外,后文會講)。無優(yōu)先級地支持硬中斷嵌套有兩個主要原因:短時間內(nèi)接受更多的中斷,可以有大的設(shè)備控制吞吐量;無優(yōu)先級可以簡化內(nèi)核,提高移植性。

硬中斷的具體linux實現(xiàn)流程是:(參考linux kernel 4.0)

硬中斷的匯編處理->do_IRQ->handle_irq->handle_edge_irq(handle_level_irq)->handle_irq_event->具體設(shè)備的硬中斷處理

同種中斷不嵌套是通過設(shè)置該種中斷的數(shù)據(jù)結(jié)構(gòu)的IRQD_IRQ_INPROGRESS標(biāo)志位來屏蔽(本cpu和其它cpu的同種中斷)的,置位表示已經(jīng)在處理該種中斷了,同種中斷會判斷此標(biāo)志而退出,同時置上IRQS_PENDING標(biāo)志位表示此種中斷還需繼續(xù)處理。這個過程是不是很類似于軟中斷的防止嵌套的套路?我們的理解是:它們本質(zhì)是一樣的,只是硬中斷這里防的是同種類型(即使是不同cpu上),而軟中斷那里防的是所有類型(只在同一個cpu上,還記得軟中斷基于per-cpu的數(shù)據(jù)結(jié)構(gòu)吧),但防范機制是一樣的!

據(jù)此,我們可以推出硬中斷的最大的嵌套層數(shù)是:硬中斷的類型數(shù)(同時需要未設(shè)置IRQF_DISABLED標(biāo)志位,馬上講到)。

2009年開源社區(qū)已經(jīng)開始討論默認(rèn)設(shè)置IRQF_DISABLED標(biāo)志位(http://lwn.net/Articles/321663/):如果設(shè)置了IRQF_DISABLED,那么該硬中斷不允許被打斷,也就禁止了嵌套。實際應(yīng)用中,由于多隊列網(wǎng)卡(一個網(wǎng)卡不再僅僅產(chǎn)生一種中斷了,可能多達(dá)數(shù)十個?。?dǎo)致中斷棧溢出,故于2010年終于關(guān)閉硬中斷嵌套機制了,具體參考patch:e58aa3d2d0cc01ad8d6f7f640a0670433f794922(genirq: Run irqhandlers with interrupts disabled)

想想,有很多非常重要的事要做,是逐個做還是打斷式并行做?如果是人去做的話,肯定會選逐個做。機器也一樣?打斷式并行做導(dǎo)致記錄現(xiàn)場的存儲量過大而崩潰。。。

硬中斷的提速很重要,不管是拆分出軟中斷還是中斷線程化,都是希望硬中斷不要過多影響用戶進程(特別是實時進程),畢竟有些硬中斷和某些高優(yōu)先級用戶進程相比,其實并不重要。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)??


同種軟中斷不可以嵌套,但可以并行在不同cpu上,即使是同種類型。詳細(xì)講解請參考我們之前的《理解linux內(nèi)核的軟中斷(上/下)》。

總結(jié)

簡潔地講解硬中斷和軟中斷的嵌套情況,硬中斷的目標(biāo)很明確:要快,不能影響系統(tǒng)其它高優(yōu)先級進程。硬中斷的詳細(xì)細(xì)節(jié)(包括PIC/APIC/EDGE/LEVEL等)我們以后再講。(純屬我們自己理解,如有不妥,還望指正)

軟中斷介紹

把可以延遲的處理從硬中斷處理程序獨立出來,這樣這個處理可以在開中斷的情況下運行,這個處理就是軟中斷。可見,軟中斷的這種脫離可以大大縮短硬中斷的響應(yīng)時間,對于很多實時應(yīng)用來說及其重要。


(二)軟中斷

我們本文只談軟中斷,至于tasklet、workqueue等我們以后再談。我們在講述軟中斷流程(參考linux kernel 4.0)時會嘗試深入理解其中的各個細(xì)節(jié)之處,分享我們自己的理解(如果不正,還望指出,謝謝)。

軟中斷數(shù)據(jù)結(jié)構(gòu)的定義

軟中斷目前有10(由NR_SOFTIRQS定義)個,通過softirq_vec[NR_SOFTIRQS]數(shù)組來管理這些軟中斷,全部cpu共用。

軟中斷的注冊

通過open_softirq()將具體的軟中斷處理函數(shù)和軟中斷編號綁定。如網(wǎng)絡(luò)系統(tǒng)注冊了收發(fā)包的軟中斷處理函數(shù):

軟中斷的激活

每個cpu都有一個32bit的位圖(即__softirq_pending)來維護本cpu上的軟中斷是否激活。

軟中斷的激活時機之一:irq_exit

irq_exit函數(shù)里可能會激活軟中斷,激活條件是:

不在硬中斷里并且不在軟中斷里并且本cpu的__softirq_pending中有置位。

由這個條件,我們可以知道,軟中斷和硬中斷在這里是同等對待(在in_interrupt里)的,體現(xiàn)都是中斷處理這一個本質(zhì)。不能在硬中斷里的條件,表明必須優(yōu)先性,必須硬中斷全部處理完,才考慮軟中斷;不能在軟中斷里的條件,表明屏蔽了軟中斷的嵌套。

invoke_softirq函數(shù)的處理是,要么(先喚醒ksoftirqd)將軟中斷交由ksoftirqd專門線程處理,要么直接調(diào)用__do_softirq即時處理(當(dāng)然,即時處理要區(qū)分是在哪個棧上:是當(dāng)前棧上還是在獨立的軟中斷棧上)。

我們看看即時處理這個流程。local_softirq_pending前肯定會清除preempt_count中的硬中斷位,如果此時preempt_count里沒有軟中斷位則可以被搶占(即時關(guān)閉硬中斷)。在進入到__do_softirq處理各個軟中斷期間,肯定是禁止搶占了。在硬(軟)中斷上下文里的搶占是眾所周知不被允許的:會讓被中斷的進程執(zhí)行時間不確定,也是不公平的(也就是說,不要在硬中斷和軟中斷的處理中有調(diào)度離開的意向)。

軟中斷的激活時機之二:raise_softirq

網(wǎng)卡收包方式從非NAPI進化到NAPI方式,就充分展示了軟中斷的優(yōu)點:把收報任務(wù)最大程度地交給軟中斷處理,最大程度簡化硬中斷處理。這種進化,我們以后再講。

raise_softirq函數(shù)會調(diào)用__raise_softirq_irqoff函數(shù),在指定cpu的__softirq_pending位圖上置位相應(yīng)的軟中斷。raise_softirq_irqoff函數(shù)和raise_softirq函數(shù)的區(qū)別是關(guān)中斷的操作是否已經(jīng)完成了。置位位圖是一個競爭操作,所有硬中斷里都可能做,所以得保證在關(guān)中斷的情況下完成。

軟中斷的激活之三:ksoftirqd

每個cpu都有一個ksoftirqd線程在軟中斷量大時專門處理軟中斷:

ksoftirqd線程的核心函數(shù)run_ksoftirqd的(循環(huán))處理是:關(guān)中斷看本cpu的__softirq_pending的置位情況,如有則執(zhí)行__do_softirqd(),執(zhí)行完開中斷)。這個執(zhí)行很順暢,因為是在該線程自己的棧上,不會有影響用戶進程的問題。

這里有個疑問,此處以前是關(guān)搶占保護,現(xiàn)在是關(guān)中斷的保護了(參考2012年的patch 3e339b,softirq: Use hotplugthread infrastructure)?我們的理解是:關(guān)搶占的保護方式,會讓后續(xù)更多的軟中斷由ksoftirqd處理,不符合ksoftirqd的輔助地位。就處理軟中斷的地位而言,應(yīng)該是irq_exit的為主,ksoftirqd的為輔。)

ksoftirqd里也可以看到,在執(zhí)行軟中斷前是可以被搶占的,但是一旦開始執(zhí)行就不能被搶占了(和上面的調(diào)度之一:irq_exit中的講述的思想是一致的)。就是說,軟中斷和硬中斷的處理思想是一致的:執(zhí)行期間不允許發(fā)生調(diào)度!

上述不能搶占的原因其實就是類似事務(wù)性的一個原則:一旦開始不能停止。另外一個原因是,執(zhí)行的是用戶自定義的硬(軟)中斷程序,操作具有不確定性,如果讓這些操作期間具有調(diào)度可能,則會脫離內(nèi)核的控制范圍。

軟中斷的激活之四:其他地方

比如netif_rx_ni(),執(zhí)行do_softirq前關(guān)搶占,不能在執(zhí)行軟中斷期間調(diào)度。

軟中斷的激活之五: local_bh_enable時

想想,如果異常和軟中斷有共享數(shù)據(jù)的話,異常處理走到此共享數(shù)據(jù)的臨界區(qū)時需要關(guān)軟中斷,但不需要關(guān)硬中斷。那么當(dāng)走完臨界區(qū)時,需要開軟中斷,此時就是一個激活時機(看preempt_count了,其實可能也是一個搶占時機)。

用“激活”而不是“調(diào)用”的原因是外圍處理僅修改本cpu的__softirq_pending位圖,最后由核心機制(比如ksoftirqd、能通過in_interrupt檢查的軟中斷處理)真正處理,而這就是軟中斷的理念:讓硬中斷(或者其它)更快執(zhí)行,所以不會采用直接調(diào)用的方式。

“激活”的原則是誰激活,誰處理,哪個cpu上的硬中斷帶來的軟中斷就由哪個cpu處理(或者說,歸屬cpu是軟中斷跟著硬中斷走)。這樣,充分發(fā)揮smp的優(yōu)勢,均衡到各個cpu上。至于硬中斷和cpu之間的關(guān)系,我們以后講到硬中斷時再討論。每個cpu維護自己的軟中斷機制就行了,各個cpu是互不相關(guān)的。注意,還是有相關(guān)性的:各個cpu并行處理同一類型的軟中斷時,該類型軟中斷處理需要為共享數(shù)據(jù)做保護,這是軟中斷可重入性需要付出的代價。

我們接著講軟中斷的核心機制相關(guān)函數(shù):do_softirq以及__do_softirq。

軟中斷核心函數(shù)處理之do_softirq

do_softirq先檢查軟中斷重入條件:必須不在硬中斷里并且不在軟中斷里,符合條件之后就可以開始做如下的軟中斷處理了:

這個處理是在關(guān)中斷的保護下完成的,畢竟軟中斷和硬中斷本質(zhì)上是一樣的,都是中斷體系的(當(dāng)然,進入到硬/軟中斷內(nèi)部再開則另當(dāng)別論了)。也可以看到,局部變量pending沒有傳入__do_softirq內(nèi)部,所以此處僅是判斷,不是使用,此處判斷值和內(nèi)部使用值可能有差異,位圖中置位位數(shù)會少一些。

我們再深究一下這個檢查條件。我們的理解是:

這個條件達(dá)到了兩個效果:同一個cpu上的軟中斷不嵌套;嵌套硬中斷中不處理軟中斷。就同一個cpu而言,__do_softirq函數(shù)的執(zhí)行是串行的,非重入的(do_softirq函數(shù)可以說是可重入的);就多個cpu而言,__do_softirq函數(shù)是可重入的,即使是同一個類型的軟中斷。也就是說,軟中斷通過這個檢查條件做到了本cpu上的軟中斷處理串行化,當(dāng)然,多cpu之間的還是并行的,所以同一類型軟中斷處理還是需要保護自己的相關(guān)共享數(shù)據(jù)結(jié)構(gòu)的。

軟中斷核心函數(shù)處理之__do_softirq

__do_softirq函數(shù)處理是盡量(雖然可能還是執(zhí)行不完)執(zhí)行所有被激活的軟中斷(由本cpu上的__softirq_pending位圖標(biāo)識)處理。我們分三個階段分析。

準(zhǔn)備處理階段:關(guān)閉軟中斷(效果是讓上面提到的檢查條件為真,從而達(dá)到禁止本cpu上的軟中斷嵌套的目的)。

核心處理階段:關(guān)硬中斷,獲得本cpu的__softirq_pending位圖并存儲起來,清空位圖,開硬中斷(僅在讀寫位圖時需要關(guān)硬中斷,防止其它硬中斷同時操作)。執(zhí)行本cpu的所有軟中斷(由存儲起來的位圖獲得)。這個核心處理是個循環(huán),最多10次(MAX_SOFTIRQ_RESTART),畢竟此時用的是用戶進程的棧,不能借用太久。退出循環(huán)的條件是:總時間超出或者被搶占(開中斷就會有被搶占)或者達(dá)到10次了。

結(jié)尾處理階段:關(guān)硬中斷,開軟中斷。

另外,如果10次循環(huán)都解決不完軟中斷,說明期間發(fā)生的硬中斷很多,帶來的額外的軟中斷也很多。那么就不繼續(xù)影響借用的用戶進程棧了,直接交給專門的ksoftirqd內(nèi)核線程處理。這也就說明了循環(huán)的含義:處理軟中斷期間時還會進入新的硬中斷,從而帶進新的軟中斷(當(dāng)然,僅僅是在本cpu的__softirq_pending上置位,不會有實際處理),所以需要反復(fù)去處理(處理的目標(biāo)很明確,就是要清空本cpu上的__softirq_pending位圖)。

再看看那個防止軟中斷嵌套的流程。關(guān)軟中斷中肯定有一句原子地加1的關(guān)鍵語句,如果當(dāng)前內(nèi)核路徑A在該原子操作之前被另一個內(nèi)核路徑B打斷,則B執(zhí)行完硬中斷和軟中斷后,返回到A的此處,A接著執(zhí)行該原子操作,之后的軟中斷處理應(yīng)該是空轉(zhuǎn),因為肯定已經(jīng)被B處理完了。如果在該原子操作之后被B打斷,則B執(zhí)行完硬中斷,不會執(zhí)行自己的軟中斷而是會直接退出(因為軟中斷嵌套了),返回到A的此處,A接著執(zhí)行,這次A除了處理自己軟中斷,還會額外地處理B的軟中斷。

對于preempt_count中的軟中斷位,由上述可以知道,它的作用有兩個:防止軟中斷在單cpu上嵌套;保證了在執(zhí)行軟中斷期間不被搶占。

最后,還得重復(fù)一句:這里講的__do_softirq函數(shù)都是在一個cpu上的處理,多個cpu上的并行是不受任何控制的。

總結(jié)

關(guān)于中斷的時序貌似很復(fù)雜,但其實都逃不過兩個原則:硬中斷會打斷硬中斷(當(dāng)然是不同類型的);硬中斷會打斷軟中斷(同樣地:軟中斷不會打斷硬中斷,軟中斷也不會打斷軟中斷)。所有貌似復(fù)雜的時序其實都只是這兩個的疊加而已。




理解內(nèi)核的硬軟中斷(詳細(xì)講解~)的評論 (共 條)

分享到微博請遵守國家法律
得荣县| 革吉县| 鸡泽县| 海兴县| 海门市| 乌兰县| 桐柏县| 桐庐县| 湖口县| 五常市| 麻栗坡县| 郧西县| 河西区| 湘西| 山阳县| 西安市| 易门县| 佛冈县| 伊金霍洛旗| 蚌埠市| 甘南县| 尉犁县| 瓦房店市| 凤台县| 富川| 枣庄市| 藁城市| 溧阳市| 抚远县| 武平县| 佛坪县| 宁武县| 山西省| 元朗区| 武川县| 谷城县| 新巴尔虎左旗| 常熟市| 峨山| 昆明市| 乌鲁木齐县|