国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
Linux系統(tǒng)中的知名內(nèi)核線(xiàn)程(1)——ksoftirqd和events
1.5ksoftirqd
1.1irq_exit
1.2in_interrupt
1.4__do_softirq
2.events
2.1什么是workqueue?
2.2Workqueue機(jī)制的實(shí)現(xiàn)
首頁(yè) 后端開(kāi)發(fā) php教程 Linux系統(tǒng)中的知名內(nèi)核線(xiàn)程(1)——ksoftirqd和events_PHP教程

Linux系統(tǒng)中的知名內(nèi)核線(xiàn)程(1)——ksoftirqd和events_PHP教程

Jul 12, 2016 am 08:53 AM
android

Linux系統(tǒng)中的知名內(nèi)核線(xiàn)程(1)——ksoftirqd和events

Linux系統(tǒng)中的知名內(nèi)核線(xiàn)程(1)——ksoftirqd和events
——lvyilong316

我們知道linux系統(tǒng)中有很多系統(tǒng)創(chuàng)建的內(nèi)核線(xiàn)程(kthread),這些內(nèi)核線(xiàn)程是系統(tǒng)正常工作的保證。這里我們看下其中比較知名的兩個(gè):ksoftirqd和events。

1.ksoftirqd

提到ksoftirqd就不得不說(shuō)下“軟中斷(softirq)”,因?yàn)檫@個(gè)線(xiàn)程正是用來(lái)執(zhí)行軟中斷的(準(zhǔn)確的說(shuō)應(yīng)該是執(zhí)行過(guò)多的軟中斷)。我們知道按照優(yōu)先級(jí)來(lái)說(shuō),中斷>軟中斷>用戶(hù)進(jìn)行,也就是說(shuō)中斷可以打斷軟中斷,而軟中斷又可以打斷用戶(hù)進(jìn)程。

而對(duì)于軟中斷,內(nèi)核會(huì)在幾個(gè)特殊的時(shí)機(jī)執(zhí)行(注意執(zhí)行和調(diào)度的區(qū)別,調(diào)度軟中斷只是對(duì)軟中斷打上待執(zhí)行的標(biāo)記,并沒(méi)有真正執(zhí)行),而在中斷處理程序返回時(shí)處理是最常見(jiàn)的。軟中斷的觸發(fā)頻率有時(shí)可能會(huì)很高(例如進(jìn)行大流量網(wǎng)絡(luò)通信期間)。更不利的是,軟中斷的執(zhí)行函數(shù)有時(shí)還會(huì)調(diào)度自身,所以如果軟中斷本身出現(xiàn)的頻率較高,再加上他們又有將自己重新設(shè)置為可執(zhí)行狀態(tài)的能力,那么就會(huì)導(dǎo)致用戶(hù)空間的進(jìn)程無(wú)法獲得足夠的處理時(shí)間,因而處于饑餓狀態(tài)。為了避免用戶(hù)進(jìn)程的饑餓。內(nèi)核開(kāi)發(fā)者做了一些折中,最終在內(nèi)核的實(shí)現(xiàn)方案中是不會(huì)立即處理由軟中斷自身重新觸發(fā)的軟中斷(不允許軟中斷嵌套)。而作為改進(jìn),內(nèi)核會(huì)喚醒一組內(nèi)核線(xiàn)程來(lái)處理這些過(guò)多的軟中斷,這些內(nèi)核線(xiàn)程在最低優(yōu)先級(jí)上運(yùn)行(nice值是19),這能避免它們跟其他重要的任務(wù)搶奪資源,但它們最終肯定會(huì)被執(zhí)行,所以這個(gè)方案能夠保證軟中斷負(fù)載很重的時(shí)候,用戶(hù)進(jìn)程不會(huì)因?yàn)榈貌坏教幚頃r(shí)間而處于饑餓狀態(tài),相應(yīng)的,也能保證過(guò)量的軟中斷終究會(huì)得到處理。

每個(gè)處理器都有一個(gè)這樣的線(xiàn)程。所有的線(xiàn)程的名字都叫做ksoftirq/n,區(qū)別在于n,他對(duì)應(yīng)的是處理器的編號(hào)。

下面我們?cè)敿?xì)的看下軟中斷是如何被ksoftirqd執(zhí)行的。首先看下軟中斷的處理調(diào)度過(guò)程。一個(gè)軟中斷在執(zhí)行之前必須被調(diào)度(激活),術(shù)語(yǔ)稱(chēng)為"raisethesoftirq"。被激活的softirq通常并不會(huì)立即執(zhí)行,一般會(huì)在之后的某個(gè)時(shí)刻檢查當(dāng)前系統(tǒng)中是否有被pending的softirq,如果有就去執(zhí)行,linux執(zhí)行軟中斷的函數(shù)是do_softirq(),而這個(gè)函數(shù)會(huì)再兩個(gè)地方被調(diào)用,一個(gè)是中斷返回時(shí),另一個(gè)就是我們討論的ksoftirqd內(nèi)核線(xiàn)程。我們先來(lái)看中斷返回的情況。

1.1irq_exit

//do_IRQ函數(shù)執(zhí)行完硬件ISR后退出時(shí)調(diào)用此函數(shù)。

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>void irq_exit(void) <br /></li><li>{ <br /></li><li>account_system_vtime(current); <br /></li><li>trace_hardirq_exit(); <br /></li><li>sub_preempt_count(IRQ_EXIT_OFFSET); //這個(gè)位置修改preempt_count<br /></li><li>// 判斷當(dāng)前是否有硬件中斷嵌套,并且是否有軟中斷在 pending 狀態(tài),注意:這里只有兩個(gè)條件同時(shí)滿(mǎn)足時(shí),才有可能調(diào)用 do_softirq() 進(jìn)入軟中斷。也就是說(shuō)確認(rèn)當(dāng)前所有硬件中斷處理完成,且有硬件中斷安裝了軟中斷處理時(shí)理時(shí)才會(huì)進(jìn)入。關(guān)于in_interrupt()后面會(huì)詳細(xì)分析。<br /></li><li>if (!in_interrupt() && local_softirq_pending()) <br /></li><li>// 其實(shí)這里就是調(diào)用 do_softirq() 執(zhí)行 <br /></li><li>invoke_softirq(); <br /></li><li>preempt_enable_no_resched(); <br /></li><li>}</li></ol>

1.2in_interrupt

這里需要重點(diǎn)分析一下in_interrupt()函數(shù)的含義。在linux內(nèi)核中,為了方便判斷當(dāng)前執(zhí)行路徑在哪個(gè)上下文環(huán)境中,定義了幾個(gè)接口:


<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#define hardirq_count() (preempt_count() & HARDIRQ_MASK)<br /></li><li>#define softirq_count() (preempt_count() & SOFTIRQ_MASK)<br /></li><li>#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK | NMI_MASK))<br /></li><li>/*<br /></li><li>* Are we doing bottom half or hardware interrupt processing?<br /></li><li>* Are we in a softirq context? Interrupt context?<br /></li><li>*/<br /></li><li>#define in_irq() (hardirq_count())<br /></li><li>#define in_softirq() (softirq_count())<br /></li><li>#define in_interrupt() (irq_count())<br /></li><li>/*<br /></li><li>* Are we in NMI context?<br /></li><li>*/<br /></li><li>#define in_nmi() (preempt_count() & NMI_MASK)</li></ol>

從注釋可以看出包括:硬件中斷上下文,軟件中斷上下文,不可屏蔽上下文等。在這些宏中,都涉及到了preempt_count()這個(gè)宏,這個(gè)宏是一個(gè)比較重要的宏,在Linux源碼中對(duì)其做了詳細(xì)的注釋?zhuān)?/p>


<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>/*<br /></li><li>* We put the hardirq and softirq counter into the preemption<br /></li><li>* counter. The bitmask has the following meaning:<br /></li><li>*<br /></li><li>* - bits 0-7 are the preemption count (max preemption depth: 256)<br /></li><li>* - bits 8-15 are the softirq count (max # of softirqs: 256)<br /></li><li>*<br /></li><li>* The hardirq count can in theory reach the same as NR_IRQS.<br /></li><li>* In reality, the number of nested IRQS is limited to the stack<br /></li><li>* size as well. For archs with over 1000 IRQS it is not practical<br /></li><li>* to expect that they will all nest. We give a max of 10 bits for<br /></li><li>* hardirq nesting. An arch may choose to give less than 10 bits.<br /></li><li>* m68k expects it to be 8.<br /></li><li>*<br /></li><li>* - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)<br /></li><li>* - bit 26 is the NMI_MASK<br /></li><li>* - bit 28 is the PREEMPT_ACTIVE flag<br /></li><li>*<br /></li><li>* PREEMPT_MASK: 0x000000ff<br /></li><li>* SOFTIRQ_MASK: 0x0000ff00<br /></li><li>* HARDIRQ_MASK: 0x03ff0000<br /></li><li>* NMI_MASK: 0x04000000<br /></li><li>*/</li></ol>

從注釋可以看出,preempt_count各個(gè)bit位的含義:

(1)bit0~7位表示搶占計(jì)數(shù),即支持最大的搶占深度為256

(2)bit8~15位表示軟中斷計(jì)數(shù),即支持最大的軟中斷的個(gè)數(shù)為256,需要注意的是,由于軟中斷還受制于pending狀態(tài),一個(gè)32位的變量,因此實(shí)際最大只能支持32個(gè)軟中斷。

(3)bit16~25位表示硬件中斷嵌套層數(shù),即最大可支持的嵌套層次為1024,實(shí)際情況下這是不可能的,因?yàn)橹袛嗟那短讓訑?shù)還受制于中斷處理的棧空間的大小。

介紹了這么多,現(xiàn)在了重點(diǎn)分析下上面提到的in_interrupt到底表示什么意思?

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#define in_interrupt() (irq_count())<br /></li><li>#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \<br /></li><li>| NMI_MASK))</li></ol>

從其宏定義可以看出,in_interrupt宏的值是硬件中斷嵌套層數(shù),軟中斷計(jì)數(shù)以及可屏蔽中斷三者之和。所以如果in_interrupt()的值大于0,就不會(huì)處理軟中斷,意思是(a)當(dāng)有硬件中斷嵌套,(b)或軟中斷被禁止(c)不可屏蔽中斷的情況下,不會(huì)去處理軟中斷。有人會(huì)問(wèn)軟中斷不是從中斷處理后irq_exit中進(jìn)入的嗎?那軟中斷執(zhí)行時(shí)preempt_count的硬中斷位不是還沒(méi)有修改掉嗎?其實(shí)已經(jīng)做了修改,就在irq_exit函數(shù)中的sub_preempt_count中進(jìn)行。其實(shí)執(zhí)行過(guò)sub_preempt_count就算退出中斷處理程序了。

l注:軟中斷被禁止會(huì)增加軟中斷的計(jì)數(shù);

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>__local_bh_disable((unsigned long)__builtin_return_address(0));<br /></li><li>static inline void __local_bh_disable(unsigned long ip)<br /></li><li>{<br /></li><li>add_preempt_count(SOFTIRQ_OFFSET);<br /></li><li>barrier();<br /></li><li>}<br /></li><li># define add_preempt_count(val) do { preempt_count() += (val); } while (0)</li></ol>

1.3do_softirq

下面重點(diǎn)分析以下do_softirq(),了解Linux內(nèi)核到底是怎么來(lái)處理softirq的。

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>asmlinkage void do_softirq(void)<br /></li><li>{<br /></li><li>__u32 pending;<br /></li><li> unsigned long flags;<br /></li><li>// 這個(gè)函數(shù)判斷,如果當(dāng)前有硬件中斷嵌套,或者軟中斷被禁止時(shí),則馬上返回。在這個(gè)入口判斷主要是為了與 ksoftirqd 互斥。<br /></li><li>if (in_interrupt())<br /></li><li>   return;<br /></li><li>// 關(guān)中斷執(zhí)行以下代碼<br /></li><li> local_irq_save(flags); <br /></li><li>// 判斷是否有 pending 的軟中斷需要處理。<br /></li><li> pending = local_softirq_pending();<br /></li><li>// 如果有則調(diào)用 __do_softirq() 進(jìn)行實(shí)際處理<br /></li><li>if (pending)<br /></li><li>   __do_softirq();<br /></li><li>// 開(kāi)中斷繼續(xù)執(zhí)行<br /></li><li> local_irq_restore(flags);<br /></li><li>}</li></ol>

注意調(diào)用local_softirq_pending()獲取pending和將pending請(qǐng)0這兩個(gè)操作一定要位于關(guān)中斷情況,否則兩個(gè)操作間可能發(fā)生中斷,中斷再次調(diào)度軟中段的置位標(biāo)記會(huì)丟失。

真正的軟中斷處理再__do_softirq中。

1.4__do_softirq

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>// 最大軟中斷調(diào)用次數(shù)為 10 次。<br /></li><li>#define MAX_SOFTIRQ_RESTART 10<br /></li><li>asmlinkage void __do_softirq(void)<br /></li><li>{<br /></li><li>// 軟件中斷處理結(jié)構(gòu),此結(jié)構(gòu)中包括軟中斷回調(diào)函數(shù)。<br /></li><li>  struct softirq_action *h;<br /></li><li>  __u32 pending;<br /></li><li>int max_restart = MAX_SOFTIRQ_RESTART;<br /></li><li>int cpu;<br /></li><li>// 得到當(dāng)前所有 pending 的軟中斷。<br /></li><li>  pending = local_softirq_pending();<br /></li><li>  account_system_vtime(current);<br /></li><li>// 執(zhí)行到這里要禁止其他軟中斷,這里也就證明了每個(gè) CPU 上同時(shí)運(yùn)行的軟中斷只能有一個(gè)。<br /></li><li>  __local_bh_disable((unsigned long)__builtin_return_address(0));<br /></li><li>  trace_softirq_enter();<br /></li><li>// 針對(duì) SMP 得到當(dāng)前正在處理的 CPU<br /></li><li>  cpu = smp_processor_id();<br /></li><li>restart:<br /></li><li>// 每次循環(huán)在允許硬件 中斷強(qiáng)占前,首先重置軟中斷的標(biāo)志位。<br /></li><li>/* Reset the pending bitmask before enabling irqs */<br /></li><li>  set_softirq_pending(0); //要在關(guān)中斷情況下才能調(diào)用<br /></li><li> // 到這里才開(kāi)中斷運(yùn)行,注意:以前運(yùn)行狀態(tài)一直是關(guān)中斷運(yùn)行,這時(shí)當(dāng)前處理軟中斷才可能被硬件中斷搶占。也就是說(shuō)在進(jìn)入軟中斷時(shí)不是一開(kāi)始就會(huì)被硬件中斷搶占。只有在這里以后的代碼才可能被硬件中斷搶占。<br /></li><li>  local_irq_enable();<br /></li><li> // 這里要注意,以下代碼運(yùn)行時(shí)可以被硬件中斷搶占,但這個(gè)硬件中斷執(zhí)行完成后,它的所注冊(cè)的軟中斷無(wú)法馬上運(yùn)行,別忘了,現(xiàn)在雖是開(kāi)硬件中斷執(zhí)行,但前面的 __local_bh_disable()函數(shù)屏蔽了軟中斷。所以這種環(huán)境下只能被硬件中斷搶占,但這個(gè)硬中斷注冊(cè)的軟中斷回調(diào)函數(shù)無(wú)法運(yùn)行。要問(wèn)為什么,那是因?yàn)開(kāi)_local_bh_disable() 函數(shù)設(shè)置了一個(gè)標(biāo)志當(dāng)作互斥量,而這個(gè)標(biāo)志正是上面的 irq_exit() 和 do_softirq() 函數(shù)中的in_interrupt() 函數(shù)判斷的條件之一,也就是說(shuō) in_interrupt() 函數(shù)不僅檢測(cè)硬中斷而且還判斷了軟中斷。所以在這個(gè)環(huán)境下觸發(fā)硬中斷時(shí)注冊(cè)的軟中斷,根本無(wú)法重新進(jìn)入到這個(gè)函數(shù)中來(lái),只能是做一個(gè)標(biāo)志,等待下面的重復(fù)循環(huán)(最大 MAX_SOFTIRQ_RESTART)才可能處理到這個(gè)時(shí)候觸發(fā)的硬件中斷所注冊(cè)的軟中斷。得到軟中斷向量表。<br /></li><li>  h = softirq_vec;<br /></li><li> // 循環(huán)處理所有 softirq 軟中斷注冊(cè)函數(shù)。</li><li> do {</li><li>// 如果對(duì)應(yīng)的軟中斷設(shè)置 pending 標(biāo)志則表明需要進(jìn)一步處理它所注冊(cè)的函數(shù)。<br /></li><li>if (pending & 1) {<br /></li><li>// 在這里執(zhí)行了這個(gè)軟中斷所注冊(cè)的回調(diào)函數(shù)。<br /></li><li>      h->action(h);<br /></li><li>      rcu_bh_qsctr_inc(cpu);<br /></li><li>}<br /></li><li>// 繼續(xù)找,直到把軟中斷向量表中所有 pending 的軟中斷處理完成。<br /></li><li>     h++;<br /></li><li>     // 從代碼里可以看出按位操作,表明一次循環(huán)只處理 32 個(gè)軟中斷的回調(diào)函數(shù)。<br /></li><li>      pending >>= 1; <br /></li><li>} while (pending);<br /></li><li>// 關(guān)中斷執(zhí)行以下代碼。注意:這里又關(guān)中斷了,下面的代碼執(zhí)行過(guò)程中硬件中斷無(wú)法搶占。<br /></li><li>  local_irq_disable();<br /></li><li>// 前面提到過(guò),在剛才開(kāi)硬件中斷執(zhí)行環(huán)境時(shí)只能被硬件中斷搶占 ,在這個(gè)時(shí)候是無(wú)法處理軟中斷的,因?yàn)閯偛砰_(kāi)中斷執(zhí)行過(guò)程中可能多次被硬件中斷搶占,每搶占一次就有可能注冊(cè)一個(gè)軟中斷,所以要再重新取一次所有的軟中斷。以便下面的代碼進(jìn)行處理后跳回到 restart 處重復(fù)執(zhí)行。 <br /></li><li>  pending = local_softirq_pending(); <br /></li><li>// 如果在上面的開(kāi)中斷執(zhí)行環(huán)境中觸發(fā)了硬件中斷,且注冊(cè)了一個(gè)軟中斷的話(huà),這個(gè)軟中斷會(huì)設(shè)置 pending 位,但在當(dāng)前一直屏蔽軟中斷的環(huán)境下無(wú)法得到執(zhí)行,前面提到過(guò),因?yàn)?irq_exit() 和 do_softirq() 根本無(wú)法進(jìn)入到這個(gè)處理過(guò)程中來(lái)。這個(gè)在上面周詳?shù)挠涗涍^(guò)了。那么在這里又有了一個(gè)執(zhí)行的機(jī)會(huì)。注意:雖然當(dāng)前環(huán)境一直是處于屏蔽軟中斷執(zhí)行的環(huán)境中,但在這里又給出了一個(gè)執(zhí)行剛才在開(kāi)中斷環(huán)境過(guò)程中觸發(fā)硬件中斷時(shí)所注冊(cè)的軟中斷的機(jī)會(huì),其實(shí)只要理解了軟中斷機(jī)制就會(huì)知道,無(wú)非是在一些特定環(huán)境下調(diào)用 ISR 注冊(cè)到軟中斷向量表里的函數(shù)而已。如果剛才觸發(fā)的硬件中斷注冊(cè)了軟中斷,并且重復(fù)執(zhí)行次數(shù)沒(méi)有到 10 次的話(huà),那么則跳轉(zhuǎn)到 restart 標(biāo)志處重復(fù)以上所介紹的所有步驟:設(shè)置軟中斷標(biāo)志位,重新開(kāi)中斷執(zhí)行... <br /></li><li>// 注意:這里是要兩個(gè)條件都滿(mǎn)足的情況下才可能重復(fù)以上步驟。 <br /></li><li>if (pending && --max_restart) <br /></li><li>    goto restart; <br /></li><li>// 如果以上步驟重復(fù)了 10 次后還有 pending 的軟中斷的話(huà),那么系統(tǒng)在一定時(shí)間內(nèi)可能達(dá)到了一個(gè)峰值,為了平衡這點(diǎn)。系統(tǒng)專(zhuān)門(mén)建立了一個(gè) ksoftirqd 線(xiàn)程來(lái)處理,這樣避免在一 定時(shí)間內(nèi)負(fù)荷太大。這個(gè) ksoftirqd 線(xiàn)程本身是個(gè)大循環(huán),在某些條件下為了不負(fù)載過(guò)重,他是能被其他進(jìn)程搶占的,但注意,他是顯示的調(diào)用了 preempt_xxx() 和 schedule()才會(huì)被搶占和轉(zhuǎn)換的。這么做的原因是因?yàn)樵谒坏┱{(diào)用 local_softirq_pending() 函數(shù)檢測(cè)到有 pending 的軟中斷需要處理的時(shí)候,則會(huì)顯示的調(diào)用 do_softirq() 來(lái)處理軟中 斷。也就是說(shuō),下面代碼喚醒的 ksoftirqd 線(xiàn)程有可能會(huì)回到這個(gè)函數(shù)當(dāng)中來(lái),尤其是在系統(tǒng)需要響應(yīng)非常多軟中斷的情況下,他的調(diào)用入口是 do_softirq(),這也就是為什么在 do_softirq() 的入口處也會(huì)用 in_interrupt() 函數(shù)來(lái)判斷是否有軟中斷正在處理的原因了,目的還是為了防止重入。ksoftirqd 實(shí)現(xiàn)看下面對(duì) ksoftirqd() 函數(shù)的分析。 <br /></li><li>if (pending) <br /></li><li>// 此函數(shù)實(shí)際是調(diào)用 wake_up_process() 來(lái)喚醒 ksoftirqd <br /></li><li>   wakeup_softirqd(); <br /></li><li>trace_softirq_exit(); <br /></li><li>account_system_vtime(current); <br /></li><li>// 到最后才開(kāi)軟中斷執(zhí)行環(huán)境,允許軟中斷執(zhí)行。注意:這里使用的不是 local_bh_enable(),不會(huì)再次觸發(fā) do_softirq()的調(diào)用。 <br /></li><li>_local_bh_enable(); <br /></li><li>}</li></ol>

1.5ksoftirqd

這個(gè)函數(shù)就是ksoftirqd內(nèi)核線(xiàn)程對(duì)應(yīng)的執(zhí)行函數(shù)。只要有待處理的軟中斷(由softirq_pending()函數(shù)負(fù)責(zé)發(fā)現(xiàn)),ksoftirq就會(huì)調(diào)用do_softirq()去處理它們。通過(guò)重復(fù)執(zhí)行這樣的操作,重新觸發(fā)的軟中斷也會(huì)被執(zhí)行。如果有必要的話(huà),每次迭代后都會(huì)調(diào)用schedule()以便讓更重要的進(jìn)程得到處理機(jī)會(huì)。當(dāng)所有需要執(zhí)行的操作都完成以后,該內(nèi)核線(xiàn)程將自己設(shè)置為T(mén)ASK_INTERTUPTIBLE狀態(tài),喚起調(diào)度程序選擇其他可執(zhí)行的進(jìn)程投入運(yùn)行。

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>static int ksoftirqd(void * __bind_cpu)<br /></li><li>{<br /></li><li>// 顯示調(diào)用此函數(shù)設(shè)置當(dāng)前進(jìn)程的靜態(tài)優(yōu)先級(jí)。當(dāng)然,這個(gè)優(yōu)先級(jí)會(huì)隨調(diào)度器策略而變化。<br /></li><li>set_user_nice(current, 19);<br /></li><li>// 設(shè)置當(dāng)前進(jìn)程不允許被掛啟<br /></li><li>current->flags |= PF_NOFREEZE;<br /></li><li>//設(shè)置當(dāng)前進(jìn)程狀態(tài)為可中斷的狀態(tài),這種睡眠狀態(tài)可響應(yīng)信號(hào)處理等。<br /></li><li>set_current_state(TASK_INTERRUPTIBLE);<br /></li><li>// 下面是個(gè)大循環(huán),循環(huán)判斷當(dāng)前進(jìn)程是否會(huì)停止,不會(huì)則繼續(xù)判斷當(dāng)前是否有 pending 的軟中斷需要處理。<br /></li><li>while (!kthread_should_stop()) {<br /></li><li>   // 如果能進(jìn)行處理,那么在此處理期間內(nèi)禁止當(dāng)前進(jìn)程被搶占。<br /></li><li>   preempt_disable();<br /></li><li>   // 首先判斷系統(tǒng)當(dāng)前沒(méi)有需要處理的 pending 狀態(tài)的軟中斷<br /></li><li>   if (!local_softirq_pending()) {<br /></li><li>// 沒(méi)有的話(huà)在主動(dòng)放棄 CPU 前先要允許搶占,因?yàn)橐恢笔窃诓辉试S搶占狀態(tài)下執(zhí)行的代碼。<br /></li><li>preempt_enable_no_resched();<br /></li><li>// 顯示調(diào)用此函數(shù)主動(dòng)放棄 CPU 將當(dāng)前進(jìn)程放入睡眠隊(duì)列,并轉(zhuǎn)換新的進(jìn)程執(zhí)行(調(diào)度器相關(guān)不記錄在此)<br /></li><li>schedule();<br /></li><li>// 注意:如果當(dāng)前顯示調(diào)用 schedule() 函數(shù)主動(dòng)轉(zhuǎn)換的進(jìn)程再次被調(diào)度執(zhí)行的話(huà),那么將從調(diào)用這個(gè)函數(shù)的下一條語(yǔ)句開(kāi)始執(zhí)行。也就是說(shuō),在這里當(dāng)前進(jìn)程再次被執(zhí)行的話(huà),將會(huì)執(zhí)行下面的 preempt_disable() 函數(shù)。當(dāng)進(jìn)程再度被調(diào)度時(shí),在以下處理期間內(nèi)禁止當(dāng)前進(jìn)程被搶占。<br /></li><li>preempt_disable();<br /></li><li>}<br /></li><li>/*設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)。注意:已設(shè)置了當(dāng)前進(jìn)程不可搶占在進(jìn)入循環(huán)后,以上兩個(gè)分支不論走哪個(gè)都會(huì)執(zhí)行到這里。一是進(jìn)入循環(huán)時(shí)就有 pending 的軟中斷需要執(zhí)行時(shí)。二是進(jìn)入循環(huán)時(shí)沒(méi)有 pending 的軟中斷,當(dāng)前進(jìn)程再次被調(diào)度獲得 CPU 時(shí)繼續(xù)執(zhí)行時(shí)。*/<br /></li><li>__set_current_state(TASK_RUNNING);<br /></li><li>/* 循環(huán)判斷是否有 pending 的軟中斷,如果有則調(diào)用 do_softirq()來(lái)做具體處理。注意:這里又是個(gè) do_softirq() 的入口點(diǎn),那么在 __do_softirq() 當(dāng)中循環(huán)處理 10 次軟中斷的回調(diào)函數(shù)后,如果更有 pending 的話(huà),會(huì)又調(diào)用到這里。那么在這里則又會(huì)有可能去調(diào)用 __do_softirq() 來(lái)處理軟中斷回調(diào)函數(shù)。在前面介紹 __do_softirq() 時(shí)已提到過(guò),處理 10 次還處理不完的話(huà)說(shuō)明系統(tǒng)正處于繁忙狀態(tài)。根據(jù)以上分析,我們能試想如果在系統(tǒng)非常繁忙時(shí),這個(gè)進(jìn)程將會(huì)和 do_softirq() 相互交替執(zhí)行,這時(shí)此進(jìn)程占用 CPU 應(yīng)該會(huì)非常高,雖然下面的 cond_resched()函數(shù)做了一些處理,他在處理完一輪軟中斷后當(dāng)前處理進(jìn)程可能會(huì)因被調(diào)度而減少 CPU 負(fù)荷,不過(guò)在非常繁忙時(shí)這個(gè)進(jìn)程仍然有可能大量占用 CPU。*/<br /></li><li>while (local_softirq_pending()) {<br /></li><li>/* Preempt disable stops cpu going offline. If already offline, we’ll be on wrong CPU: don’t process */<br /></li><li>if (cpu_is_offline((long)__bind_cpu))<br /></li><li>/*如果當(dāng)前被關(guān)聯(lián)的 CPU 無(wú)法繼續(xù)處理則跳轉(zhuǎn)到 wait_to_die 標(biāo)記出,等待結(jié)束并退出。*/<br /></li><li>goto wait_to_die;<br /></li><li>/*執(zhí)行 do_softirq() 來(lái)處理具體的軟中斷回調(diào)函數(shù)。注意:如果此時(shí)有一個(gè)正在處理的軟中斷的話(huà),則會(huì)馬上返回,還記得前面介紹的 in_interrupt() 函數(shù)么。*/<br /></li><li>do_softirq();<br /></li><li>/*允許當(dāng)前進(jìn)程被搶占。*/<br /></li><li>preempt_enable_no_resched();<br /></li><li>/*這個(gè)函數(shù)有可能間接的調(diào)用 schedule() 來(lái)轉(zhuǎn)換當(dāng)前進(jìn)程,而且上面已允許當(dāng)前進(jìn)程可被搶占。也就是說(shuō)在處理完一輪軟中斷回調(diào)函數(shù)時(shí),有可能會(huì)轉(zhuǎn)換到其他進(jìn)程。我認(rèn)為這樣做的目的一是為了在某些負(fù)載超標(biāo)的情況下不至于讓這個(gè)進(jìn)程長(zhǎng)時(shí)間大量的占用 CPU,二是讓在有非常多軟中斷需要處理時(shí)不至于讓其他進(jìn)程得不到響應(yīng)。*/<br /></li><li>        cond_resched();<br /></li><li>       /* 禁止當(dāng)前進(jìn)程被搶占。*/<br /></li><li>preempt_disable();<br /></li><li>/* 處理完所有軟中斷了嗎?沒(méi)有的話(huà)繼續(xù)循環(huán)以上步驟*/<br /></li><li>     }<br /></li><li>/*待一切都處理完成后,允許當(dāng)前進(jìn)程被搶占,并設(shè)置當(dāng)前進(jìn)程狀態(tài)為可中斷狀態(tài),繼續(xù)循環(huán)以上所有過(guò)程。*/<br /></li><li>     preempt_enable();<br /></li><li>     set_current_state(TASK_INTERRUPTIBLE);<br /></li><li>}<br /></li><li>/*如果將會(huì)停止則設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)后直接返回。調(diào)度器會(huì)根據(jù)優(yōu)先級(jí)來(lái)使當(dāng)前進(jìn)程運(yùn)行。*/<br /></li><li>__set_current_state(TASK_RUNNING);<br /></li><li>return 0;<br /></li><li>/*一直等待到當(dāng)前進(jìn)程被停止*/</li><li>wait_to_die:</li><li>/*允許當(dāng)前進(jìn)程被搶占。*/<br /></li><li>preempt_enable();<br /></li><li>/* Wait for kthread_stop */<br /></li><li>/*設(shè)置當(dāng)前進(jìn)程狀態(tài)為可中斷的狀態(tài),這種睡眠狀態(tài)可響應(yīng)信號(hào)處理等。*/<br /></li><li>set_current_state(TASK_INTERRUPTIBLE);<br /></li><li>/*判斷當(dāng)前進(jìn)程是否會(huì)被停止,如果不是的話(huà)則設(shè)置進(jìn)程狀態(tài)為可中斷狀態(tài)并放棄當(dāng)前 CPU主動(dòng)轉(zhuǎn)換。也就是說(shuō)這里將一直等待當(dāng)前進(jìn)程將被停止時(shí)候才結(jié)束。*/<br /></li><li>while (!kthread_should_stop()) {<br /></li><li>schedule();<br /></li><li>set_current_state(TASK_INTERRUPTIBLE);<br /></li><li>}<br /></li><li>/*如果將會(huì)停止則設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)后直接返回。調(diào)度器會(huì)根據(jù)優(yōu)先級(jí)來(lái)使當(dāng)前進(jìn)程運(yùn)行。*/<br /></li><li>__set_current_state(TASK_RUNNING);<br /></li><li>return 0;<br /></li><li>}</li></ol>

最后說(shuō)明一下,因?yàn)閠asklet也是通過(guò)軟中斷實(shí)現(xiàn)的,所以tasklet過(guò)多也會(huì)導(dǎo)致ksoftirqd線(xiàn)程的調(diào)度,進(jìn)而再進(jìn)程上下文中執(zhí)行tasklet。(ksoftirqd執(zhí)行軟中斷處理程序,tasklet對(duì)應(yīng)的軟中斷處理程序執(zhí)行所有調(diào)度的tasklet)

2.events

下面看events線(xiàn)程,提到這個(gè)線(xiàn)程就不得不說(shuō)道“工作隊(duì)列(workqueue)”了,這個(gè)線(xiàn)程是就是工作隊(duì)了用來(lái)執(zhí)行隊(duì)列中的工作的。

2.1什么是workqueue?

Workqueue也是linux下半部(包括軟中斷、tasklet、工作隊(duì)列)實(shí)現(xiàn)的一種方式。Linux中的Workqueue機(jī)制就是為了簡(jiǎn)化內(nèi)核線(xiàn)程的創(chuàng)建。通過(guò)調(diào)用workqueue的接口就能創(chuàng)建內(nèi)核線(xiàn)程。并且可以根據(jù)當(dāng)前系統(tǒng)CPU的個(gè)數(shù)創(chuàng)建線(xiàn)程的數(shù)量,使得線(xiàn)程處理的事務(wù)能夠并行化。

Workqueue是內(nèi)核中實(shí)現(xiàn)簡(jiǎn)單而有效的機(jī)制,他顯然簡(jiǎn)化了內(nèi)核daemon的創(chuàng)建,方便了用戶(hù)的編程。

2.2Workqueue機(jī)制的實(shí)現(xiàn)

Workqueue機(jī)制中定義了兩個(gè)重要的數(shù)據(jù)結(jié)構(gòu),分析如下:

1.cpu_workqueue_struct結(jié)構(gòu)。該結(jié)構(gòu)將CPU和內(nèi)核線(xiàn)程進(jìn)行了綁定。在創(chuàng)建workqueue的過(guò)程中,Linux根據(jù)當(dāng)前系統(tǒng)CPU的個(gè)數(shù)創(chuàng)建cpu_workqueue_struct。在該結(jié)構(gòu)主要維護(hù)了一個(gè)任務(wù)(work_struct)隊(duì)列,以及內(nèi)核線(xiàn)程需要睡眠的等待隊(duì)列,另外還維護(hù)了一個(gè)任務(wù)上下文,即task_struct。

2.work_struct結(jié)構(gòu)是對(duì)任務(wù)的抽象。在該結(jié)構(gòu)中需要維護(hù)具體的任務(wù)方法,需要處理的數(shù)據(jù),以及任務(wù)處理的時(shí)間。該結(jié)構(gòu)定義如下:

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>struct work_struct {<br /></li><li> unsigned long pending;<br /></li><li>  struct list_head entry; /* 將任務(wù)掛載到queue的掛載點(diǎn) */<br /></li><li>  void (*func)(void *); /* 任務(wù)方法 */<br /></li><li>  void *data; /* 任務(wù)處理的數(shù)據(jù)*/<br /></li><li>  void *wq_data; /* work的屬主 */<br /></li><li>  strut timer_list timer; /* 任務(wù)延時(shí)處理定時(shí)器 */<br /></li><li>};</li></ol>

當(dāng)用戶(hù)調(diào)用workqueue的初始化接口create_workqueue或者create_singlethread_workqueue對(duì)workqueue隊(duì)列進(jìn)行初始化時(shí),內(nèi)核就開(kāi)始為用戶(hù)分配一個(gè)workqueue對(duì)象,并且將其鏈到一個(gè)全局的workqueue隊(duì)列中。然后Linux根據(jù)當(dāng)前CPU的情況,為workqueue對(duì)象分配與CPU個(gè)數(shù)相同的cpu_workqueue_struct對(duì)象,每個(gè)cpu_workqueue_struct對(duì)象都會(huì)存在一條任務(wù)隊(duì)列。緊接著,Linux為每個(gè)cpu_workqueue_struct對(duì)象分配一個(gè)內(nèi)核thread,即內(nèi)核daemon去處理每個(gè)隊(duì)列中的任務(wù)。至此,用戶(hù)調(diào)用初始化接口將workqueue初始化完畢,返回workqueue的指針。

在初始化workqueue過(guò)程中,內(nèi)核需要初始化內(nèi)核線(xiàn)程,注冊(cè)的內(nèi)核線(xiàn)程工作比較簡(jiǎn)單,就是不斷的掃描對(duì)應(yīng)cpu_workqueue_struct中的任務(wù)隊(duì)列,從中獲取一個(gè)有效任務(wù),然后執(zhí)行該任務(wù)。所以如果任務(wù)隊(duì)列為空,那么內(nèi)核daemon就在cpu_workqueue_struct中的等待隊(duì)列上睡眠,直到有人喚醒daemon去處理任務(wù)隊(duì)列。

Workqueue初始化完畢之后,將任務(wù)運(yùn)行的上下文環(huán)境構(gòu)建起來(lái)了,但是具體還沒(méi)有可執(zhí)行的任務(wù),所以,需要定義具體的work_struct對(duì)象。然后將work_struct加入到任務(wù)隊(duì)列中,Linux會(huì)喚醒daemon去處理任務(wù)。

上述描述的workqueue內(nèi)核實(shí)現(xiàn)原理可以描述如下:

在Workqueue機(jī)制中,提供了一個(gè)系統(tǒng)默認(rèn)的workqueue隊(duì)列——keventd_wq,這個(gè)隊(duì)列是Linux系統(tǒng)在初始化的時(shí)候就創(chuàng)建的。用戶(hù)可以直接初始化一個(gè)work_struct對(duì)象,然后在該隊(duì)列中進(jìn)行調(diào)度,使用更加方便。

我們看到的events/0,events/1這些內(nèi)核線(xiàn)程就是這個(gè)默認(rèn)工作隊(duì)列再每個(gè)cpu上創(chuàng)建的執(zhí)行任務(wù)(work)的kthread。

有人會(huì)問(wèn),那我們?nèi)绻约簞?chuàng)建工作隊(duì)列呢?如果通過(guò)create_singlethread_workqueue來(lái)創(chuàng)建,那么只會(huì)產(chǎn)生一個(gè)kthread,如果使用create_workqueue創(chuàng)建,則和默認(rèn)工作隊(duì)列一樣,在每個(gè)cpu上創(chuàng)建一個(gè)kthread,kthread的名字有參數(shù)傳入。

lWorkqueue編程接口

序號(hào)

接口函數(shù)

說(shuō)明

1

create_workqueue

用于創(chuàng)建一個(gè)workqueue隊(duì)列,為系統(tǒng)中的每個(gè)CPU都創(chuàng)建一個(gè)內(nèi)核線(xiàn)程。輸入?yún)?shù):

@name:workqueue的名稱(chēng)

2

create_singlethread_workqueue

用于創(chuàng)建workqueue,只創(chuàng)建一個(gè)內(nèi)核線(xiàn)程。輸入?yún)?shù):

@name:workqueue名稱(chēng)

3

destroy_workqueue

釋放workqueue隊(duì)列。輸入?yún)?shù):

@workqueue_struct:需要釋放的workqueue隊(duì)列指針

4

schedule_work

調(diào)度執(zhí)行一個(gè)具體的任務(wù),執(zhí)行的任務(wù)將會(huì)被掛入Linux系統(tǒng)提供的workqueue——keventd_wq輸入?yún)?shù):

@work_struct:具體任務(wù)對(duì)象指針

5

schedule_delayed_work

延遲一定時(shí)間去執(zhí)行一個(gè)具體的任務(wù),功能與schedule_work類(lèi)似,多了一個(gè)延遲時(shí)間,輸入?yún)?shù):

@work_struct:具體任務(wù)對(duì)象指針

@delay:延遲時(shí)間

6

queue_work

調(diào)度執(zhí)行一個(gè)指定workqueue中的任務(wù)。輸入?yún)?shù):

@workqueue_struct:指定的workqueue指針

@work_struct:具體任務(wù)對(duì)象指針

7

queue_delayed_work

延遲調(diào)度執(zhí)行一個(gè)指定workqueue中的任務(wù),功能與queue_work類(lèi)似,輸入?yún)?shù)多了一個(gè)delay。


www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1124517.htmlTechArticleLinux系統(tǒng)中的知名內(nèi)核線(xiàn)程(1)——ksoftirqd和events Linux系統(tǒng)中的知名內(nèi)核線(xiàn)程(1)——ksoftirqd和events ——lvyilong316 我們知道linux系統(tǒng)中有很多系...
本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線(xiàn)人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

熱門(mén)話(huà)題

新報(bào)告對(duì)傳聞中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相機(jī)升級(jí)進(jìn)行了嚴(yán)厲的評(píng)估 新報(bào)告對(duì)傳聞中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相機(jī)升級(jí)進(jìn)行了嚴(yán)厲的評(píng)估 Sep 12, 2024 pm 12:23 PM

最近幾天,Ice Universe 不斷披露有關(guān) Galaxy S25 Ultra 的詳細(xì)信息,人們普遍認(rèn)為這款手機(jī)將是三星的下一款旗艦智能手機(jī)。除此之外,泄密者聲稱(chēng)三星只計(jì)劃升級(jí)一款相機(jī)

三星 Galaxy S25 Ultra 泄露了第一張渲染圖,傳聞中的設(shè)計(jì)變化被曝光 三星 Galaxy S25 Ultra 泄露了第一張渲染圖,傳聞中的設(shè)計(jì)變化被曝光 Sep 11, 2024 am 06:37 AM

OnLeaks 現(xiàn)在與 Android Headlines 合作,首次展示了 Galaxy S25 Ultra,幾天前,他試圖從他的 X(以前的 Twitter)粉絲那里籌集到 4,000 美元以上的資金,但失敗了。對(duì)于上下文,嵌入在 h 下面的渲染圖像

IFA 2024 | TCL 的 NXTPAPER 14 在性能上無(wú)法與 Galaxy Tab S10 Ultra 相媲美,但在尺寸上幾乎可以與之媲美 IFA 2024 | TCL 的 NXTPAPER 14 在性能上無(wú)法與 Galaxy Tab S10 Ultra 相媲美,但在尺寸上幾乎可以與之媲美 Sep 07, 2024 am 06:35 AM

除了發(fā)布兩款新智能手機(jī)外,TCL 還發(fā)布了一款名為 NXTPAPER 14 的新 Android 平板電腦,其大屏幕尺寸是其賣(mài)點(diǎn)之一。 NXTPAPER 14 采用 TCL 標(biāo)志性品牌啞光液晶面板 3.0 版本

Vivo Y300 Pro 在 7.69 毫米纖薄機(jī)身中配備 6,500 mAh 電池 Vivo Y300 Pro 在 7.69 毫米纖薄機(jī)身中配備 6,500 mAh 電池 Sep 07, 2024 am 06:39 AM

Vivo Y300 Pro剛剛?cè)媪料啵亲畋〉闹卸薃ndroid手機(jī)之一,配備大電池。準(zhǔn)確來(lái)說(shuō),這款智能手機(jī)的厚度僅為 7.69 毫米,但配備了 6,500 mAh 的電池。這與最近推出的容量相同

三星 Galaxy S24 FE 預(yù)計(jì)將以低于預(yù)期的價(jià)格推出,有四種顏色和兩種內(nèi)存選項(xiàng) 三星 Galaxy S24 FE 預(yù)計(jì)將以低于預(yù)期的價(jià)格推出,有四種顏色和兩種內(nèi)存選項(xiàng) Sep 12, 2024 pm 09:21 PM

三星尚未就何時(shí)更新其 Fan Edition (FE) 智能手機(jī)系列提供任何提示。目前來(lái)看,Galaxy S23 FE 仍然是該公司的最新版本,于 2023 年 10 月年初推出。

iQOO Z9 Turbo Plus:可能增強(qiáng)的系列旗艦產(chǎn)品已開(kāi)始預(yù)訂 iQOO Z9 Turbo Plus:可能增強(qiáng)的系列旗艦產(chǎn)品已開(kāi)始預(yù)訂 Sep 10, 2024 am 06:45 AM

OnePlus的姐妹品牌iQOO的2023-4年產(chǎn)品周期可能即將結(jié)束;盡管如此,該品牌已宣布 Z9 系列的開(kāi)發(fā)尚未結(jié)束。它的最終版,也可能是最高端的 Turbo+ 變體剛剛按照預(yù)測(cè)發(fā)布。時(shí)間

新報(bào)告對(duì)傳聞中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相機(jī)升級(jí)進(jìn)行了嚴(yán)厲的評(píng)估 新報(bào)告對(duì)傳聞中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相機(jī)升級(jí)進(jìn)行了嚴(yán)厲的評(píng)估 Sep 12, 2024 pm 12:22 PM

最近幾天,Ice Universe 不斷披露有關(guān) Galaxy S25 Ultra 的詳細(xì)信息,人們普遍認(rèn)為這款手機(jī)將是三星的下一款旗艦智能手機(jī)。除此之外,泄密者聲稱(chēng)三星只計(jì)劃升級(jí)一款相機(jī)

小米紅米 Note 14 Pro Plus 上市,成為首款配備 Light Hunter 800 攝像頭的高通 Snapdragon 7s Gen 3 智能手機(jī) 小米紅米 Note 14 Pro Plus 上市,成為首款配備 Light Hunter 800 攝像頭的高通 Snapdragon 7s Gen 3 智能手機(jī) Sep 27, 2024 am 06:23 AM

Redmi Note 14 Pro Plus 現(xiàn)已正式成為去年 Redmi Note 13 Pro Plus 的直接后繼產(chǎn)品(亞馬遜售價(jià) 375 美元)。正如預(yù)期的那樣,Redmi Note 14 Pro Plus與Redmi Note 14和Redmi Note 14 Pro一起成為Redmi Note 14系列的主角。李

See all articles