?? 2.html
字號(hào):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312"> <META NAME="GENERATOR" CONTENT="《良友》v2.1, 作者:安富國(guó),http://winking.126.com"> <TITLE>中斷</TITLE></HEAD><BODY style="font-family: 宋體; font-size: 9pt"> <CENTER><TABLE CELLSPACING=10 CELLPADDING=10 WIDTH="60%" BGCOLOR="#FFB693" ><TR><TD ALIGN=CENTER><FONT SIZE=+2><!--標(biāo)題由此開(kāi)始-->中斷</TD></TR></TABLE></CENTER><p><h3>目 錄</h3><!--目錄由此開(kāi)始--><A NAME="Content" ID="Content"></A><OL><LI><A HREF="#I362">中斷</A></LI><OL><LI><A HREF="#I363">軟中斷</A></LI><LI><A HREF="#I364">硬中斷</A></LI><LI><A HREF="#I365">定時(shí)器代碼分析</A></LI><LI><A HREF="#I366">from aka</A></LI><OL><LI><A HREF="#I367">硬件中斷</A></LI><LI><A HREF="#I368">軟中斷</A></LI></OL><LI><A HREF="#I369">from lisolog</A></LI><OL><LI><A HREF="#I370">index</A></LI><LI><A HREF="#I371">內(nèi)部中斷</A></LI><LI><A HREF="#I372">外部中斷</A></LI><LI><A HREF="#I373">后續(xù)處理</A></LI></OL><LI><A HREF="#I374">軟中斷代碼線索</A></LI><LI><A HREF="#I375">2. 4軟中斷機(jī)制</A></LI></OL></OL><hr><br><A NAME="I362" ID="I362"></A><center><b><font size=+2>中斷</font></b></center><br> Linux系統(tǒng)中有很多不同的硬件設(shè)備。你可以同步使用這些設(shè)備,也就是說(shuō)你可以發(fā)出一個(gè)請(qǐng)求,然后等待一直到設(shè)備完成操作以后再進(jìn)行其他的工作。但這種方法的效率卻非常的低,因?yàn)椴僮飨到y(tǒng)要花費(fèi)很多的等待時(shí)間。一個(gè)更為有效的方法是發(fā)出請(qǐng)求以后,操作系統(tǒng)繼續(xù)其他的工作,等設(shè)備完成操作以后,給操作系統(tǒng)發(fā)送一個(gè)中斷,操作系統(tǒng)再繼續(xù)處理和此設(shè)備有關(guān)的操作。<p> 在將多個(gè)設(shè)備的中斷信號(hào)送往CPU的中斷插腳之前,系統(tǒng)經(jīng)常使用中斷控制器來(lái)綜合多個(gè)設(shè)備的中斷。這樣即可以節(jié)約CPU的中斷插腳,也可以提高系統(tǒng)設(shè)計(jì)的靈活性。中斷控制器用來(lái)控制系統(tǒng)的中斷,它包括屏蔽和狀態(tài)寄存器。設(shè)置屏蔽寄存器的各個(gè)位可以允許或屏蔽某一個(gè)中斷,狀態(tài)寄存器則用來(lái)返回系統(tǒng)中正在使用的中斷。<p> 大多數(shù)處理器處理中斷的過(guò)程都相同。當(dāng)一個(gè)設(shè)備發(fā)出中段請(qǐng)求時(shí),CPU停止正在執(zhí)行的指令,轉(zhuǎn)而跳到包括中斷處理代碼或者包括指向中斷處理代碼的轉(zhuǎn)移指令所在的內(nèi)存區(qū)域。這些代碼一般在CPU的中斷方式下運(yùn)行。在此方式下,將不會(huì)再有中斷發(fā)生。但有些CPU的中斷有自己的優(yōu)先權(quán),這樣,更高優(yōu)先權(quán)的中斷則可以發(fā)生。這意味著第一級(jí)的中斷處理程序必須擁有自己的堆棧,以便在處理更高級(jí)別的中斷前保存CPU的執(zhí)行狀態(tài)。當(dāng)中斷處理完畢以后,CPU將恢復(fù)到以前的狀態(tài),繼續(xù)執(zhí)行中斷處理前正在執(zhí)行的指令。<p> 中斷處理程序十分簡(jiǎn)單有效,這樣,操作系統(tǒng)就不會(huì)花太長(zhǎng)的時(shí)間屏蔽其他的中斷。<p>[設(shè)置Softirq]<br> cpu_raise_softirq是一個(gè)輪訓(xùn),喚醒ksoftirqd_CPU0內(nèi)核線程, 進(jìn)行管理<p>cpu_raise_softirq<br> |__cpu_raise_softirq<br> |wakeup_softirqd<br> |wake_up_process<p> ·cpu_raise_softirq [kernel/softirq.c]<br> ·__cpu_raise_softirq [include/linux/interrupt.h]<br> ·wakeup_softirq [kernel/softirq.c]<br> ·wake_up_process [kernel/sched.c]<p>[執(zhí)行Softirq]<br> 當(dāng)內(nèi)核線程ksoftirqd_CPU0被喚醒, 它會(huì)執(zhí)行隊(duì)列里的工作。當(dāng)然ksoftirqd_CPU0也是一個(gè)死循環(huán):<p>for (;;) {<br> if (!softirq_pending(cpu))<br> schedule();<br> __set_current_state(TASK_RUNNING);<br> while (softirq_pending(cpu)) {<br> do_softirq();<br> if (current->need_resched)<br> schedule<br> }<br> __set_current_state(TASK_INTERRUPTIBLE)<br>}<p> ·ksoftirqd [kernel/softirq.c]<br><center><A HREF="#Content">[目錄](méi)</A></center><hr><br><A NAME="I363" ID="I363"></A><center><b><font size=+2>軟中斷</font></b></center><br>發(fā)信人: fist (星仔迷), 信區(qū): SysInternals WWW-POST<br>標(biāo) 題: 軟中斷<br>發(fā)信站: 武漢白云黃鶴站 (Thu Mar 22 14:12:46 2001) , 轉(zhuǎn)信<p>軟中斷「一」<p>一、 引言<br> 軟中斷是linux系統(tǒng)原“底半處理”的升級(jí),在原有的基礎(chǔ)上發(fā)展的新的處理方式,以適應(yīng)多cpu 、多線程的軟中斷處理。要了解軟中斷,我們必須要先了原來(lái)底半處理的處理機(jī)制。<p>二、底半處理機(jī)制(基于2.0.3版本)<p> 某些特殊時(shí)刻我們并不愿意在核心中執(zhí)行一些操作。例如中斷處理過(guò)程中。當(dāng)中斷發(fā)生時(shí)處理器將停止當(dāng)前的工作, 操作系統(tǒng)將中斷發(fā)送到相應(yīng)的設(shè)備驅(qū)動(dòng)上去。由于此時(shí)系統(tǒng)中其他程序都不能運(yùn)行, 所以設(shè)備驅(qū)動(dòng)中的中斷處理過(guò)程不宜過(guò)長(zhǎng)。有些任務(wù)最好稍后執(zhí)行。Linux底層部分處理機(jī)制可以讓設(shè)備驅(qū)動(dòng)和Linux核心其他部分將這些工作進(jìn)行排序以延遲執(zhí)行。<br> 系統(tǒng)中最多可以有32個(gè)不同的底層處理過(guò)程;bh_base是指向這些過(guò)程入口的指針數(shù)組。而bh_active和 bh_mask用來(lái)表示那些處理過(guò)程已經(jīng)安裝以及那些處于活動(dòng)狀態(tài)。如果bh_mask的第N位置位則表示bh_base的 第N個(gè)元素包含底層部分處理例程。如果bh_active的第N位置位則表示第N個(gè)底層處理過(guò)程例程可在調(diào)度器認(rèn) 為合適的時(shí)刻調(diào)用。這些索引被定義成靜態(tài)的;定時(shí)器底層部分處理例程具有最高優(yōu)先級(jí)(索引值為0), 控制臺(tái)底層部分處理例程其次(索引值為1)。典型的底層部分處理例程包含與之相連的任務(wù)鏈表。例如 immediate底層部分處理例程通過(guò)那些需要被立刻執(zhí)行的任務(wù)的立即任務(wù)隊(duì)列(tq_immediate)來(lái)執(zhí)行。<br> --引自David A Rusling的《linux核心》。<p>三、對(duì)2.4.1 軟中斷處理機(jī)制<br> 下面,我們進(jìn)入軟中斷處理部份(softirq.c):<br> 由softirq.c的代碼閱讀中,我們可以知道,在系統(tǒng)的初始化過(guò)程中(softirq_init()),它使用了兩個(gè)數(shù)組:bh_task_vec[32],softirq_vec[32]。其中,bh_task_vec[32]填入了32個(gè)bh_action()的入口地址,但soft_vec[32]中,只有softirq_vec[0],和softirq_vec[3]分別填入了tasklet_action()和tasklet_hi_action()的地址。其余的保留它用。<br> 當(dāng)發(fā)生軟中斷時(shí),系統(tǒng)并不急于處理,只是將相應(yīng)的cpu的中斷狀態(tài)結(jié)構(gòu)中的active 的相應(yīng)的位置位,并將相應(yīng)的處理函數(shù)掛到相應(yīng)的隊(duì)列,然后等待調(diào)度時(shí)機(jī)來(lái)臨(如:schedule(),<br> 系統(tǒng)調(diào)用返回異常時(shí),硬中斷處理結(jié)束時(shí)等),系統(tǒng)調(diào)用do_softirq()來(lái)測(cè)試active位,再調(diào)用被激活的進(jìn)程在這處過(guò)程中,軟中斷的處理與底半處理有了差別,active 和mask不再對(duì)應(yīng)bh_base[nr], 而是對(duì)應(yīng)softirq_vec[32]。在softirq.c中,我們只涉及了softirq_vec[0]、softirq_vec[3]。這兩者分別調(diào)用了tasklet_action()和tasklet_hi_action()來(lái)進(jìn)行后續(xù)處理。這兩個(gè)過(guò)程比較相似,大致如下:<p>1 鎖cpu的tasklet_vec[cpu]鏈表,取出鏈表,將原鏈表清空,解鎖,還給系統(tǒng)。<br>2 對(duì)鏈表進(jìn)行逐個(gè)處理。<br>3 有無(wú)法處理的,(task_trylock(t)失敗,可能有別的進(jìn)程鎖定),插回系統(tǒng)鏈表。至此,系統(tǒng)完成了一次軟中斷的處理。<p>接下來(lái)有兩個(gè)問(wèn)題:<br>1 bh_base[]依然存在,但應(yīng)在何處調(diào)用?<br>2 tasklet_vec[cpu]隊(duì)列是何時(shí)掛上的?<p><br>四、再探討<br> 再次考查softirq.c 的bh_action()部份,發(fā)現(xiàn)有兩個(gè)判斷:<br> A:if(!spin_trylock(&global_bh_lock))goto:rescue 指明如果global_bh_lock 不能被鎖上(已被其它進(jìn)程鎖上),則轉(zhuǎn)而執(zhí)行rescue,將bh_base[nr]掛至tasklet_hi_vec[cpu]隊(duì)列中。等候中斷調(diào)度。<br> B:if(!hardirq_trylock(cpu)) goto tescue unlock 此時(shí)有硬中斷發(fā)生,放入隊(duì)列推遲執(zhí)行。若為空閑,現(xiàn)在執(zhí)行。<p> 由此可見(jiàn),這部分正是對(duì)應(yīng)底半處理的程序,bh_base[]的延時(shí)處理正是底半處理的特點(diǎn),可以推測(cè),如果沒(méi)有其它函數(shù)往tasklet_hi_vec[cpu]隊(duì)列掛入,那tasklet_hi_vec[cpu]正完全對(duì)應(yīng)著bh_base[]底半處理<br> 在bh_action()中,把bh_ation()掛入tasklet_hi_vec[cpu]的正是mark_bh(),在整個(gè)源碼樹(shù)中查找,發(fā)現(xiàn)調(diào)用mark_bh()的函數(shù)很多,可以理解,軟中斷產(chǎn)生之時(shí),相關(guān)的函數(shù)會(huì)調(diào)用mark_bh(),將bh_action掛上tasklet_hi_vec隊(duì)列,而bh_action()的作用不過(guò)是在發(fā)現(xiàn)bh_base[nr]暫時(shí)無(wú)法處理時(shí)重返隊(duì)列的方法。<br> 由此可推測(cè)tasklet_vec隊(duì)列的掛接應(yīng)與此相似,查看interrupt.h,找到tasklet_schedule()函數(shù):<p>157 static inline void tasklet_schedule(struct tasklet_struct *t)<br>158 {<br>159 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {<br>160 int cpu = smp_processor_id();<br>161 unsigned long flags;<br>162<br>163 local_irq_save(flags);<br>164 t->next = tasklet_vec[cpu].list;<br>165 tasklet_vec[cpu].list = t; /*插入隊(duì)列。<br>166 __cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);<br>167 local_irq_restore(flags);<br>168 }<br>169 }<p> 正是它為tasklet_vec[cpu]隊(duì)列的建立立下了汗馬功勞,在源碼樹(shù)中,它亦被多個(gè)模塊調(diào)用,來(lái)完成它的使命。<br> 至此,我們可以描繪一幅完整的軟中斷處理圖了。<br> 現(xiàn)在,再來(lái)考查do_softirq()的softirq_vec[32],在interrupt.h中有如下定義:<p>56 enum<br>57 {<br>58 HI_SOFTIRQ=0,<br>59 NET_TX_SOFTIRQ,<br>60 NET_RX_SOFTIRQ,<br>61 TASKLET_SOFTIRQ<br>62 };<p> 這四個(gè)變量應(yīng)都是為softirq_vec[]的下標(biāo),那么,do_softirq()也將會(huì)處理NET_TX_SOFTIRQ和NET_RX_SOFTIRQ,是否還處理其它中斷,這有待探討。也許,這個(gè)do_softirq()有著極大的拓展性,等著我們?nèi)ラ_(kāi)發(fā)呢。<p> 主要通過(guò)__cpu_raise_softirq來(lái)設(shè)置<br> 在hi_tasklet(也就是一般用于bh的)的處理里面,在處理完當(dāng)前的隊(duì)列后,會(huì)將補(bǔ)充的隊(duì)列重新掛上,然后標(biāo)記(不管是否補(bǔ)充隊(duì)列里面有tasklet):<p>local_irq_disable();<br>t->next = tasklet_hi_vec[cpu].list;<br>tasklet_hi_vec[cpu].list = t;<br>__cpu_raise_softirq(cpu, HI_SOFTIRQ);<br>local_irq_enable();<p> 因此,對(duì)mark_bh根本不用設(shè)置這個(gè)active位。對(duì)于一般的tasklet也一樣:<p>local_irq_disable();<br>t->next = tasklet_vec[cpu].list;<br>tasklet_vec[cpu].list = t;<br>__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);<br>local_irq_enable();<p> 其它的設(shè)置,可以檢索上面的__cpu_raise_softirq<p>bottom half, softirq, tasklet, tqueue<br>[bottom half]<br>bh_base[32]<br>|<br>\/<br>bh_action();<br>|<br>\/<br>bh_task_vec[32];<br>| mark_bh(), tasklet_hi_schedule()<br>
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -