调度时机
調(diào)度什么時候發(fā)生?即:schedule()函數(shù)什么時候被調(diào)用?
調(diào)度的發(fā)生有兩種方式:
1、主動式
在內(nèi)核中直接調(diào)用schedule()。當(dāng)進程需要等待資源等而暫時停止運行時,會把狀態(tài)置于掛起(睡眠),并主動請求調(diào)度,讓出CPU。
主動放棄cpu例:
1. current->state = TASK_INTERRUPTIBLE;
2. schedule();
2、被動式(搶占)
用戶搶占(Linux2.4、Linux2.6)
內(nèi)核搶占(Linux2.6)
用戶搶占發(fā)生在:
* 從系統(tǒng)調(diào)用返回用戶空間。
* 從中斷處理程序返回用戶空間。
內(nèi)核即將返回用戶空間的時候,如果need_resched標(biāo)志被設(shè)置,會導(dǎo)致schedule()被調(diào)用,此時就會發(fā)生用戶搶占.
* ENTRY(ret_from_exception) //異常返回 get_thread_info tsk mov why, #0 b ret_to_user * __irq_usr: //在用戶態(tài)收到中斷 usr_entry kuser_cmpxchg_check …… …… …… b ret_to_userENTRY(ret_to_user) ret_slow_syscall: disable_irq @ disable interrupts ldrr1, [tsk, #TI_FLAGS] tstr1, #_TIF_WORK_MASK bne work_pendingwork_pending: tstr1, #_TIF_NEED_RESCHED bne work_resched work_resched: bl schedule
?
內(nèi)核搶占:
* 在不支持內(nèi)核搶占的系統(tǒng)中,進程/線程一旦運行于內(nèi)核空間,就可以一直執(zhí)行,直到它主動放棄或時間片耗盡為止。這樣一些非常緊急的進程或線程將長時間得不到運行。
* 在支持內(nèi)核搶占的系統(tǒng)中,更高優(yōu)先級的進程/線程可以搶占正在內(nèi)核空間運行的低優(yōu)先級進程/線程。
在支持內(nèi)核搶占的系統(tǒng)中,某些特例下是不允許內(nèi)核搶占的:
* 內(nèi)核正進行中斷處理。進程調(diào)度函數(shù)schedule()會對此作出判斷,如果是在中斷中調(diào)用,會打印出錯信息。
* 內(nèi)核正在進行中斷上下文的Bottom Half(中斷的底半部)處理。硬件中斷返回前會執(zhí)行軟中斷,此時仍然處于中斷上下文中。
* 進程正持有spinlock自旋鎖、writelock/readlock讀寫鎖等,當(dāng)持有這些鎖時,不應(yīng)該被搶占,否則由于搶占將導(dǎo)致其他CPU長期不能獲得鎖而死等。
* 內(nèi)核正在執(zhí)行調(diào)度程序Scheduler。搶占的原因就是為了進行新的調(diào)度,沒有理由將調(diào)度程序搶占掉再運行調(diào)度程序。
為保證Linux內(nèi)核在以上情況下不會被搶占,搶占式內(nèi)核使用了一個變量preempt_count,稱為內(nèi)核搶占計數(shù)。這一變量被設(shè)置在進程的thread_info結(jié)構(gòu)中。每當(dāng)內(nèi)核要進入以上幾種狀態(tài)時,變量preempt_count就加1,指示
內(nèi)核不允許搶占。每當(dāng)內(nèi)核從以上幾種狀態(tài)退出時,變量preempt_count就減1,同時進行可搶占的判斷與調(diào)度。
內(nèi)核搶占可能發(fā)生在:
* 中斷處理程序完成,返回內(nèi)核空間之前。
* 當(dāng)內(nèi)核代碼再一次具有可搶占性的時候,如解鎖及使能軟中斷等。
內(nèi)核搶占(中斷):
__irq_svc: /*內(nèi)核態(tài)接收到中斷*/ svc_entry 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 /*進入中斷,搶占計數(shù)加1*/ #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count add r7, r8, #1 @ increment it str r7, [tsk, #TI_PREEMPT] #endif irq_handler /*中斷處理*/ #ifdef CONFIG_PREEMPT str r8, [tsk, #TI_PREEMPT] @ restore preempt count ldr r0, [tsk, #TI_FLAGS] @ get flags teq r8, #0 @ if preempt count != 0 movne r0, #0 @ force flags to 0 tst r0, #_TIF_NEED_RESCHED blne svc_preempt #endifsvc_preempt: mov r8, lr 1: bl preempt_schedule_irq /*調(diào)度*/ ldr r0, [tsk, #TI_FLAGS] tst r0, #_TIF_NEED_RESCHED moveqpc, r8
?
內(nèi)核搶占(解鎖):
void __lockfunc _spin_unlock(spinlock_t *lock) { spin_release(&lock->dep_map, 1, _RET_IP_); _raw_spin_unlock(lock); preempt_enable(); } define preempt_enable() \ do { \ preempt_enable_no_resched(); \ barrier(); \ preempt_check_resched(); \ } while (0)#define preempt_enable_no_resched() \ do { \ barrier(); \ dec_preempt_count();\ /*搶占計數(shù)減一*/ } while (0)#define preempt_check_resched() \ do { \ if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ preempt_schedule();\ /*調(diào)度*/ } while (0)
?
轉(zhuǎn)載于:https://www.cnblogs.com/Daniel-G/p/3306674.html
總結(jié)
- 上一篇: 乌镇去南浔古镇怎么坐车
- 下一篇: YUM配置