生活随笔
收集整理的這篇文章主要介紹了
基于CFS算法的schedule()源码分析
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
內(nèi)核中的調(diào)度算法在不斷變化,2.4內(nèi)核中的調(diào)度器是在所有的進(jìn)程中選擇優(yōu)先級(jí)最高的進(jìn)程,2.6內(nèi)核前期的調(diào)度器是基于O(1)算法的,而 2.6.23版本之后的內(nèi)核采用CFS調(diào)度算法,并同時(shí)對(duì)調(diào)度器進(jìn)行了比較大的改善。內(nèi)核主要是引入了調(diào)度器類(lèi)來(lái)增加調(diào)度器的可擴(kuò)展性。調(diào)度器類(lèi)將各種調(diào) 度策略模塊化,封裝了對(duì)不同調(diào)度策略的具體實(shí)現(xiàn)。
內(nèi)核中對(duì)進(jìn)程調(diào)度的方法有兩種,其一為周期性調(diào)度器(generic scheduler),它對(duì)進(jìn)行進(jìn)行周期性的調(diào)度,以固定的頻率運(yùn)行;其二為主調(diào)度器(main scheduler),如果進(jìn)程要進(jìn)行睡眠或因?yàn)槠渌蛑鲃?dòng)放棄CPU,那么就直接調(diào)用主調(diào)度器。
內(nèi)核的主調(diào)度器是通過(guò)schedule()實(shí)現(xiàn)的,該函數(shù)的主要工作就是挑選下一個(gè)應(yīng)該被調(diào)度的進(jìn)程next。
該函數(shù)首先禁止內(nèi)核搶占,并且依次獲取當(dāng)前CPU編號(hào)cpu、當(dāng)前CPU對(duì)應(yīng)的運(yùn)行隊(duì)列rq、當(dāng)前進(jìn)程的切換次數(shù)switch_count以及當(dāng)前進(jìn)程的描述符prev。
| 1 | asmlinkage void __sched schedule(void) |
| 3 | ????struct task_struct *prev, *next; |
| 4 | ????unsigned long *switch_count; |
| 10 | ????cpu = smp_processor_id(); |
| 14 | ????switch_count = &prev->nivcsw; |
| 16 | ????release_kernel_lock(prev); |
| 17 | need_resched_nonpreemptible: |
| 19 | ????schedule_debug(prev); |
| 21 | ????if (sched_feat(HRTICK)) |
| 22 | ????????hrtick_clear(rq); |
接下來(lái)通過(guò)update_rq_clock()更新就緒隊(duì)列上的時(shí)鐘,接著通過(guò)clear_tsk_need_resched()清除當(dāng)前進(jìn)程prev的重新調(diào)度標(biāo)志TIF_NEED_RESCHED。
| 1 | raw_spin_lock_irq(&rq->lock); |
| 3 | clear_tsk_need_resched(prev); |
如果當(dāng)前進(jìn)程是可中斷睡眠狀態(tài)(可運(yùn)性狀態(tài)TASK_RUNNING宏的值為0),但它卻收到了某個(gè)喚醒它的信號(hào),那么當(dāng)前進(jìn)程的標(biāo)志被更新為T(mén)ASK_RUNNING,等待再次被調(diào)度。否則,通過(guò)deactivate_task()將當(dāng)前進(jìn)程prev從就緒隊(duì)列中刪除。
這里的deactivate_task()根據(jù)調(diào)度類(lèi)的不同實(shí)現(xiàn)也有所不同,但這些差異對(duì)主調(diào)度器是透明的,因?yàn)檎{(diào)度器類(lèi)在各種調(diào)度實(shí)例和調(diào)度器之間起到了連接作用。該函數(shù)的核心語(yǔ)句即為:
| 1 | p->sched_class->dequeue_task(rq, p, sleep); |
sched_class是進(jìn)程描述符中描述當(dāng)前進(jìn)程所屬調(diào)度類(lèi)的字段,通過(guò)這個(gè)字段回調(diào)鉤子函數(shù)dequeue_task()。
| 1 | if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { |
| 2 | ????if (unlikely(signal_pending_state(prev->state, prev))) |
| 3 | ????????prev->state = TASK_RUNNING; |
| 5 | ????????deactivate_task(rq, prev, 1); |
| 6 | ????switch_count = &prev->nvcsw; |
| 11 | if (unlikely(!rq->nr_running)) |
| 12 | ????idle_balance(cpu, rq); |
通過(guò)put_prev_task()將prev進(jìn)程重新插入到就緒隊(duì)列合適的位置中。再通過(guò)pick_next_task()在當(dāng)前的就緒隊(duì)列中挑選下一個(gè)應(yīng)該被執(zhí)行的進(jìn)程next。這兩個(gè)函數(shù)都屬于調(diào)度器類(lèi)中的鉤子函數(shù),它們的具體實(shí)現(xiàn)根據(jù)調(diào)度實(shí)例的不同而不同。
| 1 | put_prev_task(rq, prev); |
| 2 | next = pick_next_task(rq); |
有時(shí)候,調(diào)度器所選的下一個(gè)被執(zhí)行的進(jìn)程恰好就是當(dāng)前進(jìn)程,那么調(diào)度器就不必耗費(fèi)精力去執(zhí)行上下文切換,但這種情況不是經(jīng)常發(fā)生的。如果prev和 next不是同一個(gè)進(jìn)程,那么先通過(guò)sched_info_switch()更新兩個(gè)進(jìn)程描述符的相關(guān)字段,并且更新可運(yùn)行隊(duì)列的相關(guān)字段。
接下來(lái)調(diào)用context_switch()進(jìn)行prev和next兩個(gè)進(jìn)程的上下文切換,該函數(shù)由一段匯編代碼組成。
| 1 | if (likely(prev != next)) { |
| 2 | ????sched_info_switch(prev, next); |
| 3 | ????perf_event_task_sched_out(prev, next); |
| 9 | ????context_switch(rq, prev, next); /* unlocks the rq */ |
| 11 | ?????* the context switch might have flipped the stack from under |
| 12 | ?????* us, hence refresh the local variables. |
| 14 | ????cpu = smp_processor_id(); |
| 17 | ????raw_spin_unlock_irq(&rq->lock); |
切換完畢后,當(dāng)前的進(jìn)程就是新選擇的進(jìn)程,它會(huì)開(kāi)始執(zhí)行。而被切換出去的進(jìn)程重新運(yùn)行時(shí)會(huì)從切換函數(shù)的下一條語(yǔ)句開(kāi)始執(zhí)行。
| 3 | ????if (unlikely(reacquire_kernel_lock(current) < 0)) {????? prev = rq->curr; |
| 4 | ????????switch_count = &prev->nivcsw; |
| 5 | ????????goto need_resched_nonpreemptible; |
| 8 | ????preempt_enable_no_resched(); |
| 10 | ????????goto need_resched; |
根據(jù)上述對(duì)主調(diào)度器函數(shù)源碼的分析,可以總結(jié)出主調(diào)度器的主要功能如下:
1.獲取當(dāng)前進(jìn)程的描述符以及本地CPU的運(yùn)行隊(duì)列
2.將當(dāng)前進(jìn)程prev放入可運(yùn)行隊(duì)列中,等待下一次被重新調(diào)度
3.在當(dāng)前的可運(yùn)行隊(duì)列中選取下一個(gè)被調(diào)度的新進(jìn)程next
4.從當(dāng)前進(jìn)程切換到新進(jìn)程
轉(zhuǎn)載于:https://my.oschina.net/u/174242/blog/72938
總結(jié)
以上是生活随笔為你收集整理的基于CFS算法的schedule()源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。