天天看點

ucos-ii 任務排程

(1)任務級的任務切換原理

  μC/OS-II是一個多任務的作業系統,在沒有使用者自己定義的中斷情況下,任務間的切換步驟是這樣的:任務間的切換一般會調用OSSched()函數。函數的結構如下:

  void OSSched(void){

  關中斷

  如果(不是中斷嵌套并且系統可以被排程){

  确定優先級最高的任務

  如果(最進階的任務不是目前的任務){

  調用OSCtxSw();

  }

  開中斷

void OSSched (void)

{

    INT8U y;

    OS_ENTER_CRITICAL();

    if ((OSLockNesting | OSIntNesting) == 0) { (1)

        y             = OSUnMapTbl[OSRdyGrp]; (2)

        OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); (2)

        if (OSPrioHighRdy != OSPrioCur) { (3)

            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (4)

            OSCtxSwCtr++;                                              (5)

            OS_TASK_SW();                                              (6)

        }

    }

    OS_EXIT_CRITICAL();

}

  我們把這個函數稱作任務排程的前導函數。它先判斷要進行任務切換的條件,如果條件允許進行任務排程,則調用OSCtxSw()。這個函數是真正實作任務排程的函數。由于期間要對堆棧進行操作,是以OSCtxSw()一般用彙編語言寫成。它将正在運作的任務的CPU的SR寄存器推入堆棧,然後把R4~R15壓棧。接着把目前的SP儲存在TCB->OSTCBStkPtr中,然後把最高優先級的TCB->OSTCBStkPtr的值指派給SP。這時候,SP就已經指到最高優先級任務的任務堆棧了。然後進行出棧工作,把R15~R4出棧。接着使用RETI傳回,這樣就把SR和PC出棧了。簡單地說,μC/OS-II切換到最高優先級的任務,隻是恢複最高優先級任務所有的寄存器并運作

中斷傳回指令

(RETI),實際上,所作的隻是人為地模仿了一次中斷。

  (2)中斷級的任務切換原理

  μC/OS-II的中斷服務子程式和一般前

背景

的操作有少許不同,往往需要這樣操作:

  儲存全部CPU寄存器

  調用OSIntEnter()或OSIntNesting++

  開放中斷

  執行使用者代碼

  關閉中斷

  調用OSIntExit();

  恢複所有CPU寄存器

  RETI

  OSIntEnter()就是将全局變量OSIntNesting加1。OSIntNesting是中斷嵌套層數的變量。μC/OS-II通過它確定在中斷嵌套的時候,不進行任務排程。執行完使用者的代碼後,μC/OS-II調用OSIntExit(),一個與OSSched()很像的函數。在這個函數中,系統首先把OSIntNesting減1,然後判斷是否中斷嵌套。如果不是的話,并且目前任務不是最高優先級的任務,那麼找到優先級最高的任務,執行OSIntCtxSw()這一出中斷任務切換函數。因為,在這之前已經做好了壓棧工作;在這個函數中,要進行R15~R4的出棧工作。而且,由于在之前調用函數的時候,可能已經有一些寄存器被壓入了堆棧。是以要進行堆棧指針的調整,使得能夠從正确的位置出棧。

void OSIntExit (void)

    OS_ENTER_CRITICAL();                                             (1)

    if ((--OSIntNesting | OSLockNesting) == 0) {                     (2)

        OSIntExitY    = OSUnMapTbl[OSRdyGrp];                        (3)

        OSPrioHighRdy = (INT8U)((OSIntExitY << 3) +

                        OSUnMapTbl[OSRdyTbl[OSIntExitY]]);

        if (OSPrioHighRdy != OSPrioCur) {

            OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];

            OSCtxSwCtr++;

            OSIntCtxSw();                                            (4)

}

繼續閱讀