Linux内核实现中断和中断处理(二)
第一部分移步傳送門召喚!!:http://www.cnblogs.com/lenomirei/p/5562086.html
上回說了Linux內(nèi)核實現(xiàn)中斷會把中斷分為兩部分進行處理,上回講了上部分,這回講下部分的設(shè)計思路
- 下半部的實現(xiàn)機制
-
- 軟中斷
- tasklet:是通過軟中斷實現(xiàn)的,但和軟中斷有所不同
- 工作隊列
講上面幾個實現(xiàn)機制之前先講一個古老的方法,現(xiàn)在版本的內(nèi)核雖然已經(jīng)不再食用了,但是思想還在繼續(xù)使用
最早的Linux只提供了“bottom half”這種機制實現(xiàn)下半部分,被稱為BH,實現(xiàn)簡單粗暴,設(shè)置一個全局變量(32位整數(shù)),表示一個32個節(jié)點的鏈表隊列,哪位設(shè)置為1證明哪個bottom half就可以執(zhí)行了。
?
?
- 軟中斷
第一個先將軟中斷實現(xiàn)下半部分機制,要想將這個機制,必須得先說明軟中斷的實現(xiàn)方式,軟中斷實在編譯期間靜態(tài)分配的,kernel/softirq.c中定義了一個包含有32個結(jié)構(gòu)體的數(shù)組static struct softirq_action softirq_vec[NR_SOFTIRQS],并且有一個對應(yīng)的32位整數(shù)u32 pending,用來表示每個軟中斷的狀態(tài)(不要嫌少,一般根本用不了那么多,一般9個10個就夠用了,為什么這么少?很少有用軟中斷處理下半部分的,能用tasklet的地方絕不會使用軟中斷)
把軟中斷放進剛才說的32個長度的結(jié)構(gòu)體數(shù)組中就完成了軟中斷的注冊,想要執(zhí)行軟中斷必須先標記注冊好的軟中斷,這個過程被稱為觸發(fā)軟中斷,通常,中斷處理程序(就是上半部分)會在返回之前標記它的軟中斷,所以不必擔心,然后在合適的時刻就會執(zhí)行該軟中斷
合適的時刻:1.從一個硬件中斷代碼處返回時;2.在ksoftirqd內(nèi)核線程中;3.在那些顯示檢查和執(zhí)行待處理的軟中斷的代碼中;
不管是上面哪個時刻,軟中斷最終都是會被執(zhí)行的,調(diào)用do_softirq()該函數(shù)會循環(huán)遍歷(循環(huán)檢查pending的每一個位,所以循環(huán)最多只能執(zhí)行32次)
- tasklet
因為takslet是使用軟中斷實現(xiàn)的,所以tasklet本身就是個軟中斷,我們是通過tasklet來實現(xiàn)下半部的機制的,所以在處理方式上和軟中斷十分的相似,tasklet由tasklet結(jié)構(gòu)體表示,每一個結(jié)構(gòu)體單獨代表一個tasklet,它的定義如下
?
1 struct tasklet_struct 2 { 3 stauct tasklet_struct *next;//鏈表中的下一個節(jié)點 4 unsigned long state;//tasklet的狀態(tài) 5 atomic_t count;//引用計數(shù)器 6 void (*func)(unsigned long);//tasklet處理函數(shù) 7 unsigned long data;//給tasklet處理函數(shù)的參數(shù) 8 };?
其中tasklet的狀態(tài)一共只有三種:0,TASKLET_STATE_SCHED,TASKLET_STATE_RUN,只能在這三種之間取值,0表示啥也沒有等待調(diào)度,SCHED表示已經(jīng)調(diào)度,RUN表示該tasklet正在運行。
已經(jīng)被調(diào)度的tasklet結(jié)構(gòu)體存放在兩種單處理器數(shù)據(jù)結(jié)構(gòu)當中,分別是tasklet_vec(普通優(yōu)先級的tasklet)和tasklet_hi_vec(高優(yōu)先級的tasklet),幾乎沒區(qū)別,只是優(yōu)先級不一樣,調(diào)度的步驟如下
運行的步驟如下:
?
?
其實tasklet給人的感覺就是一個對軟中斷的封裝的簡單接口而已。。?
每個處理器都有一組輔助處理軟中斷(當然也就包括tasklet)的內(nèi)核線程,那么什么時候執(zhí)行這些軟中斷呢,上面在軟中斷部分也闡述了,但是這樣有個問題,那就是軟中斷如果繼續(xù)調(diào)軟中斷,就會不停的執(zhí)行軟中斷。。這樣在處理器負載很嚴重的時候就不太好了,會導致用戶空間進程饑餓,還有一種方案,那就是并不立即處理軟中斷,而是等待一段時間,但是在處理器比較閑的時候這么做很顯然不太好,因為完全可以立即執(zhí)行你卻讓處理器閑著。作為改進,當大量軟中斷出現(xiàn)的時候,內(nèi)核會喚醒一組內(nèi)核線程來處理這些負載,關(guān)鍵來了,這些帶著軟中斷的線程的優(yōu)先級會被設(shè)置到最低的優(yōu)先級上(nice值取最高為19),這樣的會在處理器比較忙的時候,這些軟中斷不會跟用戶空間進程爭奪處理器資源,而且最終一定會被執(zhí)行,處理器空閑的時候也可以直接得到運行。
- 工作隊列
工作隊列是另外一種比較新的將工作推后的形式,和之前的兩種處理方式不同,它會把工作交給一個內(nèi)核線程去執(zhí)行,這就意!味!著!是由進程上下文來處理了!就可以睡眠了!!(中斷是不允許睡眠的)所以很簡單就可以在這兩種方法之間做出選擇。
每一個處理器都有一個對應(yīng)的工作者線程
?
1 struct workqueue_struct 2 { 3 struct cpu_work_queue_struct cpu_wq[NR_CPUS]; 4 struct list_head list; 5 const char *name; 6 int sinqlethread; 7 int freezeable; 8 int rt; 9 };?
?
1 struct cpu_workqueue_struct 2 { 3 spinlck_t lock;//鎖保護這種結(jié)構(gòu) 4 struct list_head worklist;//工作列表 5 wait_queue_head_t more_work; 6 struct work_struct *current_struct; 7 struct workqueue_struct *wq;//關(guān)聯(lián)工作隊列結(jié)構(gòu) 8 task_t *thread;//關(guān)聯(lián)線程 9 };?
表示工作的數(shù)據(jù)結(jié)構(gòu)
?
1 struct work_struct 2 { 3 atomic_long_t data; 4 struct list_head entry; 5 work_func_t func; 6 };?
?
這些工作的結(jié)構(gòu)體被連城鏈表,當鏈表上的所有工作都做完了之后,線程就會休眠
實現(xiàn)方式也很簡單,
來個結(jié)構(gòu)圖
?
- 下半部機制的選擇
這三種看上去都不錯,那么應(yīng)該怎么選擇呢
如果你對共享有很高的要求,雖然比較麻煩,但還是使用軟中斷吧,因為可以各種操作(雖然保障這些很麻煩)
如果你不是對共享有那么高的要求,推薦使用tasklet,因為兩種同類型的tasklet不能同時并行
如果你想在進程上下文中解決下半部分的問題,使用工作隊列吧,當然如果你想睡眠,你也沒得選了
* 全劇終*
轉(zhuǎn)載于:https://www.cnblogs.com/lenomirei/p/5564131.html
總結(jié)
以上是生活随笔為你收集整理的Linux内核实现中断和中断处理(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 打开CEPH内核DOUT日志输出
- 下一篇: Maven中settings.xml的配