想讓?C/OS-Ⅱ系統管理使用者的任務,使用者必須要先建立任務。使用者可以通過傳遞任務地址和其它參數到以下兩個函數之一來建立任務:OSTaskCreate() 或 OSTaskCreateExt()。OSTaskCreate()與?C/OS是向下相容的,OSTaskCreateExt()是OSTaskCreate()的擴充版本,提供了一些附加的功能。用兩個函數中的任何一個都可以建立任務。任務可以在多任務調度開始前建立,也可以在其它任務的執行過程中被建立。在開始多任務調度(即調用OSStart())前,使用者必須建立至少一個任務。任務不能由中斷服務程式(ISR)來建立。
OSTaskCreate()的代碼如程式清單 L4.1所述。從中可以知道,OSTaskCreate()需要四個參數:task是任務代碼的指標,pdata是當任務開始執行時傳遞給任務的參數的指標,ptos是分配給任務的堆棧的棧頂指標(參看4.02,任務堆棧),prio是分配給任務的優先順序。
程式清單 L4.1 OSTaskCreate() |
INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio) |
{ |
void *psp; |
INT8U err; |
|
|
if (prio > OS_LOWEST_PRIO) { (1) |
return (OS_PRIO_INVALID); |
} |
OS_ENTER_CRITICAL(); |
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { (2) |
OSTCBPrioTbl[prio] = (OS_TCB *)1; (3) |
OS_EXIT_CRITICAL(); (4) |
psp = (void *)OSTaskStkInit(task, pdata, ptos, 0); (5) |
err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0); (6) |
if (err == OS_NO_ERR) { (7) |
OS_ENTER_CRITICAL(); |
OSTaskCtr++; (8) |
OSTaskCreateHook(OSTCBPrioTbl[prio]); (9) |
OS_EXIT_CRITICAL(); |
if (OSRunning) { (10) |
OSSched(); (11) |
} |
} else { |
OS_ENTER_CRITICAL(); |
OSTCBPrioTbl[prio] = (OS_TCB *)0; (12) |
OS_EXIT_CRITICAL(); |
} |
return (err); |
} else { |
OS_EXIT_CRITICAL(); |
return (OS_PRIO_EXIST); |
} |
} |
OSTaskCreate()一開始先檢測分配給任務的優先順序是否有效[L4.1(1)]。任務的優先順序必須在0到OS_LOWEST_PRIO之間。接著,OSTaskCreate()要確保在規定的優先順序上還沒有建立任務[L4.1(2)]。在使用?C/OS-Ⅱ時,每個任務都有特定的優先順序。如果某個優先順序是閒置,?C/OS-Ⅱ通過放置一個非null 指標在OSTCBPrioTbl[]中來保留該優先順序[L4.1(3)]。這就使得OSTaskCreate()在設定任務資料結構的其他部分時能重新允許中斷[L4.1(4)]。
然後,OSTaskCreate()調用OSTaskStkInit()[L4.1(5)],它負責建立任務的堆棧。該函數是與處理器的硬體體系相關的函數,可以在OS_CPU_C.C檔案中找到。有關實現OSTaskStkInit()的細節可參看第8章——移植?C/OS-Ⅱ。如果已經有人在你用的處理器上成功地移植了?C/OS-Ⅱ,而你又得到了他的代碼,就不必考慮該函數的實現細節了。OSTaskStkInit()函數返回新的堆棧棧頂(psp),並被儲存在任務的0S_TCB中。注意使用者得將傳遞給OSTaskStkInit()函數的第四個參數opt置0,因為OSTaskCreate()與OSTaskCreateExt()不同,它不支援使用者為任務的建立過程設定不同的選項,所以沒有任何選項可以通過opt參數傳遞給OSTaskStkInit()。
?C/OS-Ⅱ支援的處理器的堆棧既可以從上(高地址)往下(低地址)遞減也可以從下往上遞增。使用者在調用OSTaskCreate()的時候必須知道堆棧是遞增的還是遞減的(參看所用處理器的OS_CPU.H中的OS_STACK_GROWTH),因為使用者必須得把堆棧的棧頂傳遞給OSTaskCreate(),而棧頂可能是堆棧的最高地址(堆棧從上往下遞減),也可能是最低地址(堆棧從下往上長)。
一旦OSTaskStkInit()函數完成了建立堆棧的任務,OSTaskCreate()就調用OSTCBInit()[L4.1(6)],從閒置OS_TCB池中獲得並初始化一個OS_TCB。OSTCBInit()的代碼如程式清單 L4.2所示,它存在於0S_CORE.C檔案中而不是OS_TASK.C檔案中。OSTCBInit()函數首先從OS_TCB緩衝池中獲得一個OS_TCB[L4.2(1)],如果OS_TCB池中有閒置OS_TCB[L4.2(2)],它就被初始化[L4.2(3)]。注意一旦OS_TCB被分配,該任務的建立者就已經完全擁有它了,即使這時核心又建立了其它的任務,這些新任務也不可能對已指派的OS_TCB作任何操作,所以OSTCBInit()在這時就可以允許中斷,並繼續初始化OS_TCB的資料單元。
程式清單 L 4.2 OSTCBInit() |
INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr; #endif OS_TCB *ptcb; OS_ENTER_CRITICAL(); ptcb = OSTCBFreeList; /* Get a free TCB from the free TCB list */ if (ptcb != (OS_TCB *)0) { OSTCBFreeList = ptcb->OSTCBNext; /* Update pointer to free TCB list */ OS_EXIT_CRITICAL(); ptcb->OSTCBStkPtr = ptos; /* Load Stack pointer in TCB */ ptcb->OSTCBPrio = (INT8U)prio; /* Load task priority into TCB */ ptcb->OSTCBStat = OS_STAT_RDY; /* Task is ready to run */ ptcb->OSTCBDly = 0; /* Task is not delayed */ #if OS_TASK_CREATE_EXT_EN > 0 ptcb->OSTCBExtPtr = pext; /* Store pointer to TCB extension */ ptcb->OSTCBStkSize = stk_size; /* Store stack size */ ptcb->OSTCBStkBottom = pbos; /* Store pointer to bottom of stack */ ptcb->OSTCBOpt = opt; /* Store task options */ ptcb->OSTCBId = id; /* Store task ID */ #else pext = pext; /* Prevent compiler warning if not used */ stk_size = stk_size; pbos = pbos; opt = opt; id = id; #endif #if OS_TASK_DEL_EN > 0 ptcb->OSTCBDelReq = OS_NO_ERR; #endif ptcb->OSTCBY = prio >> 3; /* Pre-compute X, Y, BitX and BitY */ ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY]; ptcb->OSTCBX = prio & 0x07; ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX]; #if OS_EVENT_EN > 0 ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Task is not pending on an event */ #endif #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0) ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* Task is not pending on an event flag */ #endif #if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) ptcb->OSTCBMsg = (void *)0; /* No message received */ #endif #if OS_VERSION >= 204 OSTCBInitHook(ptcb); #endif OSTaskCreateHook(ptcb); /* Call user defined hook */ OS_ENTER_CRITICAL(); OSTCBPrioTbl[prio] = ptcb; ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain */ ptcb->OSTCBPrev = (OS_TCB *)0; if (OSTCBList != (OS_TCB *)0) { OSTCBList->OSTCBPrev = ptcb; } OSTCBList = ptcb; OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; OS_EXIT_CRITICAL(); return (OS_NO_ERR); } OS_EXIT_CRITICAL(); return (OS_NO_MORE_TCB); } |