之前寫的兩個博客中講了調度時機的用戶態搶佔調度部分,分別講了系統調用返回和中斷處理返回這兩個點的用戶態搶佔的一些情況。
這篇博客會寫內核搶佔調度的部分。
------------------------------------------------------------------------------------------------------------------------------
內核態搶佔調度
內核態搶佔調度發生在下面兩者情況:
◆內核進程運行過程中沒有關搶佔,有中斷產生,在中斷返回時,判斷出沒有關搶佔就會調用preempt_schedule_irq函數
◆內核進程運行過程中又產生了更高優先級的進程。
早期的Linux內核版本不支持內核態搶佔,內核進程的切換需要主動調度,這樣調度延遲大,無法做到實時調度。實現可搶佔內核的主要修改就是在中斷處理返回時,如果是返回內核態,在通過一些檢查後,就會調用preempt_schedule_irq函數。
下面從中斷處理返回開始分析。在前面講到如果中斷返回時返回到內核態,就會跳轉到retint_kernel執行
/* Returning to kernel space. Check if we need preemption */ /* rcx: threadinfo. interrupts off. */ .p2align retint_kernel: cmpl $0,threadinfo_preempt_count(%rcx) //判斷是否關搶佔了 jnz retint_restore_args //關搶佔了,不能搶佔,恢復被中斷時的處理器的狀態 bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx) /*檢測是否有設置TIF_NEED_RESCHED標誌,是否需要重新調度*/ jnc retint_restore_args //不需要重新調度,恢復被中斷時的處理器的狀態 bt $9,EFLAGS-ARGOFFSET(%rsp)/* interrupts off? */ /*1:響應可屏蔽中斷 ;0:抑制可屏蔽中斷*/ jnc retint_restore_args //IF標誌清零了,恢復被中斷時的處理器的狀態 call preempt_schedule_irq jmp exit_intr |
首先判斷是否關搶佔了,如果關搶佔了,那麼不能搶佔,就跳轉到retint_restore_args恢復被中斷時的處理器狀態。
判斷是否有設置TIF_NEED_RESCHED標誌,需要重新調度,如果不需要的話,也是跳轉到retint_restore_args執行。
判斷EFLAGS寄存器的IF標誌,如果IF標誌清零了,說明現在中斷上下文所在的中斷不是外部可屏蔽中斷,也就是內部中斷(或外部不可屏蔽中斷),這種情況下不考慮內核態搶佔的情況,直接跳轉到retint_restore_args恢復被中斷時的處理器狀態。
上面的檢查都通過之後,就會調用preempt_schedule_irq函數執行。此函數是在退出中斷上下文時開搶佔的情況下進程搶佔調度的入口點。
asmlinkage void __sched preempt_schedule_irq(void) { BUG_ON(ti->preempt_count || !irqs_disabled());
need_resched: add_preempt_count(PREEMPT_ACTIVE);
local_irq_enable(); schedule(); local_irq_disable();
sub_preempt_count(PREEMPT_ACTIVE);
barrier(); if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) goto need_resched; } |
函數首先檢查是關搶佔或者開中斷了,如果這兩種情況任何一個滿足,則報錯。此函數是在關中斷的情況下調用的,這樣是爲了避免出現中斷中遞歸的調用此函數。
接着調用add_preempt_count(PREEMPT_ACTIVE)函數設置PREEMPT_ACTIVE,這樣在後面的schedule函數中見到設置了PREEMPT_ACTIVE,就不會將先前的prev進程從運行隊列中移除了。這樣能夠防止在內核搶佔時錯誤的將當前進程切入阻塞狀態。
錯誤的切入阻塞狀態,會有什麼後果?如果一個內核進程剛剛調用set_current_state(TASK_INTERRUPTIBLE)後被中斷打斷,那麼在中斷返回時,在schedule函數裏判斷此進程不是TASK_RUNNING狀態,如果不加上設置PREEMPT_ACTIVE,就會將此進程從運行隊列中移除,不再運行,此進程後面的代碼沒有得到執行,今後也沒有機會被喚醒執行到了。