os任務調(diào)度實現(xiàn)原理

為什么要做任務調(diào)度-why

操作系統(tǒng)中最為顯著的特性就是任務調(diào)度,任務調(diào)度主要來自于以下幾種需求:

  • 程序并發(fā)(multiprogram)
  • 任務間同步隔箍、消息傳遞
  • 實時性能要求
  1. 其中第一點程序并發(fā)很好理解,對于一般意義的單核硬件平臺而言脚乡,任何特定時間實際只能有一個機器指令在執(zhí)行(實際上對于現(xiàn)代cpu不準確蜒滩,例如pipeline等硬件技術實際可以令單核cpu實現(xiàn)一定程度并行指令執(zhí)行),因此只有實現(xiàn)任務調(diào)度才能實現(xiàn)多任務“齊頭并進”的效果锌订,各種任務調(diào)度算法實際是讓每個任務在用戶模式下有了獨占cpu的“假象”竹握,是對cpu硬件在時間維度上的抽象辆飘。這類任務調(diào)度一般表現(xiàn)為時間片形式芹关。

  2. 任務間的執(zhí)行順序和時機有時會需要按照一定邏輯規(guī)則進行,例如兩個進程A\B直颅,A向B寫事件功偿,B讀取事件养葵,邏輯上要求只有當A已經(jīng)寫過事件后着绊,B才可以去讀時間并執(zhí)行操作,因此需要在讀寫事件的實現(xiàn)中顯式地執(zhí)行任務調(diào)用

  3. 對于RTOS而言剧包,對實時性有高要求,因此在有外部事件到達時,根據(jù)優(yōu)先級需要立即進行響應掉缺,不同的外部事件一般對應不同的任務,因此在執(zhí)行低優(yōu)先級任務中有外部高優(yōu)先級事件到達,則需要立即做任務調(diào)度

任務調(diào)度需要做什么犬辰?-what

任務調(diào)度實際做的就是實現(xiàn)兩個任務的上下文切換(context),或者可以理解未某一時刻某一個任務的所有狀態(tài)信息诫欠,任務調(diào)度實際做的就是保存當前任務的狀態(tài)并將要切換的任務狀態(tài)恢復出來坏晦,一般而言仓蛆,一個任務的上下文主要有以下幾部分

  • stack搂蜓,函數(shù)調(diào)用棧、局部變量等
  • heap, 動態(tài)申請的內(nèi)存斯碌,而且一般由于heap中內(nèi)存由局部指針變量指向一死,實際heap的信息也是需要stack共同參與保存
  • register 具體執(zhí)行時,函數(shù)中的各種變量間的運算承耿、賦值,實際都是通過寄存器直接實現(xiàn)或者中轉(zhuǎn)的,任務執(zhí)行中一旦中斷需要保存重要寄存器的信息蚀之,一般通用的保存方法是將寄存器最后壓入棧中
  • 系統(tǒng)狀態(tài) 系統(tǒng)狀態(tài)和具體硬件平臺和os kernel實現(xiàn)有關贱纠,比如一些特殊寄存器,或者全局任務控制塊(TCB)中的特定信息等

涉及任務上下文的操作需要在硬件的特權模式下使用特定指令執(zhí)行响蕴,如切換sp指針等辖试,所以os一般在任務調(diào)度的句柄中使用匯編直接處理

怎樣實現(xiàn)任務調(diào)度?-how

不同os的任務調(diào)度的實現(xiàn)思路基本一致劈狐,這里用一種優(yōu)秀的支持任務優(yōu)先級搶占的Liteos源碼舉例說明罐孝,Liteos源碼開源可在github上下載

開始任務調(diào)度后,主要分4個步驟

  • 選取下一個需要調(diào)度的任務
/* Find the highest task */
    g_stLosTask.pstNewTask = LOS_DL_LIST_ENTRY(osPriqueueTop(), LOS_TASK_CB, stPendList);

    /* In case that running is not highest then reschedule */
    if (g_stLosTask.pstRunTask != g_stLosTask.pstNewTask) {
    // do real schedual
    osTaskSchedule();
    //....
    }

Liteos支持任務搶占肥缔,按任務隊列中最高優(yōu)先級任務作為待切換任務

  • 進入特權模式以及特權模式句柄
osTaskSchedule:
    LDR     R0, =OS_NVIC_INT_CTRL
    LDR     R1, =OS_NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR

osTaskSchedule開始進入?yún)R編莲兢,
進入特權模式的方式取決于具體硬件平臺,這里用arm-cotex-M架構舉例续膳,通過給NVIC_INT_CTRL寄存器置位改艇,觸發(fā)一個特定中斷進入pendSV句柄

  • 保存當前任務上下文
TaskSwitch:
    /**
     * R0 = now stack pointer of the current running task.
     */
    MRS     R0, PSP


    STMFD   R0!, {R4-R12}          /* save the core registers and PRIMASK. */

    LDR     R5, =g_stLosTask
    MOV     R8, #OS_TASK_STATUS_RUNNING

    /**
     * Save the stack pointer of the current running task to TCB.
     * (g_stLosTask.pstRunTask->pStackPointer = R0)
     */
    LDR     R6, [R5]
    STR     R0, [R6]

    /**
     * Clear the RUNNING state of the current running task.
     * (g_stLosTask.pstRunTask->usTaskStatus &= ~OS_TASK_STATUS_RUNNING)
     */
    LDRH    R7, [R6, #4]
    BIC     R7, R7, R8
    STRH    R7, [R6, #4]

    /**
     * Switch the current running task to the next running task.
     * (g_stLosTask.pstRunTask = g_stLosTask.pstNewTask)
     */
    LDR     R0, [R5, #4]
    STR     R0, [R5]

上面是保存當前任務contex的核心代碼,MRS R0, PSP指令獲取當前任務sp指針坟岔,并通過接下來的STMFD指令將r4~r12保存到當前任務棧中谒兄,接下來修改全局os任務控制塊信息,將當前任務狀態(tài)由running切換為ready社付,并切換當前任務控制塊到下個任務

注意承疲,arm-m架構中邻耕,進入中斷后,硬件會自動壓入r0~r3,r12,Lr,pc,xpsr 8個核心寄存器到任務棧中燕鸽,從中斷返回也會自動對應出棧

  • 恢復下一任務上下文赊豌,返回繼續(xù)執(zhí)行
    /**
     * Set the RUNNING state of the next running task.
     * (g_stLosTask.pstNewTask->usTaskStatus |= OS_TASK_STATUS_RUNNING)
     */
    LDRH    R7, [R0, #4]
    ORR     R7, R7, R8
    STRH    R7, [R0, #4]

    /**
     * Restore the stack pointer of the next running task from TCB.
     * (R1 = g_stLosTask.pstNewTask->pStackPointer)
     */
    LDR     R1, [R0]

 
    LDMFD   R1!, {R4-R12}          /* restore the core registers and PRIMASK. */

    /**
     * Set the stack pointer of the next running task to PSP.
     */
    MSR     PSP, R1

    /**
     * Restore the interruption state of the next running task.
     */
    MSR     PRIMASK, R12
    BX      LR

與保存舊任務現(xiàn)場類似,最后使用MSR PSP, R1指令將任務棧指針sp切到新的任務的棧頂绵咱,并使用跳轉(zhuǎn)指令BX從中斷返回,一旦返回熙兔,則所有現(xiàn)場信息均恢復為新任務上次中斷調(diào)度走的狀態(tài)悲伶,其中包括PC指針,則下一個機器周期就會繼續(xù)從新任務上次中斷的地方執(zhí)行住涉,這樣就實現(xiàn)了任務調(diào)度

【REF】

[ref 1] arm匯編指令集手冊
[ref 2] 內(nèi)聯(lián)匯編和匯編的兩種語法規(guī)范

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麸锉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子舆声,更是在濱河造成了極大的恐慌花沉,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件媳握,死亡現(xiàn)場離奇詭異碱屁,居然都是意外死亡,警方通過查閱死者的電腦和手機蛾找,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門娩脾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人打毛,你說我怎么就攤上這事柿赊。” “怎么了幻枉?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵碰声,是天一觀的道長。 經(jīng)常有香客問我熬甫,道長胰挑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任罗珍,我火速辦了婚禮洽腺,結果婚禮上,老公的妹妹穿的比我還像新娘覆旱。我一直安慰自己蘸朋,他們只是感情好,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布扣唱。 她就那樣靜靜地躺著藕坯,像睡著了一般团南。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炼彪,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天吐根,我揣著相機與錄音,去河邊找鬼辐马。 笑死拷橘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的喜爷。 我是一名探鬼主播冗疮,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼檩帐!你這毒婦竟也來了术幔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤湃密,失蹤者是張志新(化名)和其女友劉穎诅挑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泛源,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡拔妥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了达箍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毒嫡。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖幻梯,靈堂內(nèi)的尸體忽然破棺而出兜畸,到底是詐尸還是另有隱情,我是刑警寧澤碘梢,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布咬摇,位于F島的核電站,受9級特大地震影響煞躬,放射性物質(zhì)發(fā)生泄漏肛鹏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一恩沛、第九天 我趴在偏房一處隱蔽的房頂上張望在扰。 院中可真熱鬧,春花似錦雷客、人聲如沸芒珠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽皱卓。三九已至裹芝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間娜汁,已是汗流浹背嫂易。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掐禁,地道東北人怜械。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像傅事,于是被迫代替她去往敵國和親宫盔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容