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

Jadual Kandungan
Linux系統(tǒng)中的知名內(nèi)核線程(1)——ksoftirqd和events
1.5ksoftirqd
1.1irq_exit
1.2in_interrupt
1.4__do_softirq
2.events
2.1什么是workqueue?
2.2Workqueue機(jī)制的實現(xiàn)
Rumah pembangunan bahagian belakang tutorial php Linux系統(tǒng)中的知名內(nèi)核線程(1)——ksoftirqd和events_PHP教程

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

Jul 12, 2016 am 08:53 AM
android

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

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

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

1.ksoftirqd

提到ksoftirqd就不得不說下“軟中斷(softirq)”,因為這個線程正是用來執(zhí)行軟中斷的(準(zhǔn)確的說應(yīng)該是執(zhí)行過多的軟中斷)。我們知道按照優(yōu)先級來說,中斷>軟中斷>用戶進(jìn)行,也就是說中斷可以打斷軟中斷,而軟中斷又可以打斷用戶進(jìn)程。

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

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

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

1.1irq_exit

//do_IRQ函數(shù)執(zhí)行完硬件ISR后退出時調(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); //這個位置修改preempt_count<br /></li><li>// 判斷當(dāng)前是否有硬件中斷嵌套,并且是否有軟中斷在 pending 狀態(tài),注意:這里只有兩個條件同時滿足時,才有可能調(diào)用 do_softirq() 進(jìn)入軟中斷。也就是說確認(rèn)當(dāng)前所有硬件中斷處理完成,且有硬件中斷安裝了軟中斷處理時理時才會進(jìn)入。關(guān)于in_interrupt()后面會詳細(xì)分析。<br /></li><li>if (!in_interrupt() && local_softirq_pending()) <br /></li><li>// 其實這里就是調(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í)行路徑在哪個上下文環(huán)境中,定義了幾個接口:


<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()這個宏,這個宏是一個比較重要的宏,在Linux源碼中對其做了詳細(xì)的注釋:


<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各個bit位的含義:

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

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

(3)bit16~25位表示硬件中斷嵌套層數(shù),即最大可支持的嵌套層次為1024,實際情況下這是不可能的,因為中斷的嵌套層數(shù)還受制于中斷處理的??臻g的大小。

介紹了這么多,現(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ù),軟中斷計數(shù)以及可屏蔽中斷三者之和。所以如果in_interrupt()的值大于0,就不會處理軟中斷,意思是(a)當(dāng)有硬件中斷嵌套,(b)或軟中斷被禁止(c)不可屏蔽中斷的情況下,不會去處理軟中斷。有人會問軟中斷不是從中斷處理后irq_exit中進(jìn)入的嗎?那軟中斷執(zhí)行時preempt_count的硬中斷位不是還沒有修改掉嗎?其實已經(jīng)做了修改,就在irq_exit函數(shù)中的sub_preempt_count中進(jìn)行。其實執(zhí)行過sub_preempt_count就算退出中斷處理程序了。

l注:軟中斷被禁止會增加軟中斷的計數(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)核到底是怎么來處理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>// 這個函數(shù)判斷,如果當(dāng)前有硬件中斷嵌套,或者軟中斷被禁止時,則馬上返回。在這個入口判斷主要是為了與 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)行實際處理<br /></li><li>if (pending)<br /></li><li>   __do_softirq();<br /></li><li>// 開中斷繼續(xù)執(zhí)行<br /></li><li> local_irq_restore(flags);<br /></li><li>}</li></ol>

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

真正的軟中斷處理再__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í)行到這里要禁止其他軟中斷,這里也就證明了每個 CPU 上同時運(yùn)行的軟中斷只能有一個。<br /></li><li>  __local_bh_disable((unsigned long)__builtin_return_address(0));<br /></li><li>  trace_softirq_enter();<br /></li><li>// 針對 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> // 到這里才開中斷運(yùn)行,注意:以前運(yùn)行狀態(tài)一直是關(guān)中斷運(yùn)行,這時當(dāng)前處理軟中斷才可能被硬件中斷搶占。也就是說在進(jìn)入軟中斷時不是一開始就會被硬件中斷搶占。只有在這里以后的代碼才可能被硬件中斷搶占。<br /></li><li>  local_irq_enable();<br /></li><li> // 這里要注意,以下代碼運(yùn)行時可以被硬件中斷搶占,但這個硬件中斷執(zhí)行完成后,它的所注冊的軟中斷無法馬上運(yùn)行,別忘了,現(xiàn)在雖是開硬件中斷執(zhí)行,但前面的 __local_bh_disable()函數(shù)屏蔽了軟中斷。所以這種環(huán)境下只能被硬件中斷搶占,但這個硬中斷注冊的軟中斷回調(diào)函數(shù)無法運(yùn)行。要問為什么,那是因為__local_bh_disable() 函數(shù)設(shè)置了一個標(biāo)志當(dāng)作互斥量,而這個標(biāo)志正是上面的 irq_exit() 和 do_softirq() 函數(shù)中的in_interrupt() 函數(shù)判斷的條件之一,也就是說 in_interrupt() 函數(shù)不僅檢測硬中斷而且還判斷了軟中斷。所以在這個環(huán)境下觸發(fā)硬中斷時注冊的軟中斷,根本無法重新進(jìn)入到這個函數(shù)中來,只能是做一個標(biāo)志,等待下面的重復(fù)循環(huán)(最大 MAX_SOFTIRQ_RESTART)才可能處理到這個時候觸發(fā)的硬件中斷所注冊的軟中斷。得到軟中斷向量表。<br /></li><li>  h = softirq_vec;<br /></li><li> // 循環(huán)處理所有 softirq 軟中斷注冊函數(shù)。</li><li> do {</li><li>// 如果對應(yīng)的軟中斷設(shè)置 pending 標(biāo)志則表明需要進(jìn)一步處理它所注冊的函數(shù)。<br /></li><li>if (pending & 1) {<br /></li><li>// 在這里執(zhí)行了這個軟中斷所注冊的回調(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 個軟中斷的回調(diào)函數(shù)。<br /></li><li>      pending >>= 1; <br /></li><li>} while (pending);<br /></li><li>// 關(guān)中斷執(zhí)行以下代碼。注意:這里又關(guān)中斷了,下面的代碼執(zhí)行過程中硬件中斷無法搶占。<br /></li><li>  local_irq_disable();<br /></li><li>// 前面提到過,在剛才開硬件中斷執(zhí)行環(huán)境時只能被硬件中斷搶占 ,在這個時候是無法處理軟中斷的,因為剛才開中斷執(zhí)行過程中可能多次被硬件中斷搶占,每搶占一次就有可能注冊一個軟中斷,所以要再重新取一次所有的軟中斷。以便下面的代碼進(jìn)行處理后跳回到 restart 處重復(fù)執(zhí)行。 <br /></li><li>  pending = local_softirq_pending(); <br /></li><li>// 如果在上面的開中斷執(zhí)行環(huán)境中觸發(fā)了硬件中斷,且注冊了一個軟中斷的話,這個軟中斷會設(shè)置 pending 位,但在當(dāng)前一直屏蔽軟中斷的環(huán)境下無法得到執(zhí)行,前面提到過,因為 irq_exit() 和 do_softirq() 根本無法進(jìn)入到這個處理過程中來。這個在上面周詳?shù)挠涗涍^了。那么在這里又有了一個執(zhí)行的機(jī)會。注意:雖然當(dāng)前環(huán)境一直是處于屏蔽軟中斷執(zhí)行的環(huán)境中,但在這里又給出了一個執(zhí)行剛才在開中斷環(huán)境過程中觸發(fā)硬件中斷時所注冊的軟中斷的機(jī)會,其實只要理解了軟中斷機(jī)制就會知道,無非是在一些特定環(huán)境下調(diào)用 ISR 注冊到軟中斷向量表里的函數(shù)而已。如果剛才觸發(fā)的硬件中斷注冊了軟中斷,并且重復(fù)執(zhí)行次數(shù)沒有到 10 次的話,那么則跳轉(zhuǎn)到 restart 標(biāo)志處重復(fù)以上所介紹的所有步驟:設(shè)置軟中斷標(biāo)志位,重新開中斷執(zhí)行... <br /></li><li>// 注意:這里是要兩個條件都滿足的情況下才可能重復(fù)以上步驟。 <br /></li><li>if (pending && --max_restart) <br /></li><li>    goto restart; <br /></li><li>// 如果以上步驟重復(fù)了 10 次后還有 pending 的軟中斷的話,那么系統(tǒng)在一定時間內(nèi)可能達(dá)到了一個峰值,為了平衡這點(diǎn)。系統(tǒng)專門建立了一個 ksoftirqd 線程來處理,這樣避免在一 定時間內(nèi)負(fù)荷太大。這個 ksoftirqd 線程本身是個大循環(huán),在某些條件下為了不負(fù)載過重,他是能被其他進(jìn)程搶占的,但注意,他是顯示的調(diào)用了 preempt_xxx() 和 schedule()才會被搶占和轉(zhuǎn)換的。這么做的原因是因為在他一旦調(diào)用 local_softirq_pending() 函數(shù)檢測到有 pending 的軟中斷需要處理的時候,則會顯示的調(diào)用 do_softirq() 來處理軟中 斷。也就是說,下面代碼喚醒的 ksoftirqd 線程有可能會回到這個函數(shù)當(dāng)中來,尤其是在系統(tǒng)需要響應(yīng)非常多軟中斷的情況下,他的調(diào)用入口是 do_softirq(),這也就是為什么在 do_softirq() 的入口處也會用 in_interrupt() 函數(shù)來判斷是否有軟中斷正在處理的原因了,目的還是為了防止重入。ksoftirqd 實現(xiàn)看下面對 ksoftirqd() 函數(shù)的分析。 <br /></li><li>if (pending) <br /></li><li>// 此函數(shù)實際是調(diào)用 wake_up_process() 來喚醒 ksoftirqd <br /></li><li>   wakeup_softirqd(); <br /></li><li>trace_softirq_exit(); <br /></li><li>account_system_vtime(current); <br /></li><li>// 到最后才開軟中斷執(zhí)行環(huán)境,允許軟中斷執(zhí)行。注意:這里使用的不是 local_bh_enable(),不會再次觸發(fā) do_softirq()的調(diào)用。 <br /></li><li>_local_bh_enable(); <br /></li><li>}</li></ol>

1.5ksoftirqd

這個函數(shù)就是ksoftirqd內(nèi)核線程對應(yīng)的執(zhí)行函數(shù)。只要有待處理的軟中斷(由softirq_pending()函數(shù)負(fù)責(zé)發(fā)現(xiàn)),ksoftirq就會調(diào)用do_softirq()去處理它們。通過重復(fù)執(zhí)行這樣的操作,重新觸發(fā)的軟中斷也會被執(zhí)行。如果有必要的話,每次迭代后都會調(diào)用schedule()以便讓更重要的進(jìn)程得到處理機(jī)會。當(dāng)所有需要執(zhí)行的操作都完成以后,該內(nèi)核線程將自己設(shè)置為TASK_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)先級。當(dāng)然,這個優(yōu)先級會隨調(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)信號處理等。<br /></li><li>set_current_state(TASK_INTERRUPTIBLE);<br /></li><li>// 下面是個大循環(huán),循環(huán)判斷當(dāng)前進(jìn)程是否會停止,不會則繼續(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)前沒有需要處理的 pending 狀態(tài)的軟中斷<br /></li><li>   if (!local_softirq_pending()) {<br /></li><li>// 沒有的話在主動放棄 CPU 前先要允許搶占,因為一直是在不允許搶占狀態(tài)下執(zhí)行的代碼。<br /></li><li>preempt_enable_no_resched();<br /></li><li>// 顯示調(diào)用此函數(shù)主動放棄 CPU 將當(dāng)前進(jìn)程放入睡眠隊列,并轉(zhuǎn)換新的進(jìn)程執(zhí)行(調(diào)度器相關(guān)不記錄在此)<br /></li><li>schedule();<br /></li><li>// 注意:如果當(dāng)前顯示調(diào)用 schedule() 函數(shù)主動轉(zhuǎn)換的進(jìn)程再次被調(diào)度執(zhí)行的話,那么將從調(diào)用這個函數(shù)的下一條語句開始執(zhí)行。也就是說,在這里當(dāng)前進(jìn)程再次被執(zhí)行的話,將會執(zhí)行下面的 preempt_disable() 函數(shù)。當(dāng)進(jìn)程再度被調(diào)度時,在以下處理期間內(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)后,以上兩個分支不論走哪個都會執(zhí)行到這里。一是進(jìn)入循環(huán)時就有 pending 的軟中斷需要執(zhí)行時。二是進(jìn)入循環(huán)時沒有 pending 的軟中斷,當(dāng)前進(jìn)程再次被調(diào)度獲得 CPU 時繼續(xù)執(zhí)行時。*/<br /></li><li>__set_current_state(TASK_RUNNING);<br /></li><li>/* 循環(huán)判斷是否有 pending 的軟中斷,如果有則調(diào)用 do_softirq()來做具體處理。注意:這里又是個 do_softirq() 的入口點(diǎn),那么在 __do_softirq() 當(dāng)中循環(huán)處理 10 次軟中斷的回調(diào)函數(shù)后,如果更有 pending 的話,會又調(diào)用到這里。那么在這里則又會有可能去調(diào)用 __do_softirq() 來處理軟中斷回調(diào)函數(shù)。在前面介紹 __do_softirq() 時已提到過,處理 10 次還處理不完的話說明系統(tǒng)正處于繁忙狀態(tài)。根據(jù)以上分析,我們能試想如果在系統(tǒng)非常繁忙時,這個進(jìn)程將會和 do_softirq() 相互交替執(zhí)行,這時此進(jìn)程占用 CPU 應(yīng)該會非常高,雖然下面的 cond_resched()函數(shù)做了一些處理,他在處理完一輪軟中斷后當(dāng)前處理進(jìn)程可能會因被調(diào)度而減少 CPU 負(fù)荷,不過在非常繁忙時這個進(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 無法繼續(xù)處理則跳轉(zhuǎn)到 wait_to_die 標(biāo)記出,等待結(jié)束并退出。*/<br /></li><li>goto wait_to_die;<br /></li><li>/*執(zhí)行 do_softirq() 來處理具體的軟中斷回調(diào)函數(shù)。注意:如果此時有一個正在處理的軟中斷的話,則會馬上返回,還記得前面介紹的 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>/*這個函數(shù)有可能間接的調(diào)用 schedule() 來轉(zhuǎn)換當(dāng)前進(jìn)程,而且上面已允許當(dāng)前進(jìn)程可被搶占。也就是說在處理完一輪軟中斷回調(diào)函數(shù)時,有可能會轉(zhuǎn)換到其他進(jìn)程。我認(rèn)為這樣做的目的一是為了在某些負(fù)載超標(biāo)的情況下不至于讓這個進(jìn)程長時間大量的占用 CPU,二是讓在有非常多軟中斷需要處理時不至于讓其他進(jìn)程得不到響應(yīng)。*/<br /></li><li>        cond_resched();<br /></li><li>       /* 禁止當(dāng)前進(jìn)程被搶占。*/<br /></li><li>preempt_disable();<br /></li><li>/* 處理完所有軟中斷了嗎?沒有的話繼續(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)以上所有過程。*/<br /></li><li>     preempt_enable();<br /></li><li>     set_current_state(TASK_INTERRUPTIBLE);<br /></li><li>}<br /></li><li>/*如果將會停止則設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)后直接返回。調(diào)度器會根據(jù)優(yōu)先級來使當(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)信號處理等。*/<br /></li><li>set_current_state(TASK_INTERRUPTIBLE);<br /></li><li>/*判斷當(dāng)前進(jìn)程是否會被停止,如果不是的話則設(shè)置進(jìn)程狀態(tài)為可中斷狀態(tài)并放棄當(dāng)前 CPU主動轉(zhuǎn)換。也就是說這里將一直等待當(dāng)前進(jìn)程將被停止時候才結(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>/*如果將會停止則設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)后直接返回。調(diào)度器會根據(jù)優(yōu)先級來使當(dāng)前進(jìn)程運(yùn)行。*/<br /></li><li>__set_current_state(TASK_RUNNING);<br /></li><li>return 0;<br /></li><li>}</li></ol>

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

2.events

下面看events線程,提到這個線程就不得不說道“工作隊列(workqueue)”了,這個線程是就是工作隊了用來執(zhí)行隊列中的工作的。

2.1什么是workqueue?

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

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

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

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

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

2.work_struct結(jié)構(gòu)是對任務(wù)的抽象。在該結(jié)構(gòu)中需要維護(hù)具體的任務(wù)方法,需要處理的數(shù)據(jù),以及任務(wù)處理的時間。該結(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ù)延時處理定時器 */<br /></li><li>};</li></ol>

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

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

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

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

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

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

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

lWorkqueue編程接口

序號

接口函數(shù)

說明

1

create_workqueue

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

@name:workqueue的名稱

2

create_singlethread_workqueue

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

@name:workqueue名稱

3

destroy_workqueue

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

@workqueue_struct:需要釋放的workqueue隊列指針

4

schedule_work

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

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

5

schedule_delayed_work

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

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

@delay:延遲時間

6

queue_work

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

@workqueue_struct:指定的workqueue指針

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

7

queue_delayed_work

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


www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1124517.htmlTechArticleLinux系統(tǒng)中的知名內(nèi)核線程(1)——ksoftirqd和events Linux系統(tǒng)中的知名內(nèi)核線程(1)——ksoftirqd和events ——lvyilong316 我們知道linux系統(tǒng)中有很多系...
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Tutorial PHP
1502
276
Laporan baharu memberikan penilaian yang memberatkan terhadap khabar angin tentang peningkatan kamera Samsung Galaxy S25, Galaxy S25 Plus dan Galaxy S25 Ultra Laporan baharu memberikan penilaian yang memberatkan terhadap khabar angin tentang peningkatan kamera Samsung Galaxy S25, Galaxy S25 Plus dan Galaxy S25 Ultra Sep 12, 2024 pm 12:23 PM

Dalam beberapa hari kebelakangan ini, Ice Universe terus mendedahkan butiran mengenai Galaxy S25 Ultra, yang secara meluas dipercayai sebagai telefon pintar utama Samsung yang seterusnya. Antara lain, pembocor itu mendakwa bahawa Samsung hanya merancang untuk membawa satu peningkatan kamera

Samsung Galaxy S25 Ultra bocor dalam imej paparan pertama dengan perubahan reka bentuk khabar angin didedahkan Samsung Galaxy S25 Ultra bocor dalam imej paparan pertama dengan perubahan reka bentuk khabar angin didedahkan Sep 11, 2024 am 06:37 AM

OnLeaks kini telah bekerjasama dengan Android Headlines untuk memberikan pandangan pertama pada Galaxy S25 Ultra, beberapa hari selepas percubaan gagal untuk menjana lebih daripada $4,000 daripada pengikut X (dahulunya Twitter). Untuk konteks, imej pemaparan yang dibenamkan di bawah h

IFA 2024 | NXTPAPER 14 TCL tidak akan sepadan dengan prestasi Galaxy Tab S10 Ultra, tetapi ia hampir sepadan dengan saiznya IFA 2024 | NXTPAPER 14 TCL tidak akan sepadan dengan prestasi Galaxy Tab S10 Ultra, tetapi ia hampir sepadan dengan saiznya Sep 07, 2024 am 06:35 AM

Di samping mengumumkan dua telefon pintar baharu, TCL juga telah mengumumkan tablet Android baharu yang dipanggil NXTPAPER 14, dan saiz skrinnya yang besar adalah salah satu nilai jualannya. NXTPAPER 14 menampilkan versi 3.0 jenama tandatangan TCL panel LCD matte

Vivo Y300 Pro mempunyai bateri 6,500 mAh dalam badan 7.69 mm yang tipis Vivo Y300 Pro mempunyai bateri 6,500 mAh dalam badan 7.69 mm yang tipis Sep 07, 2024 am 06:39 AM

Vivo Y300 Pro baru sahaja didedahkan sepenuhnya, dan ia merupakan salah satu telefon Android jarak pertengahan paling tipis dengan bateri yang besar. Tepatnya, telefon pintar ini hanya tebal 7.69 mm tetapi mempunyai bateri 6,500 mAh. Ini adalah kapasiti yang sama seperti yang dilancarkan baru-baru ini

Samsung Galaxy S24 FE dibilkan untuk melancarkan kurang daripada yang dijangkakan dalam empat warna dan dua pilihan memori Samsung Galaxy S24 FE dibilkan untuk melancarkan kurang daripada yang dijangkakan dalam empat warna dan dua pilihan memori Sep 12, 2024 pm 09:21 PM

Samsung belum menawarkan sebarang petunjuk lagi tentang bila ia akan mengemas kini siri telefon pintar Edisi Peminat (FE). Seperti sedia ada, Galaxy S23 FE kekal sebagai edisi terbaharu syarikat, telah dibentangkan pada awal Oktober 2023. Walau bagaimanapun, banyak

Laporan baharu memberikan penilaian yang memberatkan terhadap khabar angin tentang peningkatan kamera Samsung Galaxy S25, Galaxy S25 Plus dan Galaxy S25 Ultra Laporan baharu memberikan penilaian yang memberatkan terhadap khabar angin tentang peningkatan kamera Samsung Galaxy S25, Galaxy S25 Plus dan Galaxy S25 Ultra Sep 12, 2024 pm 12:22 PM

Dalam beberapa hari kebelakangan ini, Ice Universe terus mendedahkan butiran mengenai Galaxy S25 Ultra, yang secara meluas dipercayai sebagai telefon pintar utama Samsung yang seterusnya. Antara lain, pembocor itu mendakwa bahawa Samsung hanya merancang untuk membawa satu peningkatan kamera

iQOO Z9 Turbo Plus: Tempahan bermula untuk siri perdana yang berpotensi dipertingkatkan iQOO Z9 Turbo Plus: Tempahan bermula untuk siri perdana yang berpotensi dipertingkatkan Sep 10, 2024 am 06:45 AM

Jenama OnePlus iQOO mempunyai kitaran produk 2023-4 yang mungkin hampir tamat; Namun begitu, jenama itu telah mengisytiharkan bahawa ia belum selesai dengan siri Z9nya. Varian Turbo+yang terakhir, dan mungkin paling akhir, baru sahaja diumumkan seperti yang diramalkan. T

Xiaomi Redmi Note 14 Pro Plus tiba sebagai telefon pintar Qualcomm Snapdragon 7s Gen 3 pertama dengan kamera Light Hunter 800 Xiaomi Redmi Note 14 Pro Plus tiba sebagai telefon pintar Qualcomm Snapdragon 7s Gen 3 pertama dengan kamera Light Hunter 800 Sep 27, 2024 am 06:23 AM

Redmi Note 14 Pro Plus kini rasmi sebagai pengganti langsung kepada Redmi Note 13 Pro Plus tahun lepas (sekira $375 di Amazon). Seperti yang dijangkakan, Redmi Note 14 Pro Plus mengetuai siri Redmi Note 14 bersama Redmi Note 14 dan Redmi Note 14 Pro. Li

See all articles