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