chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

帶大家看看Linux內(nèi)核如何調(diào)度進程的

B4Pb_gh_6fde77c ? 來源:Linux內(nèi)核遠航者 ? 作者:Linux內(nèi)核遠航者 ? 2021-07-26 15:14 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1.開場白

環(huán)境:

處理器架構:arm64

內(nèi)核源碼:linux-5.11

ubuntu版本:20.04.1

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

本文步進到Linux內(nèi)核進程管理的核心部分,打開調(diào)度器的黑匣子,來看看Linux內(nèi)核如何調(diào)度進程的。實際上,進程調(diào)度器主要做兩件事:選擇下一個進程,然后進行上下文切換。

而何時調(diào)用主調(diào)度器調(diào)度進程那是調(diào)度時機所關注的問題,而調(diào)度時機在之前的內(nèi)核搶占文章已經(jīng)做了詳細講解,在此不在贅述,而本文關注的調(diào)度時機是真正調(diào)用主調(diào)度器的時機。

本文分析的內(nèi)核源代碼主要集中在:

kernel/sched/core.c

kernel/sched/fair.c

2.調(diào)用時機

關于調(diào)度時機,網(wǎng)上的文章也五花八門,之前在內(nèi)核搶占文章已經(jīng)做了詳細講解,而在本文我們從源碼注釋中給出依據(jù)(再次強調(diào)一下:本文的調(diào)度時機關注的是何時調(diào)用主調(diào)度器,不是設置重新調(diào)度標志的時機,之前講解中我們知道他們都可以稱為調(diào)度時機)。

先來說一下什么是主調(diào)度器,其實和主調(diào)度器并列的還有一個叫做周期性調(diào)度器的東西(后面有機會會講解,主要用于時鐘中斷tick調(diào)來使奪取處理器的控制權),他們都是內(nèi)核中的一個函數(shù),在合適的時機被調(diào)用。

主調(diào)度器函數(shù)如下:

kernel/sched/core.c __schedule()

內(nèi)核的很多路徑會包裝這個函數(shù),主要分為主動調(diào)度和搶占式調(diào)度場景。

內(nèi)核源碼中主調(diào)度器函數(shù)也給出了調(diào)度時機的注釋,下面我們就以此為依據(jù)來看下:

kernel/sched/core.c /* *__schedule()isthemainschedulerfunction. * *Themainmeansofdrivingtheschedulerandthusenteringthisfunctionare: * *1.Explicitblocking:mutex,semaphore,waitqueue,etc. * *2.TIF_NEED_RESCHEDflagischeckedoninterruptanduserspacereturn *paths.Forexample,seearch/x86/entry_64.S. * *Todrivepreemptionbetweentasks,theschedulersetstheflagintimer *interrupthandlerscheduler_tick(). * *3.Wakeupsdon'treallycauseentryintoschedule().Theyadda *tasktotherun-queueandthat'sit. * *Now,ifthenewtaskaddedtotherun-queuepreemptsthecurrent *task,thenthewakeupsetsTIF_NEED_RESCHEDandschedule()gets *calledonthenearestpossibleoccasion: * *-Ifthekernelispreemptible(CONFIG_PREEMPTION=y): * *-insyscallorexceptioncontext,atthenextoutmost *preempt_enable().(thismightbeassoonasthewake_up()'s *spin_unlock()!) * *-inIRQcontext,returnfrominterrupt-handlerto *preemptiblecontext * *-Ifthekernelisnotpreemptible(CONFIG_PREEMPTIONisnotset) *thenatthenext: *-cond_resched()call *-explicitschedule()call *-returnfromsyscallorexceptiontouser-space *-returnfrominterrupt-handlertouser-space * *WARNING:mustbecalledwithpreemptiondisabled! */ staticvoid__schednotrace__schedule(boolpreempt)

我們對注釋做出解釋,讓大家深刻理解調(diào)度時機(基本上是原樣翻譯,用顏色標注)。

1.顯式阻塞場景:包括互斥體、信號量、等待隊列等。

這個場景主要是為了等待某些資源而主動放棄處理器,來調(diào)用主調(diào)度器,如發(fā)現(xiàn)互斥體被其他內(nèi)核路徑所持有,則睡眠等待互斥體被釋放的時候來喚醒我。

2.在中斷和用戶空間返回路徑上檢查TIF_NEED_RESCHED標志。例如,arch/x86/entry_64.S。為了在任務之間驅(qū)動搶占,調(diào)度程序在計時器中斷處理程序scheduler_tick()中設置標志。

解釋如下:這實際上是說重新調(diào)度標志(TIF_NEED_RESCHED)的設置和檢查的情形。

1)重新調(diào)度標志設置情形:如scheduler_tick周期性調(diào)度器按照特定條件設置、喚醒的路徑上按照特定條件設置等。當前這樣的場景并不會直接調(diào)用主調(diào)度器,而會在最近的調(diào)度點到來時調(diào)用主調(diào)度器。

2)重新調(diào)度標志檢查情形:是真正的調(diào)用主調(diào)度器,下面的場景都會涉及到,在此不在贅述。

3.喚醒并不會真正導致schedule()的進入。他們添加一個任務到運行隊列,僅此而已。

現(xiàn)在,如果添加到運行隊列中的新任務搶占了當前任務,那么喚醒設置TIF_NEED_RESCHED, schedule()在最近的可能情況下被調(diào)用:

1)如果內(nèi)核是可搶占的(CONFIG_PREEMPTION=y)

-在系統(tǒng)調(diào)用或異常上下文中,最外層的preempt_enable()。(這可能和wake_up()的spin_unlock()一樣快!)

-在IRQ上下文中,從中斷處理程序返回到搶占上下文

注釋中很簡潔的幾句話,但其中的含義需要深刻去體會。

首先需要知道一點是:內(nèi)核搶占說的是處于內(nèi)核態(tài)的任務被其他任務所搶占的情況(無論是不是可搶占式內(nèi)核,處于用戶態(tài)的任務都可以被搶占,處于內(nèi)核態(tài)的任務是否能被搶占由是否開啟內(nèi)核搶占來決定),當然內(nèi)核態(tài)的任務可以是內(nèi)核線程也可以是通過系統(tǒng)調(diào)用請求內(nèi)核服務的用戶任務。

情況1:這是重新開啟內(nèi)核搶占的情況,即是搶占計數(shù)器為0時,檢查重新調(diào)度標志(TIF_NEED_RESCHED),如果設置則調(diào)用主調(diào)度器,放棄處理器(這是搶占式調(diào)度)。

情況2:中斷返回內(nèi)核態(tài)的時候,檢查重新調(diào)度標志(TIF_NEED_RESCHED),如果設置且搶占計數(shù)器為0時則調(diào)用主調(diào)度器,放棄處理器(這是搶占式調(diào)度)。

注:關于內(nèi)核搶占可以參考之前發(fā)布的文章。

2)如果內(nèi)核是不可搶占的(CONFIG_PREEMPTION=y)

cond_resched()調(diào)用

顯式的schedule()調(diào)用

從系統(tǒng)調(diào)用或異常返回到用戶空間

從中斷處理器返回到用戶空間

解釋如下:

cond_resched()是為了在不可搶占內(nèi)核的一些耗時的內(nèi)核處理路徑中增加主動搶占點(搶占計數(shù)器是否為0且當前任務被設置了重新調(diào)度標志),則調(diào)用主調(diào)度器進行搶占式調(diào)度,所進行低延時處理。

顯式的schedule()調(diào)用,這是主動放棄處理器的場景,如一些睡眠場景,像用戶任務調(diào)用sleep。

系統(tǒng)調(diào)用或異常返回到用戶空間使會判斷當前進程是否設置重新調(diào)度標志(TIF_NEED_RESCHED),如果設置則調(diào)用主調(diào)度器,放棄處理器。

中斷處理器返回到用戶空間會判斷當前進程是否設置重新調(diào)度標志(TIF_NEED_RESCHED),如果設置則調(diào)用主調(diào)度器,放棄處理器。

其實還有一種場景也會調(diào)用到主調(diào)度器讓出處理器,那就是進程退出時,這里不在贅述。

下面給出總結:

1.主動調(diào)度:

睡眠場景,如sleep。

顯式阻塞場景,如互斥體,信號量,等待隊列,完成量等。

任務退出時,調(diào)用do_exit去釋放進程資源,最后會調(diào)用一次主調(diào)度器

2.搶占調(diào)度:

不可搶占式內(nèi)核

cond_resched()調(diào)用

顯式的schedule()調(diào)用

從系統(tǒng)調(diào)用或異常返回到用戶空間

從中斷處理器返回到用戶空間

可搶占式內(nèi)核(增加一些搶占點)

重新開啟內(nèi)核搶占

中斷返回內(nèi)核態(tài)的時候

3.主調(diào)度器調(diào)用時機源碼窺探

下面給出主要的一些主調(diào)度器調(diào)用時機源碼分析,作為學習參考。

3.1 常規(guī)場景

中斷返回用戶態(tài)場景:

arch/arm64/kernel/entry.S el0_irq ->ret_to_user ->work_pending ->do_notify_resume ->if(thread_flags&_TIF_NEED_RESCHED){//arch/arm64/kernel/signal.c schedule(); ->__schedule(false);//kernel/sched/core.cfalse表示主動調(diào)度

異常返回用戶態(tài)場景:

arch/arm64/kernel/entry.S el0_sync ->ret_to_user ...

任務退出場景:

kernel/exit.c do_exit ->do_task_dead ->__schedule(false);//kernel/sched/core.cfalse表示主動調(diào)度

顯式阻塞場景(舉例互斥體):

kernel/locking/mutex.c mutex_lock ->__mutex_lock_slowpath ->__mutex_lock ->__mutex_lock_common ->schedule_preempt_disabled ->schedule(); ->__schedule(false);//kernel/sched/core.cfalse表示主動調(diào)度

3.2 支持內(nèi)核搶占場景

中斷返回內(nèi)核態(tài)場景

arch/arm64/kernel/entry.S el1_irq #ifdefCONFIG_PREEMPTION ->arm64_preempt_schedule_irq ->preempt_schedule_irq(); ->__schedule(true);//kernel/sched/core.ctrue表示搶占式調(diào)度 #endif

內(nèi)核搶占開啟場景

preempt_enable ->if(unlikely(preempt_count_dec_and_test()))//搶占計數(shù)器減一為0 __preempt_schedule(); ->preempt_schedule//kernel/sched/core.c ->__schedule(true)//調(diào)用主調(diào)度器進行搶占式調(diào)度

注:一般說異常/中斷返回,返回是處理器異常狀態(tài),可能是用戶態(tài)也可能是內(nèi)核態(tài),但是會看到很多資料寫的都是用戶空間/內(nèi)核空間并不準確,但是我們認為表達一個意思,做的心中有數(shù)即可。

3.選擇下一個進程

本節(jié)主要講解主調(diào)度器是如何選擇下一個進程的,這和調(diào)度策略強相關。

下面我們來看具體實現(xiàn):

kernel/sched/core.c __schedule ->next=pick_next_task(rq,prev,&rf); ->if(likely(prev->sched_class<=?&fair_sched_class?&&?????????????? ????????|??rq->nr_running==rq->cfs.h_nr_running)){ p=pick_next_task_fair(rq,prev,rf); if(unlikely(p==RETRY_TASK)) gotorestart; /*Assumesfair_sched_class->next==idle_sched_class*/ if(!p){ put_prev_task(rq,prev); p=pick_next_task_idle(rq); } returnp; } for_each_class(class){ p=class->pick_next_task(rq); if(p) returnp; }

這里做了優(yōu)化,當當前進程的調(diào)度類為公平調(diào)度類或者空閑調(diào)度類時,且cpu運行隊列的進程個數(shù)等于cfs運行隊列進程個數(shù),說明運行隊列進程都是普通進程,則直接調(diào)用公平調(diào)度類的pick_next_task_fair選擇下一個進程(選擇紅黑樹最左邊的那個進程),如果沒有找到說明當前進程調(diào)度類為空閑調(diào)度類,直接調(diào)用pick_next_task_idle選擇idle進程。

否則,遍歷調(diào)度類,從高優(yōu)先級調(diào)度類開始調(diào)用其pick_next_task方法選擇下一個進程。

下面以公平調(diào)度類為例來看如何選擇下一個進程的:調(diào)用過程如下(這里暫不考慮組調(diào)度情況):

pick_next_task ->pick_next_task_fair//kernel/sched/fair.c ->if(prev) put_prev_task(rq,prev); se=pick_next_entity(cfs_rq,NULL); set_next_entity(cfs_rq,se);

先看put_prev_task:

put_prev_task ->prev->sched_class->put_prev_task(rq,prev); ->put_prev_task_fair ->put_prev_entity(cfs_rq,se); ->/*Put'current'backintothetree.*/ __enqueue_entity(cfs_rq,prev); cfs_rq->curr=NULL;

這里會調(diào)用__enqueue_entity將前一個進程重新加入到cfs隊列的紅黑樹。然后將cfs_rq->curr 設置為空。

再看pick_next_entity:

pick_next_entity ->left=__pick_first_entity(cfs_rq); ->left=rb_first_cached(&cfs_rq->tasks_timeline);

將選擇cfs隊列紅黑樹最左邊進程。

最后看set_next_entity:

set_next_entity ->__dequeue_entity(cfs_rq,se); ->cfs_rq->curr=se;

這里調(diào)用__dequeue_entity將下一個選擇的進程從cfs隊列的紅黑樹中刪除,然后將cfs隊列的curr指向進程的調(diào)度實體。

選擇下一個進程總結如下:

運行隊列中只有公平進程則選擇公平調(diào)度類的pick_next_task_fair選擇進程。

當前進程為idle進程,且沒有公平進程存在情況下,調(diào)用pick_next_task_idle選擇idle進程。

運行隊列存在除了公平進程的其他進程,則從高優(yōu)先級到低優(yōu)先級調(diào)用具體調(diào)度類的pick_next_task選擇進程。

對于公平調(diào)度類,選擇下一個進程主要過程如下:1)調(diào)用put_prev_task方法將前一個進程重新加入cfs隊列的紅黑樹。2)調(diào)用pick_next_entity 選擇紅黑樹最左邊的進程作為下一個進程。3)將下一個進程從紅黑樹中刪除,cfs隊列的curr指向進程的調(diào)度實體。

通用的調(diào)度類選擇順序為:

stop_sched_class ->dl_sched_class->rt_sched_class->fair_sched_class ->idle_sched_class

比如:當前運行隊列都是cfs的普通進程,某一時刻發(fā)生中斷喚醒了一個rt進程,那么在最近的調(diào)度點到來時就會調(diào)用主調(diào)度器選擇rt進程作為next進程。

做了以上的工作之后,紅黑樹中選擇下一個進程的時候就不會再選擇到當前cpu上運行的進程了,而當前進程調(diào)度實體又被cfs隊列的curr來記錄著(運行隊列的curr也會記錄當前進程)。

下面給出公平調(diào)度類選擇下一個進程圖解(其中A為前一個進程,即是當前進程,即為前一個進程,B為下一個進程)

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    88

    文章

    11576

    瀏覽量

    216667

原文標題:深入理解Linux內(nèi)核之主調(diào)度器(上)

文章出處:【微信號:gh_6fde77c41971,微信公眾號:FPGA干貨】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    【HZ-T536開發(fā)板免費體驗】—— linux 進程創(chuàng)建

    Linux進程通信方式有這幾種: 1。管道 2。信號量 3。消息隊列 4。共享內(nèi)存 在本帖子中,我會講解fork(),exit()系統(tǒng)調(diào)用的實踐。通過應用編程來實現(xiàn)系統(tǒng)調(diào)用。 1,進程創(chuàng)建 打開
    發(fā)表于 09-01 20:49

    如何配置和驗證Linux內(nèi)核參數(shù)

    Linux系統(tǒng)運維和性能優(yōu)化中,內(nèi)核參數(shù)(sysctl)的配置至關重要。合理的參數(shù)調(diào)整可以顯著提升網(wǎng)絡性能、系統(tǒng)穩(wěn)定性及資源利用率。然而,僅僅修改參數(shù)是不夠的,如何驗證這些參數(shù)是否生效同樣關鍵。
    的頭像 發(fā)表于 05-29 17:40 ?672次閱讀

    Linux系統(tǒng)進程管理入門指南

    Linux 系統(tǒng)中,進程是正在運行的程序的實例。理解進程的管理、查看和控制對于系統(tǒng)管理員和開發(fā)者來說非常重要
    的頭像 發(fā)表于 04-22 14:34 ?687次閱讀
    <b class='flag-5'>Linux</b>系統(tǒng)<b class='flag-5'>進程</b>管理入門指南

    Linux內(nèi)核編譯失?。恳苿佑脖P和虛擬機的那些事兒

    Linux開發(fā)中,編譯內(nèi)核是一項常見任務,但不少開發(fā)者在移動硬盤或虛擬機環(huán)境下嘗試時會遭遇失敗。本文將簡要探討這些問題的成因,并介紹一些虛擬機使用技巧,幫助大家更好地應對相關問題。在移動硬盤里編譯
    的頭像 發(fā)表于 04-11 11:36 ?578次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>編譯失敗?移動硬盤和虛擬機的那些事兒

    Linux進程狀態(tài)詳解

    進程狀態(tài)是task_struct內(nèi)的一個整數(shù);進行:進程調(diào)度隊列中,進程的狀態(tài)都是running,阻塞:等待某種設備或者資源就緒。進程是一
    的頭像 發(fā)表于 04-01 09:46 ?710次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>進程</b>狀態(tài)詳解

    樹莓派4 性能大比拼:標準Linux與實時Linux 4.19內(nèi)核的延遲測試

    引言本文是對我之前關于RaspberryPi3同一主題的帖子的更新。與之前的帖子一樣,我使用的是隨Raspbian鏡像提供的標準內(nèi)核,以及應用了RT補丁的相似內(nèi)核版本。對于實時版,我
    的頭像 發(fā)表于 03-25 09:39 ?556次閱讀
    樹莓派4 性能大比拼:標準<b class='flag-5'>Linux</b>與實時<b class='flag-5'>Linux</b> 4.19<b class='flag-5'>內(nèi)核</b>的延遲測試

    基于OpenSBI的linux nommu實現(xiàn)

    Linux內(nèi)核6.10提供了對沒有mmu的riscv處理器工作在S模式下的內(nèi)核的支持,本文介紹基于OpenSBI的linuxnommu的實現(xiàn),供大家參考。1、OpenSBI介紹SBI
    的頭像 發(fā)表于 02-08 13:43 ?946次閱讀
    基于OpenSBI的<b class='flag-5'>linux</b> nommu實現(xiàn)

    騰訊云內(nèi)核團隊修復Linux關鍵Bug

    騰訊云操作系統(tǒng)(Tencent OS)內(nèi)核團隊近日在Linux社區(qū)取得了顯著成果。他們提交的兩項改進方案,成功解決了自2021年以來一直困擾眾多一線廠商,并在近期讓多個Linux頂級
    的頭像 發(fā)表于 12-31 10:58 ?839次閱讀

    深入解析Linux程序與進程

    關于某個數(shù)據(jù)集合的一次運行活動。作為系統(tǒng)進行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結構的基礎。 程序與進程的關系 進程的狀態(tài) 基礎進程狀態(tài) 創(chuàng)建狀態(tài):
    的頭像 發(fā)表于 12-18 11:01 ?728次閱讀
    深入解析<b class='flag-5'>Linux</b>程序與<b class='flag-5'>進程</b>

    飛凌嵌入式ElfBoard ELF 1板卡-Linux內(nèi)核移植之內(nèi)核簡介

    學到本章節(jié),大家應該對Linux操作系統(tǒng)都有了一定的了解,但可能還不知道我們拿到手的內(nèi)核源碼都經(jīng)歷了什么。linux有一個龐大的開源社區(qū),每個人都可以向開源社區(qū)提交代碼。由于
    發(fā)表于 12-13 09:03

    Linux之CPU調(diào)度策略和CPU親和性

    一、調(diào)度策略 調(diào)度進程 單個 CPU一次只能執(zhí)行一個進程,雖然 Linux 系統(tǒng)通過使用多任務同時處理多個
    的頭像 發(fā)表于 12-05 16:38 ?1519次閱讀
    <b class='flag-5'>Linux</b>之CPU<b class='flag-5'>調(diào)度</b>策略和CPU親和性

    深入Linux進程管理:提升效率與穩(wěn)定性的關鍵方法

    3.1Linux進程調(diào)度與多任務 3.2進程優(yōu)先級 3.3相對優(yōu)先級 3.4nice級別與權限 3.5進程優(yōu)先級調(diào)整 1.1
    的頭像 發(fā)表于 11-22 11:05 ?978次閱讀
    深入<b class='flag-5'>Linux</b><b class='flag-5'>進程</b>管理:提升效率與穩(wěn)定性的關鍵方法

    一文搞懂Linux進程的睡眠和喚醒

    ): 進程在等待某個條件滿足(如I/O操作),可以被信號喚醒。 Linux通過內(nèi)核提供的系統(tǒng)調(diào)用來控制進程的睡眠。常用的系統(tǒng)調(diào)用有: sleep(): 使
    發(fā)表于 11-04 15:15

    deepin社區(qū)亮相第19屆中國Linux內(nèi)核開發(fā)者大會

    中國 Linux 內(nèi)核開發(fā)者大會,作為中國 Linux 內(nèi)核領域最具影響力的峰會之一,一直以來都備受矚目。
    的頭像 發(fā)表于 10-29 16:35 ?1154次閱讀

    Linux用戶身份與進程權限詳解

    在學習 Linux 系統(tǒng)權限相關的主題時,我們首先關注的基本都是文件的 ugo 權限。ugo 權限信息是文件的屬性,它指明了用戶與文件之間的關系。但是真正操作文件的卻是進程,也就是說用戶所擁有的文件
    的頭像 發(fā)表于 10-23 11:41 ?1013次閱讀
    <b class='flag-5'>Linux</b>用戶身份與<b class='flag-5'>進程</b>權限詳解