精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入理解Linux內核之內核搶占

系統 Linux
我們或許經常聽說過內核搶占,可是我們是否真正理解它呢?內核搶占和搶占式內核究竟有什么關系呢?搶占計數器究竟干什么用?... 本文我們就來好好討論下,關于內核搶占的一些技術細節,力求讓大家理解內核搶占。

[[400324]]

本文轉載自微信公眾號「Linux內核遠航者」,作者Linux內核遠航者。轉載本文請聯系Linux內核遠航者公眾號。

1.開場白

環境:

處理器架構:arm64

內核源碼:linux-5.11

ubuntu版本:20.04.1

代碼閱讀工具:vim+ctags+cscope

我們或許經常聽說過內核搶占,可是我們是否真正理解它呢?內核搶占和搶占式內核究竟有什么關系呢?搶占計數器究竟干什么用?... 本文我們就來好好討論下,關于內核搶占的一些技術細節,力求讓大家理解內核搶占。

注:本文主要關注CFS調度類。

2.內核搶占和搶占式內核

我們經常使用uname -a命令能看到“PREEMPT”的字樣,沒錯,我們使用的是搶占式內核。

  1. # uname -a 
  2. Linux (none) 5.11.0-g08a3831f3ae1 #1 SMP PREEMPT Fri Apr 30 17:41:53 CST 2021 aarch64 GNU/Linux 

那什么是搶占式內核呢? 實際上,支持內核搶占的內核叫做搶占式內核,不支持內核搶占的內核叫做不可搶占式內核。那么問題又來了,什么是內核搶占呢?我們都知道,拿周期性的tick來說:對于用戶任務,當每個時鐘中斷到來后都會檢查它的實際運行時間是否超過理想運行時間,或者運行隊列中有沒有優先級更高的進程,一般如果滿足其中一個條件就會設置重新調度標志,然后在中斷返回用戶態的前夕發生調度,這是所謂的用戶任務搶占。

但是如果處于一個內核態的任務正在運行,這個時候發生中斷喚醒了一個高優先級的任務,那么這個被喚醒的任務能否被調度執行呢?這個時候就會分兩種情況分析,如果是搶占式內核那么高優先級任務就有可能搶占當前任務而調度執行(之所有是有可能是因為兩者虛擬運行時間差值要大于搶占粒度才允許搶占),如果是不可搶占式內核那么不允許搶占,除非當前進程執行完或者主動發生調度高優先級進程該有機會被調度。

也就是說,支持內核搶占的內核不僅允許在用戶態的任務可以被搶占,處在內核態的任務也允許被搶占(請注意這里說的是內核態,因為用戶空間任務可以通過系統調用等進入內核態),這樣對于交互性或者低延遲的應用場景很友好,如手持設備和桌面應用,響應會很快。而對于服務器來說,它就對吞吐量要求較高,希望獲得更多的cpu時間,而交互性或者低延遲都是次要的,所以被設計成不可搶占式內核。

下圖給出非搶占式內核調度情況:

下圖給出搶占式內核調度情況:

對比兩個圖可以發現:采用搶占式內核調度的情況下,在中斷中喚醒一個高優先級任務能夠得到很好的響應。

關于搶占式內核還是不可搶占式內核的選擇在源碼的kernel/Kconfig.preempt有所描述:

  1. config PREEMPT_NONE 
  2.         bool "No Forced Preemption (Server)" 
  3.         help 
  4.         ¦ This is the traditional Linux preemption model, geared towards 
  5.         ¦ throughput. It will still provide good latencies most of the 
  6.         ¦ time, but there are no guarantees and occasional longer delays 
  7.         ¦ are possible. 
  8.  
  9.         ¦ Select this option if you are building a kernel for a server or 
  10.         ¦ scientific/computation system, or if you want to maximize the 
  11.         ¦ raw processing power of the kernel, irrespective of scheduling 
  12.         ¦ latencies. 
  13.  
  14. config PREEMPT 
  15.         bool "Preemptible Kernel (Low-Latency Desktop)" 
  16.         depends on !ARCH_NO_PREEMPT 
  17.         select PREEMPTION 
  18.         select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK 
  19.         select PREEMPT_DYNAMIC if HAVE_PREEMPT_DYNAMIC 
  20.         help 
  21.         ¦ This option reduces the latency of the kernel by making 
  22.         ¦ all kernel code (that is not executing in a critical section
  23.         ¦ preemptible.  This allows reaction to interactive events by 
  24.         ¦ permitting a low priority process to be preempted involuntarily 
  25.         ¦ even if it is in kernel mode executing a system call and would 
  26.         ¦ otherwise not be about to reach a natural preemption point. 
  27.         ¦ This allows applications to run more 'smoothly' even when the 
  28.         ¦ system is under loadat the cost of slightly lower throughput 
  29.         ¦ and a slight runtime overhead to kernel code. 
  30.  
  31.         ¦ Select this if you are building a kernel for a desktop or 
  32.         ¦ embedded system with latency requirements in the milliseconds 
  33.         ¦ range. 

上面列舉了兩個編譯選項一個是支持內核搶占一個是不支持內核搶占,其實還有PREEMPT_VOLUNTARY和PREEMPT_RT,前者會顯式增加一些搶占點,后者用于支持實時性 。

3.重新調度標志和搶占計數器

內核有些路徑是不允許調度的,如原子上下文,那么這個時候如果喚醒一個高優先級的任務或者tick的時候檢查可重新調度條件滿足,那么高優先級的任務將不能馬上得到執行,但是我又要標識一下需要重新調度,那么就需要設置重新調度標志,當返回到可調度上下文的時候(如開搶占),這個時候就會檢查是否設置了這個標志來決定是否調用調度器來選擇下一個任務來運行。

標識重新調度是設置:

  1. //當前任務的task_struct的thread_info的flag 
  2. stsk->thread_info->flags設置TIF_NEED_RESCHED標志 
  3. #define TIF_NEED_RESCHED        1       /* rescheduling necessary */ 

內核的某些路徑上設置了這個標志之后,將在最近的調度點發生調度(可能是最近開啟搶占的時候,也可能是最近中斷異常返回的時候)。

當前任務被設置了重新調度標志,只是表明不久的將來會發生調度,并不是馬上發生調度,對于用戶任務來說就是中斷異常返回用戶態的前夕發生調度,而對于處于內核態的任務來說,想要在內核態搶占當前進程,僅僅置位重新調度標志還不行,還需要判斷當前進程的搶占計數器是否為0。

所有對于處于內核態的任務來說,搶占計數器對于重新調度至關重要,只要搶占計數器不為0,無論被喚醒的任務在緊急都不能獲得調度器,我們來看看這個搶占計數器:

  1. tsk->thread_info->preempt.count  

我們來看下對于arm64架構,搶占計數器的定義:

  1. 24 struct thread_info { 
  2. 25         unsigned long           flags;          /* low level flags */ 
  3.  
  4. 29         union { 
  5. 30                 u64             preempt_count;  /* 0 => preemptible, <0 => bug */ 
  6. 31                 struct { 
  7. 32 #ifdef CONFIG_CPU_BIG_ENDIAN 
  8. 33                         u32     need_resched; 
  9. 34                         u32     count
  10. 35 #else 
  11. 36                         u32     count
  12. 37                         u32     need_resched; 
  13. 38 #endif 
  14. 39                 } preempt; 
  15. 40         }; 
  16. 45 }; 

可以發現它是一個共用體,內核某些路徑使用preempt_count,有的是preempt,為何會使用這么奇怪的定義呢?因為一個成員可以表示兩種狀態:重新調度標志和搶占計數器的數值

當需要重新調度的時候會置位flags的TIF_NEED_RESCHED標志,與此同時會將preempt.need_resched清零。當檢查thread_info 的preempt_count==0成立時,說明搶占計數器的數值為0且flags的TIF_NEED_RESCHED標志被置位,這個時候可以進程重新調度(如中斷返回內核態前夕的檢查)。

下面看下如何設置重新調度標志:

  1. resched_curr   //kernel/sched/core.c 
  2.  613         if (cpu == smp_processor_id()) {    
  3.  614                 set_tsk_need_resched(curr); 
  4.  615                 set_preempt_need_resched(); 
  5.  616                 return;                     
  6.  617         }     
  7.  
  8.  
  9. 29 static inline void set_preempt_need_resched(void)   //arch/arm64/include/asm/preempt.h 
  10. 30 { 
  11. 31         current_thread_info()->preempt.need_resched = 0; 
  12. 32 } 
  13.                                

當內核的某個路徑設置重新調度標志(如時鐘中斷tick時),會調用到resched_curr 來設置重新調度標志:可以看到除了設置任務的flags的TIF_NEED_RESCHED標志外,還設置了preempt.need_resched為0。

如何清除重新調度標志:

  1. kernel/sched/core.c 
  2. __schedule    //主動調度或搶占式調度 都會調用到這 
  3.  5046         clear_tsk_need_resched(prev);  
  4.  5047         clear_preempt_need_resched();  
  5.  
  6. //arch/arm64/include/asm/preempt.h 
  7. 34 static inline void clear_preempt_need_resched(void)       
  8. 35 {                 
  9. 36         current_thread_info()->preempt.need_resched = 1; 
  10. 37 } 

可以看到在主調度器中,除了調用clear_tsk_need_resched來清除任務的flags的TIF_NEED_RESCHED標志外,會調用clear_preempt_need_resched來設置preempt.need_resched為1, 來清除重新調度。

下面為搶占計數器的各個域的表示:

0-7 表示搶占計數 ,8-15表示軟中斷計數, 16-19表示硬中斷計數,20-23表示不可屏蔽中斷計數。當進入不同的上下文時會設置響應的位域,表示在某個上下文中,當某個位域被設置,搶占計數器不為0,任務在內核態就不容許被搶占。

所以,搶占計數器有兩個作用:一個是標識內核路徑在某個原子上下文,一個是用來判斷是否允許任務在內核態被搶占。

  1. include/linux/preempt.h 
  2.  
  3. 85 /*                                                                                     
  4. 86  * Macros to retrieve the current execution context:                                   
  5. 87  *                                                                                     
  6. 88  * in_nmi()             - We're in NMI context                                         
  7. 89  * in_hardirq()         - We're in hard IRQ context                                    
  8. 90  * in_serving_softirq() - We're in softirq context                                     
  9. 91  * in_task()            - We're in task context                                        
  10. 92  */                                                                                    
  11. 93 #define in_nmi()                (nmi_count())     //判斷是否在 不可屏蔽中斷上下文                                   
  12. 94 #define in_hardirq()            (hardirq_count())     //判斷是否在硬中斷上下文                                     
  13. 95 #define in_serving_softirq()    (softirq_count() & SOFTIRQ_OFFSET)        //判斷是否在軟中斷上下文                 
  14. 96 #define in_task()               (!(in_nmi() | in_hardirq() | in_serving_softirq()))  //判斷是否在進程上下文  
  15. 97                                                                                        
  16.  
  17.  
  18.  98 /*                                                                               
  19.  99  * The following macros are deprecated and should not be used in new code:       
  20. 100  * in_irq()       - Obsolete version of in_hardirq()                             
  21. 101  * in_softirq()   - We have BH disabled, or are processing softirqs              
  22. 102  * in_interrupt() - We're in NMI,IRQ,SoftIRQ context or have BH disabled         
  23. 103  */                                                                              
  24. 104 #define in_irq()                (hardirq_count())    //判斷是否在硬中斷上下文                            
  25. 105 #define in_softirq()            (softirq_count())    //判斷是否在軟中斷上下文(關閉軟中斷或者在執行軟中斷)                               
  26. 106 #define in_interrupt()          (irq_count())      //判斷是否在中斷上下文(包括硬中斷 軟中斷和不可屏蔽中斷)                                 
  27.  
  28.  
  29. //判斷是否在原子上下文(搶占計數器不為0) 
  30. 144 #define in_atomic()     (preempt_count() != 0) 

4.內核搶占的調度時機

這里調度時機我將它細分為兩種情況,一種是不進行調度的cheek點,一種是真正的搶占點(即是調用主調度器進行調度):

cheek點->

tick的時候 : 滿足條件(任務使用完理想運行時間,運行時間大于最小搶占粒度且運行隊列有優先級更高的任務) 時,設置TIF_NEED_RESCHED標志,最近的搶占點發生調度 。

喚醒搶占 : 滿足條件(喚醒的任務與當前任務的虛擬運行時間差值大于最小喚醒搶占粒度 ,喚醒的任務虛擬運行時間更小) 時, 設置TIF_NEED_RESCHED標志,最近的搶占點發生調度。

搶占點->

中斷返回內核態 : 滿足條件(重新調度標志置位且搶占計數器為0) 時, 搶占式調度 。

打開搶占的時候 : (如開搶占,開中斷下半部,釋放自旋鎖) 滿足條件(重新調度標志置位且搶占計數器為0)時, 搶占式調度。

開啟軟中斷的時候 : 滿足條件(重新調度標志置位且搶占計數器為0)時, 搶占式調度。

中斷返回內核態是常規的搶占點,一般情況下即使沒有其他中斷產生,周期性的tick中斷也會發生, 滿足條件(重新調度標志置位且搶占計數器為0)時,當前任務就會被搶占。而在一些會發生多任務竟態的臨界區中,我們需要關閉內核搶占,有的直接調用preempt_disable, 有的是間接調用preempt_disable(如申請自旋鎖的臨界區), 有的則是關閉軟中斷等,這些都會導致搶占計數器不為0,但是在這些臨界區中如果中斷喚醒了高優先級的任務,中斷返回內核態的前夕是不能進行調度的,所以在這些臨界區結束的時候會檢查調度條件是否滿足,如果滿足進行搶占式調度,從而使得被喚醒的任務被及時的響應。一般,一些cheek點設置了當前任務的重新調度標志之后,如果搶占計數器為0,會在最近的搶占點發生調度(就是上面所說的三種情況)。還有需要注意的是:關搶占的臨界區中,只是禁止了當前任務所在cpu的內核搶占,其他cpu依然可以進行內核搶占,如果這段臨界區有可能被其他cpu訪問到,可以直接使用自旋鎖來保護。

4.1 cheek點

1) 時鐘中斷tick時:

  1. kernel/sched/core.c 
  2.  
  3. scheduler_tick 
  4. ->curr->sched_class->task_tick(rq, curr, 0) 
  5.  ->task_tick_fair 
  6.   ->entity_tick 
  7.    ->check_preempt_tick 
  8.     ->4374         if (delta_exec > ideal_runtime) {  //1.當前任務的實際運行時間大于理想運行時間 
  9.     4375                 resched_curr(rq_of(cfs_rq));   //設置重新調度標志 
  10.     4389         if (delta_exec < sysctl_sched_min_granularity) //當前任務的實際運行時間 小于 最小調度粒度嗎? 
  11.     4390                 return
  12.  
  13.     4398         if (delta > ideal_runtime)  //2.紅黑樹最左邊的任務的虛擬運行時間和當前任務的虛擬運行時間的差值小于 理想運行時間 
  14.     4399                 resched_curr(rq_of(cfs_rq)); //設置重新調度標志 

每個時鐘tick到來時,會調用scheduler_tick來檢查是否需要重新調度,以下兩個條件有一個發生都會設置重新調度標志:

1.當前任務的實際運行時間大于理想運行時間(保證任務在一個調度周期內運行時間不會超過理想運行時間,防止“流氓”任務一直霸占cpu,通過周期性的時鐘中斷奪回處理器的使用權)。

2.當前任務的實際運行時間大于最小調度粒度,且紅黑樹最左邊的任務的虛擬運行時間和當前任務的虛擬運行時間的差值小于理想運行時間(紅黑樹中的高優先級的任務可以搶占當前任務)。

2)喚醒搶占:

在fork和正常的喚醒路徑上:

fork路徑:

  1. kernel/fork.c 
  2.  
  3. kernel_clone 
  4. ->wake_up_new_task(p) 
  5.  ->check_preempt_curr(rq, p, WF_FORK) 
  6.   ->rq->curr->sched_class->check_preempt_curr(rq, p, flags) 
  7.    ->check_preempt_wakeup    //kernel/sched/fair.c 
  8.     -> 6994         if (wakeup_preempt_entity(se, pse) == 1) {   //喚醒的任務的虛擬運行時間和當前任務的虛擬運行時間差值小于最新喚醒搶占粒度轉換的虛擬運行時間        
  9.      6995                 /*                                                   
  10.      6996                 ¦* Bias pick_next to pick the sched entity that is   
  11.      6997                 ¦* triggering this preemption.                       
  12.      6998                 ¦*/                                                  
  13.      6999                 if (!next_buddy_marked)                              
  14.      7000                         set_next_buddy(pse);                         
  15.      7001                 goto preempt;                                        
  16.      7002         }                                                            
  17.      7003                                                                      
  18.      7004         return;                                                      
  19.      7005                                                                      
  20.      7006 preempt:                                                             
  21.      7007         resched_curr(rq);      //設置重新調度標志                                        

正常喚醒路徑:

  1. kernel/sched/core.c 
  2. wake_up_process 
  3. ->try_to_wake_up 
  4.  ->ttwu_queue 
  5.   ->ttwu_do_activate 
  6.    ->ttwu_do_wakeup 
  7.     ->check_preempt_curr(rq, p, wake_flags) 

無論是創建新任務或者是喚醒任務的時候,都有可能新喚醒的任務搶占當前任務,判斷條件如下:喚醒的任務的虛擬運行時間和當前任務的虛擬運行時間差值小于最小喚醒搶占粒度轉換的虛擬運行時間(喚醒的任務的虛擬運行時間更小)。

4.2 搶占點

上面介紹的都是cheek點,只是設置重新調度標志,并沒有讓搶占的任務運行,真正的搶占點是調用主調度器的時候。

1)中斷返回內核態

當開啟內核搶占的時候,在中斷返回內核態的前夕,會檢查當前任務是否設置了重新調度標志且搶占計數器為0,如果都滿足,進行搶占式調度。

  1. arch/arm64/kernel/entry.S 
  2.  
  3. el1_irq 
  4. ->  671 #ifdef CONFIG_PREEMPTION                                                                    
  5.   672         ldr     x24, [tsk, #TSK_TI_PREEMPT]     // get preempt count                        
  6.   673 alternative_if ARM64_HAS_IRQ_PRIO_MASKING                                                   
  7.   674         /*                                                                                  
  8.   675         ¦* DA_F were cleared at start of handling. If anything is set in DAIF,              
  9.   676         ¦* we come back from an NMI, so skip preemption                                     
  10.   677         ¦*/                                                                                 
  11.   678         mrs     x0, daif                                                                    
  12.   679         orr     x24, x24, x0                                                                
  13.   680 alternative_else_nop_endif                                                                  
  14.   681         cbnz    x24, 1f                         // preempt count != 0 || NMI return path    
  15.   682         bl      arm64_preempt_schedule_irq      // irq en/disable is done inside            
  16.   683 1:                                                                                          
  17.   684 #endif                  

當發生中斷時,會執行el1_irq來處理中斷,

672行 來讀取當前任務的thread_info.preempt_count 681行 判斷thread_info.preempt_count是否為0,如果為0 則調用682 行的arm64_preempt_schedule_irq 進行搶占式調度(上一節已經分析過)。

下面看下搶占式調度:

  1. arm64_preempt_schedule_irq 
  2. ->preempt_schedule_irq 
  3.  ->__schedule(true)  //調用主調度器進行搶占式調度 

2)打開搶占的時候

開啟搶占:

  1. preempt_enable 
  2. ->if (unlikely(preempt_count_dec_and_test())) \   //搶占計數器減一  為0 
  3.         __preempt_schedule(); \                
  4.    ->preempt_schedule  //kernel/sched/core.c 
  5.     -> __schedule(true)  //調用主調度器進行搶占式調度 

釋放自旋鎖:

  1. spin_unlock 
  2. ->raw_spin_unlock 
  3.  ->__raw_spin_unlock 
  4.   ->preempt_enable  //如上 

3) 開啟軟中斷

  1. local_bh_enable 
  2. ->__local_bh_enable_ip 
  3.  ->preempt_check_resched 
  4.   ->if (should_resched(0)) \      
  5.          __preempt_schedule(); 
  6.          ->preempt_schedule 
  7.     -> __schedule(true)  //調用主調度器進行搶占式調度 

其實,無論是主動進行調度還是搶占式調度都會調用__schedule,而__schedule是屬于關搶占上下文,在調度期間不允許被搶占。

5.不可搶占內核的低延遲處理

下面我們來看下在沒有開啟內核搶占的內核中如何處理低延遲:

我們會看到在一些比較耗時的處理中如文件系統和內存回收的一些路徑會調用cond_resched,它是干什么用呢:

下面是使用這個宏的例子:在內存回收路徑中,會從不活躍的lru鏈表尾部取出一些頁面回收隔離到page_list中,最終會調用到shrink_page_list:

  1. mm/vmscan.c 
  2. shrink_page_list 
  3. -> 
  4.  1084         while (!list_empty(page_list)) { 
  5.   
  6.  ... 
  7.   
  8.  1091                 cond_resched(); 
  9.   
  10.  ... //回收處理 

可以看到對于page_list中的每一個被隔離的候選回收頁,在處理之前都會調用到cond_resched來主動判斷是否需要重新調度。

下面我們來看下cond_resched這個宏實現:

  1. include/linux/sched.h 
  2.  
  3. 1868 /* 
  4. 1869  * cond_resched() and cond_resched_lock(): latency reduction via 
  5. 1870  * explicit rescheduling in places that are safe. The return 
  6. 1871  * value indicates whether a reschedule was done in fact. 
  7. 1872  * cond_resched_lock() will drop the spinlock before scheduling, 
  8. 1873  */ 
  9. 1874 #ifndef CONFIG_PREEMPTION 
  10. 1875 extern int _cond_resched(void); 
  11. 1876 #else 
  12. 1877 static inline int _cond_resched(void) { return 0; } 
  13. 1878 #endif 
  14. 1879  
  15. 1880 #define cond_resched() ({                       \ 
  16. 1881         ___might_sleep(__FILE__, __LINE__, 0);  \ 
  17. 1882          _cond_resched();                    \ 
  18. 1883 }) 

我們可以很清楚的看到,搶占式內核中(CONFIG_PREEMPTION=y)cond_resched宏的_cond_resched為空,并沒有主動判斷重新調度的功能,只有非搶占式內核才會調用_cond_resched來執行主動檢查可搶占性。

下面我們來看下_cond_resched:

  1. 6671 #ifndef CONFIG_PREEMPTION 
  2. 6672 int __sched _cond_resched(void) 
  3. 6673 { 
  4. 6674         if (should_resched(0)) {   //判斷搶占計數器是否為0 
  5. 6675                 preempt_schedule_common();  //進行搶占式調度 
  6. 6676                 return 1; 
  7. 6677         } 
  8. 6678         rcu_all_qs(); 
  9. 6679         return 0; 
  10. 6680 } 
  11. 6681 EXPORT_SYMBOL(_cond_resched); 
  12. 6682 #endif 

會主動檢查搶占計數器是否為0(實際上搶占計數器是否為0且當前任務被設置了重新調度標志),則進行搶占式調度。

實際上,對于非搶占式內核來說,在內核的很多地方,特別是文件系統操作和內存管理相關的一些耗時路徑中,都已經被內核開發者識別出來,并使用cond_resched來減小延遲(感興趣的小伙伴可以通過grep和wc -l命令來查看一下)。

6.自愿內核搶占

內核搶占模型有一種叫做自愿內核搶占模型(CONFIG_PREEMPT_VOLUNTARY=y),可以使得內核開發者在進行耗時操作的時候,主動檢查是否需要發生搶占式調度,這個和上一節差不多。

  1. config PREEMPT_VOLUNTARY 
  2.         bool "Voluntary Kernel Preemption (Desktop)" 
  3.         depends on !ARCH_NO_PREEMPT 
  4.         help 
  5.         ¦ This option reduces the latency of the kernel by adding more 
  6.         ¦ "explicit preemption points" to the kernel code. These new 
  7.         ¦ preemption points have been selected to reduce the maximum 
  8.         ¦ latency of rescheduling, providing faster application reactions, 
  9.         ¦ at the cost of slightly lower throughput. 
  10.  
  11.         ¦ This allows reaction to interactive events by allowing a 
  12.         ¦ low priority process to voluntarily preempt itself even if it 
  13.         ¦ is in kernel mode executing a system call. This allows 
  14.         ¦ applications to run more 'smoothly' even when the system is 
  15.         ¦ under load
  16.  
  17.         ¦ Select this if you are building a kernel for a desktop system. 

使用might_resched:

  1. 83 #ifdef CONFIG_PREEMPT_VOLUNTARY 
  2. 84 extern int _cond_resched(void); 
  3. 85 # define might_resched() _cond_resched() 
  4. 86 #else 
  5. 87 # define might_resched() do { } while (0) 
  6. 88 #endif 

發現只有CONFIG_PREEMPT_VOLUNTARY=y時,might_resched才有效,否則為空。

可以驚奇的發現,當搜索might_resched在內核中使用的使用的時候,并沒有看見有任何地方在使用,猜想是因為大多數耗時的內核路徑,都已經使用cond_resched來進行檢查是否具備調度時機。

7.總結

 

本文講解了內核搶占的方方面面,非搶占式內核主要用于服務器等對吞吐量要求較高的場景,而搶占式內核主要用于嵌入式設備和桌面等對響應要求較高的場景。內核搶占的調度時機主要從check點和搶占點兩個角度去分析:check點是在合適的時機(如時鐘中斷tick時或者任務喚醒的時候)判斷是否需要重新調度任務,如果需要設置重新調度標志(need_resched),并沒有馬上進行調度,然后在最近的搶占點發生調度;而搶占點是真正調用主調度器發生調度的時機,一般會在中斷返回內核態或者重新開啟內核搶占等情況下發生。最后,我們又分析了非搶占式內核如何進行低延遲處理已經自愿搶占式內核如何實現自愿式搶占。

 

責任編輯:武曉燕 來源: Linux內核遠航者
相關推薦

2021-12-09 08:09:31

Linux內核臟頁

2021-07-26 07:47:36

數據庫

2021-07-05 06:51:45

Linux內核調度器

2021-07-02 06:54:44

Linux內核主調度器

2021-07-20 08:02:41

Linux進程睡眠

2020-09-28 08:44:17

Linux內核

2025-06-16 05:10:00

2025-04-28 02:00:00

2025-04-22 08:21:10

2017-08-16 16:20:01

Linux內核態搶占用戶態搶占

2024-09-05 08:13:05

2015-12-28 11:41:57

JVM內存區域內存溢出

2022-11-09 08:12:07

2023-02-10 08:11:43

Linux系統調用

2025-10-28 04:25:00

2021-08-31 10:32:11

LinuxPage Cache命令

2013-06-20 10:25:56

2019-07-08 20:00:35

Linux內核模塊

2020-11-20 07:55:55

Linux內核映射

2016-12-08 15:36:59

HashMap數據結構hash函數
點贊
收藏

51CTO技術棧公眾號

国产精品免费久久久久影院| 精品国产乱码久久久久久婷婷 | 91看片淫黄大片一级在线观看| 欧美激情视频在线观看| 三级av免费看| 欧美伦理免费在线| 波波电影院一区二区三区| 欧美日韩国产va另类| 中文在线字幕观看| 亚洲福利影院| 国产精品天干天干在观线 | а天堂中文最新一区二区三区| 久久久精品人体av艺术| 91黄色小视频| 亚洲不卡1区| 亚洲天堂aaa| 欧美fxxxxxx另类| 亚洲成人亚洲激情| 99视频免费播放| 国产午夜精品久久久久免费视| 精品一区二区三区免费播放| 欧美精品videosex极品1| 性久久久久久久久久| 成人影院在线看| 成人免费av网站| 国产91色在线| 久久99久久98精品免观看软件| 无码少妇一区二区三区| 日韩欧美亚洲范冰冰与中字| 26uuu成人| 色屁屁草草影院ccyycom| 欧美亚洲在线| 欧美精品一区在线播放| 亚洲第一页av| 亚洲1区在线| 欧美性色黄大片手机版| 国产精品国三级国产av| 91精品大全| 成人免费高清视频在线观看| 国产美女久久精品| 800av在线播放| 亚洲男女网站| 日韩欧美国产免费播放| av动漫免费观看| 六十路在线观看| 成人高清视频在线| 91免费高清视频| 免费看一级视频| 激情另类综合| 欧美国产在线视频| 中文字幕av免费在线观看| 日韩精品永久网址| 中文字幕不卡在线视频极品| 国产真人做爰视频免费| 天海翼精品一区二区三区| 亚洲国产精品成人精品| 老司机午夜免费福利| 亚洲精品v亚洲精品v日韩精品| 制服丝袜国产精品| 中文 日韩 欧美| 97久久精品一区二区三区的观看方式| 欧美日韩一区二区三区在线看 | 欧美欧美午夜aⅴ在线观看| 日本www高清视频| 一区二区三区福利视频| 天天综合亚洲| 久久精品国产亚洲一区二区| 久久久国产精品久久久| 日韩黄色影院| 国产69精品久久久久777| 91免费看片网站| 深夜福利成人| 91黄色免费视频| av成人福利| 岛国精品视频在线播放| 日韩av片永久免费网站| 国产成人一级片| 午夜在线a亚洲v天堂网2018| 66m—66摸成人免费视频| 国产稀缺真实呦乱在线| 最新国产拍偷乱拍精品 | 亚洲片av在线| 长河落日免费高清观看| 女人av一区| 欧美日本免费一区二区三区| 香蕉视频在线观看黄| 久久成人福利| 亚洲欧美综合色| 日韩一级免费看| 久久精品视频免费看| 亚洲精品国产精华液| 一区二区日本伦理| 日本中文字幕在线| 国产一区二区在线观看视频| 国产精品网站视频| 亚洲国产精品久久久久久6q | 亚洲高清在线精品| 97影院在线午夜| 日本大臀精品| 亚洲综合欧美| 欧美诱惑福利视频| 老熟妇一区二区三区啪啪| 美女在线一区二区| 国产日韩欧美一区二区三区四区 | 日韩伦理在线一区| 亚洲国产视频一区| av在线不卡一区| 国产免费不卡av| 99在线观看免费视频精品观看| 欧美tickling网站挠脚心| ijzzijzzij亚洲大全| 日本在线观看| 超级白嫩亚洲国产第一| 欧美aaaaa成人免费观看视频| 欧美制服第一页| 在线免费看毛片| 亚洲欧美综合久久久| 久久久久久久激情视频| 国产在线综合网| 九九视频精品全部免费播放| 亚洲欧美国产精品va在线观看| 国产免费看av| 成人在线免费av| 精品国产sm最大网站| 爆乳熟妇一区二区三区霸乳| 日本电影欧美片| 精品国产一区二区在线观看| 欧美久久久久久久久久久久久久| 97精品国产综合久久久动漫日韩| 欧美裸体视频| 国产精品久久久久久久久免费桃花| 国产免费黄色一级片| 在线免费观看黄色网址| 国产精品久久久久aaaa樱花| 中国丰满人妻videoshd | 国产a一区二区| 国产尤物在线视频| 看国产成人h片视频| 欧美精品在线第一页| 九九久久免费视频| 欧美国产小视频| 久久久国产一区| 亚洲成a人片在线www| 日本h片在线观看| 国产91丝袜在线观看| 欧美劲爆第一页| 蜜桃传媒一区二区亚洲av| 天天久久人人| av中文在线| 国产精品久久久久久模特| 亚洲欧美日本精品| 亚洲熟女毛茸茸| 奇米777日韩| 久久亚洲综合色一区二区三区| 91高潮在线观看| 特级西西444www大精品视频免费看 | 成人在线视频你懂的| 国产电影精品久久禁18| 青青a在线精品免费观看| 91大学生片黄在线观看| 精品视频在线观看免费| 亚洲伦理久久| 丝袜亚洲另类欧美综合| www.成人网.com| 91精品综合视频| 黄色免费在线看| 欧美日本一道本| 91杏吧porn蝌蚪| 亚洲啊v在线观看| 国产精品一区二区久久国产| 亚洲av毛片成人精品| 亚洲日本青草视频在线怡红院| 两女双腿交缠激烈磨豆腐| 狠狠入ady亚洲精品| 成人欧美一区二区| 毛片在线看网站| 欧美日韩在线三级| 国产一二三四五区| 国产伦理一区| 亚洲黄色成人久久久| 亚洲成人影音| 欧美一级黄色网| 欧美精品七区| 欧美大片免费高清观看| 亚洲欧美精品在线| 国产精品国产三级国产aⅴ| 国产福利一区二区| 亚洲人成无码网站久久99热国产| 免费成人结看片| 91免费国产网站| 男人天堂视频在线观看| 中文在线不卡视频| 性欧美18一19性猛交| 一本大道久久a久久精二百| 亚洲欧美另类日本| 成人99免费视频| 国产91色在线观看| 亚洲国产网站| 亚洲精品在线视频观看| av男人一区| 国产精品欧美日韩| 182在线视频观看| 日韩中文在线观看| 西西人体44www大胆无码| 在线成人免费观看| 国产99久久久| 亚洲综合一区二区三区| 国产精品美女高潮无套| 粉嫩13p一区二区三区| 午夜免费高清视频| 99在线观看免费视频精品观看| 在线观看一区二区三区三州| 私拍精品福利视频在线一区| 亚洲999一在线观看www| 亚州一区二区三区| 午夜免费久久久久| 麻豆传媒在线完整视频| 亚洲欧洲在线免费| 婷婷久久久久久| 日韩精品自拍偷拍| 一级二级三级视频| 欧美在线你懂的| 在线观看免费国产视频| 亚洲欧美电影一区二区| 美女av免费看| 国产亚洲一区字幕| 一区二区三区免费在线观看视频| 国产精品1024| 99精品视频免费版的特色功能| 日本女优在线视频一区二区| 成人综合视频在线| 99精品国产在热久久婷婷| 人妻无码一区二区三区四区| 午夜精品一区二区三区国产| 日韩欧美精品一区二区| 美女毛片一区二区三区四区| 国产三区精品| 国产欧美啪啪| 不卡一区二区三区四区五区| 秋霞影院一区| 亚洲精品欧美日韩| 精品国产乱码一区二区三区 | 亚洲欧美成人网| 亚洲欧美日韩动漫| 亚洲第一偷拍网| www.污视频| 日韩欧美自拍偷拍| 999免费视频| 911精品国产一区二区在线| 18国产免费视频| 欧美偷拍一区二区| 中文字幕在线观看1| 欧美日韩久久不卡| 伊人久久一区二区| 欧美日本一区二区三区四区| 91国产精品一区| 欧美精品vⅰdeose4hd| 国产原创中文av| 7777精品伊人久久久大香线蕉完整版 | 午夜精品毛片| 日韩一区二区高清视频| 狠狠综合久久| 欧美日韩黄色一级片| 亚洲永久网站| 久久久国产欧美| 久久国产生活片100| 日韩av福利在线观看| 高清不卡在线观看| 国产精品无码网站| 国产午夜精品久久久久久久 | 手机在线国产视频| 国产成人在线色| 精品国产av色一区二区深夜久久| 26uuu久久综合| 五月激情四射婷婷| 亚洲图片你懂的| 久久久99精品| 色综合天天做天天爱| 91tv国产成人福利| 欧美大片在线观看一区二区| 手机在线不卡av| 国产亚洲人成a一在线v站| 蜜桃av在线免费观看| 久久久久久久久国产| 在线精品亚洲欧美日韩国产| 国产精品久久一区主播| 欧美特黄不卡| 欧美午夜视频在线| 亚洲精品2区| 久久黄色片视频| 蜜桃av一区二区三区| 亚洲精品成人无码毛片| 久久久久久一级片| 小泽玛利亚一区二区免费| 精品一区二区三区久久| 毛茸茸free性熟hd| 国产精品久久三| 国产香蕉在线视频| 欧美日韩综合不卡| 欧性猛交ⅹxxx乱大交| 一本色道久久综合狠狠躁篇怎么玩| 国产精品实拍| 国产99久久精品一区二区| 国产精品视频一区二区三区综合 | 欧美 日韩 中文字幕| 一区二区三欧美| ****av在线网毛片| 国产综合久久久久| 三级精品视频| 韩国黄色一级大片| 日日夜夜精品免费视频| 久久国产免费视频| 国产精品电影院| 日本免费在线观看视频| 日韩欧美一级特黄在线播放| 国产视频精品久久| 97色在线视频观看| 视频二区欧美| 一本久久a久久精品vr综合| 免费永久网站黄欧美| 97中文字幕在线观看| 国产精品久久久久久福利一牛影视| 精品在线播放视频| 精品国产一二三| 看女生喷水的网站在线观看| 日韩美女中文字幕| 日韩高清一级| 国产男女免费视频| 丰满亚洲少妇av| 日韩高清dvd碟片| 欧美日韩国产片| 波多野结衣在线影院| 欧美孕妇与黑人孕交| 豆花视频一区二区| 日本香蕉视频在线观看| 国产精品亚洲人在线观看| 男人在线观看视频| 欧美系列在线观看| 成人免费一区二区三区视频网站| 欧美一区视频在线| 啪啪激情综合网| 久久免费视频3| 99久久99久久久精品齐齐| 成年人午夜视频| 亚洲国产三级网| 182在线播放| 精品在线观看一区二区| 国产精品入口66mio| 免费的av网站| 欧美日韩亚洲一区二区三区| 香蕉视频911| 国产91精品高潮白浆喷水| 午夜精品福利影院| 少妇人妻互换不带套| 国产亚洲自拍一区| 中文字幕人妻丝袜乱一区三区 | 精品国产乱码久久久久| 日韩图片一区| 国产毛片毛片毛片毛片毛片毛片| 精品美女永久免费视频| 亚洲色图欧美视频| 奇米四色中文综合久久| 精品在线播放| 色婷婷一区二区三区av免费看| 国产精品大尺度| 亚洲爱爱综合网| 8050国产精品久久久久久| 欧美人妖在线| 亚洲一级片网站| 亚洲精品视频一区二区| 六月婷婷中文字幕| 欧日韩在线观看| 日本欧美肥老太交大片| 天天看片天天操| 亚洲一区二区三区四区五区黄 | 最新的欧美黄色| 精品欧美视频| 国产中文字幕二区| 久久精品一区蜜桃臀影院| 一区二区久久精品66国产精品| 久久在线精品视频| 日韩系列在线| www.精品在线| 亚洲一线二线三线久久久| 三级视频网站在线| 成人免费福利视频| 亚洲日本激情| 毛片久久久久久| 亚洲成人久久一区| 欧美黄色a视频| 久久国产午夜精品理论片最新版本| 26uuu欧美| 国产高清在线免费| 日韩免费在线播放| 欧美精品啪啪| 色一情一交一乱一区二区三区| 欧美一区二区三区精品| 625成人欧美午夜电影| 五月天在线免费视频| 26uuu国产在线精品一区二区|