uCOS-II系統中的任務排程
阿新 • • 發佈:2019-02-12
在前面的os_cpu_a.asm原始碼分析中看到了任務切換的函式OSCtxSw:
OSCtxSw
LDR R0, =NVIC_INT_CTRL
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
此函式是作業系統自己使用的任務切換函式,實質上只是觸發pendSV,在pendSV中斷服務函式在實現真正的切換任務。
pendSV的中斷服務函式實現體為:
OS_CPU_PendSVHandler
CPSID I
MRS R0, PSP
CBZ R0, OS_CPU_PendSVHandler_nosave
SUBS R0, R0, #0x20
STM R0, {R4-R11}
;...
END
在系統執行中,作業系統總要自己去切換任務(而非一定得等systick超時),例如某任務阻塞的獲取某事件獲取不到時候,系統就要切換任務。系統呼叫的函式是OS_Sched(),其實現體為:
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
OS_ENTER_CRITICAL();
if (OSIntNesting == 0) {
if (OSLockNesting == 0 ) {
OS_SchedNew(); /* 查表運算得出要執行的任務 */
if (OSPrioHighRdy != OSPrioCur) {
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++;
#endif
OSCtxSwCtr++;
OS_TASK_SW(); /* 執行作業系統正常的任務切換 */
}
}
}
OS_EXIT_CRITICAL();
}
此函式首先呼叫OS_SchedNew()找出當前系統優先順序的任務,將其優先順序賦值給全域性變數OSTCBHighRdy,接著呼叫OS_TASK_SW()進行當前任務和OSTCBHighRdy標記的優先順序的任務切換。OS_TASK_SW()是一個巨集:
#define OS_TASK_SW() OSCtxSw() /* 作業系統任務切換 ctx表context,上下文 */
實質就是上面講到的在os_cpu_a.asm實現的單純觸發pendSVOSCtxSw。
在CPU中有一個特殊功能的暫存器–程式執行指標PC,它使用者指向執行的程式的,CPU要執行新的任務,就必須要讓PC指標獲得新任務的執行地址(或者說斷點地址)。既然如此,被中止執行的任務就應該把自身的PC指標的內容保壓入自身堆疊中;而對待執行的任務而言,就應該把任務堆疊中上次任務被中止時存放在堆疊的PC指標的內容壓入PC暫存器。但是目前的處理器並不可以對PC暫存器的內容進行壓棧和出棧。要想保留PC暫存器的內容,可行的辦法就是引發一次中斷(或者一次函式呼叫),OSCtxSw()就觸發了一個pendSVOSCtxSw中斷,系統在跳轉到中斷服務函式時,會自動地將PC指標壓入堆疊,中斷處理函式返回時也能將PC指標出棧,這樣就可以實現PC指標的儲存與恢復了。