1. 程式人生 > >uCOS-II系統中的任務排程

uCOS-II系統中的任務排程

  在前面的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指標的儲存與恢復了。