1. 程式人生 > >改變任務的優先順序,OSTaskChangePrio()

改變任務的優先順序,OSTaskChangePrio()

在使用者建立任務的時候會分配給任務一個優先順序。在程式執行期間,使用者可以通過呼叫OSTaskChangePrio()來改變任務的優先順序。換句話說,就是µC/OS-Ⅱ允許使用者動態的改變任務的優先順序。
	OSTaskChangePrio()的程式碼如程式清單 L4.15所示。使用者不能改變空閒任務的優先順序[L4.15(1)],但使用者可以改變呼叫本函式的任務或者其它任務的優先順序。為了改變呼叫本函式的任務的優先順序,使用者可以指定該任務當前的優先順序或OS_PRIO_SELF,OSTaskChangePrio()會決定該任務的優先順序。使用者還必須指定任務的新(即想要的)優先順序。因為µC/OS-Ⅱ不允許多個任務具有相同的優先順序,所以OSTaskChangePrio()需要檢驗新優先順序是否是合法的(即不存在具有新優先順序的任務)[L4.15(2)]。如果新優先順序是合法的,µC/OS-Ⅱ通過將某些東西儲存到OSTCBPrioTbl[newprio]中保留這個優先順序[L4.15(3)]。如此就使得OSTaskChangePrio()可以重新允許中斷,因為此時其它任務已經不可能建立擁有該優先順序的任務,也不能通過指定相同的新優先順序來呼叫OSTaskChangePrio()。接下來OSTaskChangePrio()可以預先計算新優先順序任務的OS_TCB中的某些值[L4.15(4)]。而這些值用來將任務放入就緒表或從該表中移除(參看3.04,就緒表)。
	接著,OSTaskChangePrio()檢驗目前的任務是否想改變它的優先順序[L4.15(5)]。然後,OSTaskChangePrio()檢查想要改變優先順序的任務是否存在[L4.15(6)]。很明顯,如果要改變優先順序的任務就是當前任務,這個測試就會成功。但是,如果OSTaskChangePrio()想要改變優先順序的任務不存在,它必須將保留的新優先順序放回到優先順序表OSTCBPrioTbl[]中[L4.15(17)],並返回給呼叫者一個錯誤碼。
	現在,OSTaskChangePrio()可以通過插入NULL指標將指向當前任務OS_TCB的指標從優先順序表中移除了[L4.15(7)]。這就使得當前任務的舊的優先順序可以重新使用了。接著,我們檢驗一下OSTaskChangePrio()想要改變優先順序的任務是否就緒[L4.15(8)]。如果該任務處於就緒狀態,它必須在當前的優先順序下從就緒表中移除[L4.15(9)],然後在新的優先順序下插入到就緒表中[L4.15(10)]。這兒需要注意的是,OSTaskChangePrio()所用的是重新計算的值[L4.15(4)]將任務插入就緒表中的。
	如果任務已經就緒,它可能會正在等待一個訊號量、一封郵件或是一個訊息佇列。如果OSTCBEventPtr非空(不等於NULL)[L4.15(8)],OSTaskChangePrio()就會知道任務正在等待以上的某件事。如果任務在等待某一事件的發生,OSTaskChangePrio()必須將任務從事件控制塊(參看6.00,事件控制塊)的等待佇列(在舊的優先順序下)中移除。並在新的優先順序下將事件插入到等待佇列中[L4.15(12)]。任務也有可能正在等待延時的期滿(參看第五章-任務管理)或是被掛起(參看4.07,掛起任務,OSTaskSuspend())。在這些情況下,從L4.15(8)到L4.15(12)這幾行可以略過。
	接著,OSTaskChangePrio()將指向任務OS_TCB的指標存到OSTCBPrioTbl[]中[L4.15(13)]。新的優先順序被儲存在OS_TCB中[L4.15(14)],重新計算的值也被儲存在OS_TCB中[L4.15(15)]。OSTaskChangePrio()完成了關鍵性的步驟後,在新的優先順序高於舊的優先順序或新的優先順序高於呼叫本函式的任務的優先順序情況下,任務排程程式就會被呼叫[L4.15(16)]。

程式清單 L 4.15	OSTaskChangePrio().
INT8U OSTaskChangePrio (INT8U oldprio, INT8U newprio)
{
    OS_TCB   *ptcb;
    OS_EVENT *pevent;
    INT8U     x;
    INT8U     y;
    INT8U     bitx;
    INT8U     bity;


    if ((oldprio >= OS_LOWEST_PRIO && oldprio != OS_PRIO_SELF)  ||	       (1)
         newprio >= OS_LOWEST_PRIO) {
        return (OS_PRIO_INVALID);
    }
    OS_ENTER_CRITICAL();
    if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) {	                            (2)
        OS_EXIT_CRITICAL();
        return (OS_PRIO_EXIST);
    } else {
        OSTCBPrioTbl[newprio] = (OS_TCB *)1;	                               (3)
        OS_EXIT_CRITICAL();
        y    = newprio >> 3;	                                               (4)        bity = OSMapTbl[y];
        x    = newprio & 0x07;
        bitx = OSMapTbl[x];
        OS_ENTER_CRITICAL();
        if (oldprio == OS_PRIO_SELF) {	                                     (5)
            oldprio = OSTCBCur->OSTCBPrio;
        }
        if ((ptcb = OSTCBPrioTbl[oldprio]) != (OS_TCB *)0) {	            (6)
            OSTCBPrioTbl[oldprio] = (OS_TCB *)0;	                           (7)
            if (OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) {	              (8)
                if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {(9)
                    OSRdyGrp &= ~ptcb->OSTCBBitY;
                }
                OSRdyGrp    |= bity;	                                      (10)
                OSRdyTbl[y] |= bitx;
            } else {
                if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) {	(11)
                    if ((pevent->OSEventTbl[ptcb->OSTCBY] &=      
                         ~ptcb->OSTCBBitX) == 0) {
                        pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
                    }
                    pevent->OSEventGrp    |= bity;	                   (12)
                    pevent->OSEventTbl[y] |= bitx;
                }
            }
            OSTCBPrioTbl[newprio] = ptcb;	                                 (13)
            ptcb->OSTCBPrio       = newprio;	                              (14)
            ptcb->OSTCBY          = y;	                                    (15)
            ptcb->OSTCBX          = x;
            ptcb->OSTCBBitY       = bity;
            ptcb->OSTCBBitX       = bitx;
            OS_EXIT_CRITICAL();
            OSSched();	                                                    (16)
            return (OS_NO_ERR);
        } else {            OSTCBPrioTbl[newprio] = (OS_TCB *)0;	                          (17)
            OS_EXIT_CRITICAL();
            return (OS_PRIO_ERR);
        }
    }
}