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

Table of Contents
Well-known kernel threads in Linux systems (1)——ksoftirqd and events
1.5ksoftirqd
1.1irq_exit
1.2in_interrupt
1.4__do_softirq
2.events
2.1什么是workqueue?
2.2Workqueue機(jī)制的實(shí)現(xiàn)
Home Backend Development PHP Tutorial Well-known kernel threads in Linux systems (1) - ksoftirqd and events_PHP tutorial

Well-known kernel threads in Linux systems (1) - ksoftirqd and events_PHP tutorial

Jul 12, 2016 am 08:53 AM
android

Well-known kernel threads in Linux systems (1)——ksoftirqd and events

Well-known kernel threads in Linux systems (1)——ksoftirqd and events
—— lvyilong316

We know that there are many kernel threads (kthreads) created by the system in the Linux system. These kernel threads are the guarantee for the normal operation of the system. Here we take a look at two of the more well-known ones: ksoftirqd and events.

1.ksoftirqd

When it comes to ksoftirqd, we have to say "softirq", because this thread is used to execute softirqs (to be precise, it should be executed multiple softirqs). We know that in terms of priority, interrupts > soft interrupts > user processes, which means interrupts can interrupt soft interrupts, and soft interrupts can interrupt user processes.

As for soft interrupts, the kernel will execute them at several special times (note the difference between execution and scheduling. Scheduling soft interrupts only marks the soft interrupts as to be executed and does not actually execute them). Handling when the handler returns is most common. Softirqs can sometimes be triggered very frequently (such as during heavy network traffic). What's even more unfavorable is that the execution function of soft interrupts sometimes schedules itself, so if soft interrupts themselves occur more frequently, and they have the ability to reset themselves to an executable state, it will lead to user space 's process cannot get enough processing time and is starved. To avoid starvation of user processes. The kernel developers made some compromises. In the end, the kernel implementation will not immediately handle soft interrupts that are retriggered by the soft interrupt itself (soft interrupt nesting is not allowed). As an improvement, the kernel will wake up a group of kernel threads to handle these excessive soft interrupts. These kernel threads run at the lowest priority (nice value is 19), which prevents them from competing for resources with other important tasks, but they It will definitely be executed eventually, so this solution can ensure that when the soft interrupt load is heavy, the user process will not be starved because it cannot get processing time. Correspondingly, it can also ensure that excessive soft interrupts will eventually be processed.

Each processor has one such thread. The names of all threads are called ksoftirq/n. The difference is n, which corresponds to the processor number.

Let’s take a detailed look at how softirqd is executed by ksoftirqd. First, let’s look at the processing and scheduling process of soft interrupts. A softirq must be scheduled (activated) before execution, the term is called "raisethesoftirq". The activated softirq is usually not executed immediately. It will usually check whether there is a pending softirq in the current system at a later time. If there is, execute it. The function for executing softirq in Linux is do_softirq(), and this function It will be called in two places, one is when the interrupt returns, and the other is the ksoftirqd kernel thread we discussed. Let's first look at the situation of interrupt return.

1.1irq_exit

//This function is called when the do_IRQ function exits after executing the hardware ISR.

<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>// 其實(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

Here we need to focus on analyzing the meaning of the in_interrupt() function. In the Linux kernel, in order to facilitate the judgment of which context the current execution path is in, several interfaces are defined:


<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>

From the comments, you can It can be seen that it includes: hardware interrupt context, software interrupt context, non-maskable context, etc. Among these macros, the preempt_count() macro is involved. This macro is a relatively important macro. It is commented in detail in the Linux source code:


<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>

As can be seen from the comments, the meaning of each bit of preempt_count:

(1) Bits 0~7 represent the preemption count, that is, the maximum preemption depth supported is 256

(2) bit8~15 represents the soft interrupt count, that is, the maximum number of soft interrupts supported is 256. It should be noted that since the soft interrupt is also subject to the pending status, a 32-bit variable, the actual maximum Only 32 soft interrupts can be supported.

(3) bit16~25 indicates the number of nesting levels of hardware interrupts, that is, the maximum supported nesting level is 1024. In actual circumstances, this is impossible because the number of nesting levels of interrupts is still limited. The size of the stack space for interrupt processing.

Having introduced so much, let’s focus on analyzing what does in_interrupt mentioned above mean?

<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>

As can be seen from its macro definition, the value of the in_interrupt macro is the number of hardware interrupt nesting levels, soft interrupt count and maskable interrupt. sum. So if the value of in_interrupt() is greater than 0, the soft interrupt will not be processed, which means that (a) when there is a hardware interrupt nesting, (b) or the soft interrupt is disabled (c) when the interrupt is not maskable, it will not be processed. Handle softirqs. Some people may ask whether soft interrupts are entered from irq_exit after interrupt processing? Hasn't the hard interrupt bit of preempt_count not been modified when the soft interrupt is executed? In fact, the modification has been made, and it is done in sub_preempt_count in the irq_exit function. In fact, if sub_preempt_count is executed, the interrupt handler is exited.

l注:軟中斷被禁止會增加軟中斷的計(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)核到底是怎么來處理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)行實(shí)際處理<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)行。要問為什么,那是因?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)境時只能被硬件中斷搶占 ,在這個時候是無法處理軟中斷的,因?yà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í)行,前面提到過,因?yàn)?irq_exit() 和 do_softirq() 根本無法進(jìn)入到這個處理過程中來。這個在上面周詳?shù)挠涗涍^了。那么在這里又有了一個執(zhí)行的機(jī)會。注意:雖然當(dāng)前環(huán)境一直是處于屏蔽軟中斷執(zhí)行的環(huán)境中,但在這里又給出了一個執(zhí)行剛才在開中斷環(huán)境過程中觸發(fā)硬件中斷時所注冊的軟中斷的機(jī)會,其實(shí)只要理解了軟中斷機(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)換的。這么做的原因是因?yà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 實(shí)現(xiàn)看下面對 ksoftirqd() 函數(shù)的分析。 <br /></li><li>if (pending) <br /></li><li>// 此函數(shù)實(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 前先要允許搶占,因?yàn)橐恢笔窃诓辉试S搶占狀態(tài)下執(zhí)行的代碼。<br /></li><li>preempt_enable_no_resched();<br /></li><li>// 顯示調(diào)用此函數(shù)主動放棄 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ù)主動轉(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>

最后說明一下,因?yàn)閠asklet也是通過軟中斷實(shí)現(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線程,提到這個線程就不得不說道“工作隊(duì)列(workqueue)”了,這個線程是就是工作隊(duì)了用來執(zhí)行隊(duì)列中的工作的。

2.1什么是workqueue?

Workqueue也是linux下半部(包括軟中斷、tasklet、工作隊(duì)列)實(shí)現(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)核中實(shí)現(xiàn)簡單而有效的機(jī)制,他顯然簡化了內(nèi)核daemon的創(chuàng)建,方便了用戶的編程。

2.2Workqueue機(jī)制的實(shí)現(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)隊(duì)列,以及內(nèi)核線程需要睡眠的等待隊(duì)列,另外還維護(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隊(duì)列進(jìn)行初始化時,內(nèi)核就開始為用戶分配一個workqueue對象,并且將其鏈到一個全局的workqueue隊(duì)列中。然后Linux根據(jù)當(dāng)前CPU的情況,為workqueue對象分配與CPU個數(shù)相同的cpu_workqueue_struct對象,每個cpu_workqueue_struct對象都會存在一條任務(wù)隊(duì)列。緊接著,Linux為每個cpu_workqueue_struct對象分配一個內(nèi)核thread,即內(nèi)核daemon去處理每個隊(duì)列中的任務(wù)。至此,用戶調(diào)用初始化接口將workqueue初始化完畢,返回workqueue的指針。

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

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

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

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

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

Some people may ask, what if we create a work queue ourselves? If created through create_singlethread_workqueue, only one kthread will be generated. If created using create_workqueue, a kthread will be created on each CPU like the default work queue. The name of the kthread is passed in as a parameter.

lWorkqueue programming interface

1
is used to create a workqueue and only creates one kernel thread. Input parameters: @name: workqueue name

序號

接口函數(shù)

說明

1

create_workqueue

用于創(chuàng)建一個workqueue隊(duì)列,為系統(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隊(duì)列。輸入?yún)?shù):

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

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。

Serial number


Interface function
Description

create_workqueue is used to create a The workqueue queue creates a kernel thread for each CPU in the system. Input parameters: @name: the name of the workqueue
2 create_singlethread_workqueue
3
destroy_workqueue Release the workqueue queue. Input parameters: @workqueue_struct: the workqueue queue pointer that needs to be released
4 schedule_work td> Schedule the execution of a specific task, and the executed task will be hooked into the workqueue provided by the Linux system— —keventd_wq input parameters: @work_struct: specific task object pointer
5 schedule_delayed_work td> Delay a certain period of time to perform a specific task. The function is similar to schedule_work, with an additional delay time. Input parameters: @work_struct: specific task object pointer@delay: delay time
6 queue_work Scheduling and executing tasks in a specified workqueue. Input parameters: @workqueue_struct: specified workqueue pointer@work_struct: specific task object pointer
7 queue_delayed_work Delayed scheduling executes tasks in a specified workqueue. The function is similar to queue_work, with an additional delay input parameter.
http://www.bkjia.com/PHPjc/1124517.htmlwww.bkjia.comtruehttp: //www.bkjia.com/PHPjc/1124517.htmlTechArticleWell-known kernel threads in Linux systems (1) - ksoftirqd and events Well-known kernel threads in Linux systems (1 )——ksoftirqd and events——lvyilong316 We know that there are many systems in Linux system...
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

New report delivers damning assessment of rumoured Samsung Galaxy S25, Galaxy S25 Plus and Galaxy S25 Ultra camera upgrades New report delivers damning assessment of rumoured Samsung Galaxy S25, Galaxy S25 Plus and Galaxy S25 Ultra camera upgrades Sep 12, 2024 pm 12:23 PM

In recent days, Ice Universe has been steadily revealing details about the Galaxy S25 Ultra, which is widely believed to be Samsung's next flagship smartphone. Among other things, the leaker claimed that Samsung only plans to bring one camera upgrade

Samsung Galaxy S25 Ultra leaks in first render images with rumoured design changes revealed Samsung Galaxy S25 Ultra leaks in first render images with rumoured design changes revealed Sep 11, 2024 am 06:37 AM

OnLeaks has now partnered with Android Headlines to provide a first look at the Galaxy S25 Ultra, a few days after a failed attempt to generate upwards of $4,000 from his X (formerly Twitter) followers. For context, the render images embedded below h

IFA 2024 | TCL\'s NXTPAPER 14 won\'t match the Galaxy Tab S10 Ultra in performance, but it nearly matches it in size IFA 2024 | TCL\'s NXTPAPER 14 won\'t match the Galaxy Tab S10 Ultra in performance, but it nearly matches it in size Sep 07, 2024 am 06:35 AM

Alongside announcing two new smartphones, TCL has also announced a new Android tablet called the NXTPAPER 14, and its massive screen size is one of its selling points. The NXTPAPER 14 features version 3.0 of TCL's signature brand of matte LCD panels

Vivo Y300 Pro packs 6,500 mAh battery in a slim 7.69 mm body Vivo Y300 Pro packs 6,500 mAh battery in a slim 7.69 mm body Sep 07, 2024 am 06:39 AM

The Vivo Y300 Pro just got fully revealed, and it's one of the slimmest mid-range Android phones with a large battery. To be exact, the smartphone is only 7.69 mm thick but features a 6,500 mAh battery. This is the same capacity as the recently launc

Samsung Galaxy S24 FE billed to launch for less than expected in four colours and two memory options Samsung Galaxy S24 FE billed to launch for less than expected in four colours and two memory options Sep 12, 2024 pm 09:21 PM

Samsung has not offered any hints yet about when it will update its Fan Edition (FE) smartphone series. As it stands, the Galaxy S23 FE remains the company's most recent edition, having been presented at the start of October 2023. However, plenty of

iQOO Z9 Turbo Plus: Reservations begin for the potentially beefed-up series flagship iQOO Z9 Turbo Plus: Reservations begin for the potentially beefed-up series flagship Sep 10, 2024 am 06:45 AM

OnePlus'sister brand iQOO has a 2023-4 product cycle that might be nearlyover; nevertheless, the brand has declared that it is not done with itsZ9series just yet. Its final, and possibly highest-end,Turbo+variant has just beenannouncedas predicted. T

New report delivers damning assessment of rumoured Samsung Galaxy S25, Galaxy S25 Plus and Galaxy S25 Ultra camera upgrades New report delivers damning assessment of rumoured Samsung Galaxy S25, Galaxy S25 Plus and Galaxy S25 Ultra camera upgrades Sep 12, 2024 pm 12:22 PM

In recent days, Ice Universe has been steadily revealing details about the Galaxy S25 Ultra, which is widely believed to be Samsung's next flagship smartphone. Among other things, the leaker claimed that Samsung only plans to bring one camera upgrade

Xiaomi Redmi Note 14 Pro Plus arrives as first Qualcomm Snapdragon 7s Gen 3 smartphone with Light Hunter 800 camera Xiaomi Redmi Note 14 Pro Plus arrives as first Qualcomm Snapdragon 7s Gen 3 smartphone with Light Hunter 800 camera Sep 27, 2024 am 06:23 AM

The Redmi Note 14 Pro Plus is now official as a direct successor to last year'sRedmi Note 13 Pro Plus(curr. $375 on Amazon). As expected, the Redmi Note 14 Pro Plus heads up the Redmi Note 14 series alongside theRedmi Note 14and Redmi Note 14 Pro. Li

See all articles