![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Quick and dirty CoOS + LWIP ( Webserver )
Diff: CoOS/kernel/task.c
- Revision:
- 0:94897d537b31
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CoOS/kernel/task.c Sat Sep 10 22:41:10 2011 +0000 @@ -0,0 +1,1260 @@ +/** + ******************************************************************************* + * @file task.c + * @version V1.1.4 + * @date 2011.04.20 + * @brief task management implementation code of CooCox CoOS kernel. + ******************************************************************************* + * @copy + * + * INTERNAL FILE,DON'T PUBLIC. + * + * <h2><center>© COPYRIGHT 2009 CooCox </center></h2> + ******************************************************************************* + */ + + +/*---------------------------- Include ---------------------------------------*/ +#include <coocox.h> + +/*---------------------------- Variable Define -------------------------------*/ + +/*!< Table use to save TCB pointer. */ +OSTCB TCBTbl[CFG_MAX_USER_TASKS+SYS_TASK_NUM] = {{0}}; + +/*!< The stack of IDLE task. */ +OS_STK idle_stk[CFG_IDLE_STACK_SIZE] = {0}; + +P_OSTCB FreeTCB = 0; /*!< pointer to free TCB */ +P_OSTCB TCBRdy = 0; /*!< Pointer to the READY list. */ +P_OSTCB TCBNext = 0; /*!< Poniter to task that next scheduled by OS */ +P_OSTCB TCBRunning = 0; /*!< Pointer to TCB that current running task. */ +U64 OSCheckTime = 0; /*!< The counter of system tick. */ + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 +OS_TID PriNum; +U8 ActivePri[CFG_MAX_USER_TASKS+SYS_TASK_NUM]; +U8 TaskNumPerPri[CFG_MAX_USER_TASKS+SYS_TASK_NUM]; +OS_TID RdyTaskPri[CFG_MAX_USER_TASKS+SYS_TASK_NUM] = {0}; +U32 RdyTaskPriInfo[(CFG_MAX_USER_TASKS+SYS_TASK_NUM+31)/32]; +#endif + + +/** + ******************************************************************************* + * @brief Create a TCB list. + * @param[in] None + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called by CoOSInit() to initial the empty list + * of OS_TCBS,supply a pointer to free TCB. + ******************************************************************************* + */ +void CreateTCBList(void) +{ + U8 i; + P_OSTCB ptcb1,ptcb2; + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + PriNum = 0; +#endif + + ptcb1 = &TCBTbl[0]; /* Build the free TCB list */ + ptcb2 = &TCBTbl[1]; + for(i=0;i< (CFG_MAX_USER_TASKS+SYS_TASK_NUM-1);i++ ) + { + ptcb1->taskID = i; + ptcb1->state = TASK_DORMANT; + ptcb1->TCBnext = ptcb2; +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + RdyTaskPri[i] = INVALID_ID; + ActivePri[i] = INVALID_ID; +#endif + ptcb1++; + ptcb2++; + } +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + ActivePri[i] = INVALID_ID; +#endif + + ptcb1->taskID = i; + ptcb1->TCBnext = 0; + FreeTCB = &TCBTbl[0]; /* Initialize FreeTCB as head item of list */ +} + + + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + +/** + ******************************************************************************* + * @brief Get sequence number for Assign priority + * @param[in] pri Assign priority + * @param[out] SequenceNum priority number + * @retval Co_TRUE Assign priority in priority queue. + * Co_FALSE Assign priority not in priority queue. + * + * @par Description + * @details This function is called in Binary-Scheduling Algorithm + * to get sequence number for Assign priority. + ******************************************************************************* + */ +static BOOL GetPriSeqNum(U8 pri,OS_TID* SequenceNum) +{ + OS_TID seqNum; + OS_TID num,tmpNum; + num = 0; + seqNum = PriNum; + while(num != seqNum) + { + tmpNum = num; + num = (num+seqNum)/2; + if(pri == ActivePri[num]) + { + *SequenceNum = num; + return Co_TRUE; + } + else if (pri < ActivePri[num]) + { + seqNum = num; + num = tmpNum; + } + else + { + num++; + } + } + *SequenceNum = num; + return Co_FALSE; +} + + +/** + ******************************************************************************* + * @brief Get the nearest ready priority sequence number for Assign number + * @param[in] seqNum Assign sequence number + * @param[out] None + * @retval INVALID_ID Cannot find higher ready priority. + * Others Nearest ready priority sequence number + * + * @par Description + * @details This function is called in Binary-Scheduling Algorithm + * to get the nearest ready priority sequence number. + ******************************************************************************* + */ +static U8 GetRdyPriSeqNum(U8 seqNum) +{ + U32 tmp; + U8 i,j,num; + S8 cnt; + i = seqNum/32; + j = seqNum%32; + + do + { + tmp = RdyTaskPriInfo[i]; + if(tmp != 0) + { + num = j/8; + do + { + if((tmp&(0xff<<(num*8))) !=0 ) + { + if((tmp&(0xf0<<(num*8))) !=0) + { + for(cnt=j; cnt >=(num*8+4); cnt--) + { + if( (tmp&(1<<cnt)) !=0) + { + return (32*i+cnt); + } + } + } + + if((j&0x4)==4) + j = (j|0x3) -4; + + for(cnt=j; cnt >=num*8; cnt--) + { + if( (tmp&(1<<cnt)) !=0) + { + return (32*i+cnt); + } + } + } + j = num*8 -1; + }while((num--)!=0); + } + j=31; + }while((i--)!=0); + return INVALID_ID; +} + + +/** + ******************************************************************************* + * @brief Remap the ready status of priority queue from Assign sequence number + * @param[in] seqNum Assign sequence number + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called in Binary-Scheduling Algorithm + * to Remap the ready status for priority queue. + ******************************************************************************* + */ +static void PrioRemap(OS_TID seqNum) +{ + U8 i,j; + U32 tmp; + tmp = j = 0; + j = seqNum/32; + for(i=0;i<seqNum%32;i++) + { + tmp |= 1<<i; + } + tmp &= RdyTaskPriInfo[j]; + + for(i=seqNum; i<PriNum; i++) + { + if((i%32==0)&&(i!=seqNum)) + { + RdyTaskPriInfo[j++] = tmp; + tmp = 0; + } + if(RdyTaskPri[i] != INVALID_ID) + { + tmp = tmp | (1<<(i%32)); + } + } + RdyTaskPriInfo[j++] = tmp; +} + + +/** + ******************************************************************************* + * @brief Get the ready status for assign sequence number + * @param[in] seqNum Assign sequence number + * @param[out] None + * @retval Co_TRUE This priority has ready task + * Co_FALSE This priority doesn't have ready task + * + * @par Description + * @details This function is called in Binary-Scheduling Algorithm + * to get the ready status for assign sequence number. + ******************************************************************************* + */ +static BOOL GetPrioSeqNumStatus(U8 seqNum) +{ + if( (RdyTaskPriInfo[seqNum/32] & (1<<(seqNum%32))) == 0) + { + return Co_FALSE; + } + return Co_TRUE; +} + + +/** + ******************************************************************************* + * @brief Set the ready status for assign sequence number + * @param[in] seqNum Assign sequence number + * @param[in] isRdy Ready statues for assign sequence number + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called in Binary-Scheduling Algorithm + * to set the ready status for assign sequence number. + ******************************************************************************* + */ +static void SetPrioSeqNumStatus(U8 seqNum, BOOL isRdy) +{ + U32 tmp; + tmp = RdyTaskPriInfo[seqNum/32]; + tmp &= ~(1<<(seqNum%32)); + tmp |= isRdy<<(seqNum%32); + RdyTaskPriInfo[seqNum/32] = tmp; +} + + +/** + ******************************************************************************* + * @brief Active priority in queue + * @param[in] pri Task priority + * @param[in] None + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called in Binary-Scheduling Algorithm + * to active priority in queue, if this priority had been in activation, + * increate the task num for this priority. + ******************************************************************************* + */ +void ActiveTaskPri(U8 pri) +{ + OS_TID seqNum,num; + if(GetPriSeqNum(pri,&seqNum) == Co_FALSE) + { + for(num=PriNum;num>seqNum;num--) + { + ActivePri[num] = ActivePri[num-1]; + TaskNumPerPri[num] = TaskNumPerPri[num-1]; + RdyTaskPri[num] = RdyTaskPri[num-1]; + } + ActivePri[seqNum] = pri; + TaskNumPerPri[seqNum] = 1; + RdyTaskPri[seqNum] = INVALID_ID; + PriNum++; + PrioRemap(seqNum); + } + else + { + TaskNumPerPri[seqNum]++; + } +} + + + +/** + ******************************************************************************* + * @brief Delete priority in queue + * @param[in] pri Task priority + * @param[in] None + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called in Binary-Scheduling Algorithm + * to decrease the task num for this priority, if the num goto 0, + * remove the priority for queue. + ******************************************************************************* + */ +void DeleteTaskPri(U8 pri) +{ + OS_TID seqNum,num; + + GetPriSeqNum(pri,&seqNum); + TaskNumPerPri[seqNum]--; + if(TaskNumPerPri[seqNum]==0) + { + for(num=seqNum; num<(PriNum-1); num++) + { + ActivePri[num] = ActivePri[num+1]; + TaskNumPerPri[num] = TaskNumPerPri[num+1]; + RdyTaskPri[num] = RdyTaskPri[num+1]; + } + PriNum--; + PrioRemap(seqNum); + } +} + +#endif + + +/** + ******************************************************************************* + * @brief Insert a task to the ready list + * @param[in] tcbInsert A pointer to task will be inserted. + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called to insert a task to the READY list. + ******************************************************************************* + */ +void InsertToTCBRdyList(P_OSTCB tcbInsert) +{ + P_OSTCB ptcbNext,ptcb; + U8 prio; +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + U8 seqNum; + U8 RdyTaskSeqNum; +#endif + + prio = tcbInsert->prio; /* Get PRI of inserted task */ + tcbInsert->state = TASK_READY; /* Set task as TASK_READY */ + +#if CFG_ROBIN_EN >0 + ptcb = TCBRunning; + /* Set schedule time for the same PRI task as TCBRunning. */ + if(prio == ptcb->prio) /* Is PRI of inserted task equal to running task? */ + { + if(ptcb != tcbInsert) /* Yes,is inserted task equal to running task? */ + { + if(ptcb != Co_NULL) /* No,TCBRunning == Co_NULL? */ + { /* N0,OSCheckTime < OSTickCnt? */ + if(OSCheckTime < OSTickCnt) + { /* Yes,set OSCheckTime for task robin */ + OSCheckTime = OSTickCnt + ptcb->timeSlice; + } + } + } + } +#endif + + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + GetPriSeqNum(prio,&seqNum); + if(GetPrioSeqNumStatus(seqNum) == Co_TRUE) + { + ptcb = &TCBTbl[RdyTaskPri[seqNum]]; + RdyTaskPri[seqNum] = tcbInsert->taskID; + } + else + { + RdyTaskPri[seqNum] = tcbInsert->taskID; + RdyTaskSeqNum = GetRdyPriSeqNum(seqNum); + SetPrioSeqNumStatus(seqNum, 1); + if(RdyTaskSeqNum == INVALID_ID) + { + ptcb = TCBRdy; + TaskSchedReq = Co_TRUE; + if(ptcb == Co_NULL) + { + TCBRdy = tcbInsert; + } + else + { + tcbInsert->TCBnext = ptcb; /* Yes,set tcbInsert as head item of list */ + ptcb->TCBprev = tcbInsert; + TCBRdy = tcbInsert; + } + return; + } + else + { + ptcb = &TCBTbl[RdyTaskPri[RdyTaskSeqNum]]; + } + } + + ptcbNext = ptcb->TCBnext; + tcbInsert->TCBnext = ptcbNext; /* Set link for list */ + ptcb->TCBnext = tcbInsert; + tcbInsert->TCBprev = ptcb; + if(ptcbNext != Co_NULL) + { + ptcbNext->TCBprev = tcbInsert; + } + + +#else + ptcb = TCBRdy; + if (ptcb == Co_NULL) /* Is ready list Co_NULL? */ + { + TaskSchedReq = Co_TRUE; + TCBRdy = tcbInsert; /* Yse,set tcbInsert as head item of list */ + } + else if (prio < ptcb->prio)/* Is PRI of inserted task higher than TCBRdy? */ + { + TaskSchedReq = Co_TRUE; + tcbInsert->TCBnext = ptcb; /* Yes,set tcbInsert as head item of list */ + ptcb->TCBprev = tcbInsert; + TCBRdy = tcbInsert; + } + else /* No,find correct place */ + { + ptcbNext = ptcb->TCBnext; /* Get next item */ + while(ptcbNext != Co_NULL) /* Is last item in ready list? */ + { /* No,find correct place */ + if(prio < ptcbNext->prio) /* Is correct place? */ + break; /* Yes,break circulation */ + ptcb = ptcbNext; /* Save current item */ + ptcbNext = ptcbNext->TCBnext; /* Get next item */ + } + tcbInsert->TCBnext = ptcbNext; /* Set link for list */ + ptcb->TCBnext = tcbInsert; + tcbInsert->TCBprev = ptcb; + if(ptcbNext != Co_NULL) + { + ptcbNext->TCBprev = tcbInsert; + } + } +#endif +} + + + +/** + ******************************************************************************* + * @brief Remove a task from the READY list + * @param[in] ptcb A pointer to task which be removed. + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called to remove a task from the READY list. + ******************************************************************************* + */ +void RemoveFromTCBRdyList(P_OSTCB ptcb) +{ + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + U8 prio; + U8 seqNum; + BOOL isChange; + isChange = Co_FALSE; + prio = ptcb->prio; + GetPriSeqNum(prio,&seqNum); +#endif + + /* Is there only one item in READY list? */ + if((ptcb->TCBnext == Co_NULL) && (ptcb->TCBprev == Co_NULL) ) + { + TCBRdy = 0; /* Yes,set READY list as Co_NULL */ +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + isChange = Co_TRUE; +#endif + } + else if(ptcb->TCBprev == 0) /* Is the first item in READY list? */ + { + /* Yes,remove task from the list,and reset the head of READY list */ + TCBRdy = ptcb->TCBnext; + ptcb->TCBnext = 0; + TCBRdy->TCBprev = 0; +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + if(TCBRdy->prio != prio) + isChange = Co_TRUE; + +#endif + } + else if( ptcb->TCBnext == 0) /* Is the last item in READY list? */ + { /* Yes,remove task from list */ +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + if(ptcb->TCBprev->prio != prio) + isChange = Co_TRUE; + else + RdyTaskPri[seqNum] = ptcb->TCBprev->taskID; +#endif + ptcb->TCBprev->TCBnext = 0; + ptcb->TCBprev = 0; + } + else /* No, remove task from list */ + { +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + if((ptcb->TCBprev->prio != prio) && (ptcb->TCBnext->prio != prio)) + isChange = Co_TRUE; + else if((ptcb->TCBprev->prio == prio) && (ptcb->TCBnext->prio != prio)) + RdyTaskPri[seqNum] = ptcb->TCBprev->taskID; +#endif + ptcb->TCBprev->TCBnext = ptcb->TCBnext; + ptcb->TCBnext->TCBprev = ptcb->TCBprev; + ptcb->TCBnext = 0; + ptcb->TCBprev = 0; + } +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + if(isChange == Co_TRUE) + { + RdyTaskPri[seqNum] = INVALID_ID; + SetPrioSeqNumStatus(seqNum, 0); + } +#endif +} + + +#if CFG_MUTEX_EN > 0 +#define CFG_PRIORITY_SET_EN (1) +#endif +#if CFG_PRIORITY_SET_EN >0 +/** + ******************************************************************************* + * @brief Change task priority + * @param[in] taskID Specify task id. + * @param[in] priority New priority. + * @param[out] None + * @retval E_OK Change priority successful. + * @retval E_INVALID_ID Invalid id,change priority fail. + * @retval E_PROTECTED_TASK Can't change idle task priority. + * + * @par Description + * @details This function is called to change priority for a specify task. + ******************************************************************************* + */ +StatusType CoSetPriority(OS_TID taskID,U8 priority) +{ + P_OSTCB ptcb; +#if CFG_MUTEX_EN >0 + U8 prio; + P_MUTEX pMutex; +#endif +#if CFG_EVENT_EN >0 + P_ECB pecb; +#endif + + if(taskID == 0) /* Is idle task? */ + { + return E_PROTECTED_TASK; /* Yes,error return */ + } + +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if(taskID >= CFG_MAX_USER_TASKS + SYS_TASK_NUM) + { + return E_INVALID_ID; + } +#endif + ptcb = &TCBTbl[taskID]; /* Get TCB of task ID */ +#if CFG_PAR_CHECKOUT_EN >0 + if(ptcb->state == TASK_DORMANT) + { + return E_INVALID_ID; + } + if(priority > CFG_LOWEST_PRIO) + { + return E_INVALID_ID; + } +#endif + + if(ptcb->prio != priority) /* Is PRI equal to original PRI? */ + { /* No */ +#if CFG_MUTEX_EN >0 + if(ptcb->mutexID != INVALID_ID) + { + pMutex = &MutexTbl[ptcb->mutexID]; + if(pMutex->taskID == ptcb->taskID) /* Task hold mutex? */ + { + pMutex->originalPrio= priority;/* Yes,change original PRI in mutex*/ + if(ptcb->prio < priority) /* Is task priority higher than set?*/ + { + return E_OK; /* Yes,do nothing,return OK */ + } + } + } + +#endif + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + DeleteTaskPri(ptcb->prio); + ActiveTaskPri(priority); +#endif + + ptcb->prio = priority; /* Change task PRI */ + if(ptcb->state == TASK_READY) /* Is task in READY list? */ + { + OsSchedLock(); /* Yes,reorder task in READY list */ + RemoveFromTCBRdyList(ptcb); + InsertToTCBRdyList(ptcb); + OsSchedUnlock(); + } + else if(ptcb->state == TASK_RUNNING)/* Is task running? */ + { + if(ptcb->prio > TCBRdy->prio) /* Yes,Is PRI higher than TCBRdy? */ + { + OsSchedLock(); /* Yes,reorder task in READY list */ + TaskSchedReq = Co_TRUE; + OsSchedUnlock(); + } + } + else + { /* No,task in WAITING list */ +#if CFG_MUTEX_EN >0 + if(ptcb->mutexID != INVALID_ID) /* Is task in mutex WAITING list? */ + { + /* Yes,reset the highest PRI in the list */ + OsSchedLock(); + pMutex = &MutexTbl[ptcb->mutexID]; + ptcb = pMutex->waittingList; + prio = pMutex->originalPrio; + pMutex->hipriTaskID = pMutex->taskID; + while(ptcb != Co_NULL) + { + if(ptcb->prio < prio) + { + prio = ptcb->prio; + pMutex->hipriTaskID = ptcb->taskID; + } + ptcb = ptcb->TCBnext; + } + OsSchedUnlock(); + if(pMutex->originalPrio != prio) + { + CoSetPriority(pMutex->taskID,prio); + } + } +#endif + +#if CFG_EVENT_EN >0 + ptcb = &TCBTbl[taskID]; + if(ptcb->eventID != INVALID_ID) /* Is task in event WAITING list? */ + { + pecb = &EventTbl[ptcb->eventID]; + + /* Yes,is event sort type as preemptive PRI? */ + if(pecb->eventSortType == EVENT_SORT_TYPE_PRIO) + { + /* Yes,reorder task in the list */ + RemoveEventWaittingList(ptcb); + EventTaskToWait(pecb,ptcb); + } + } +#endif + } + } + return E_OK; +} +#endif + +/** + ******************************************************************************* + * @brief Schedule function + * @param[in] None + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called by every where need to switch context, + * It is schedule function of OS kernel. + ******************************************************************************* + */ +void Schedule(void) +{ + U8 RunPrio,RdyPrio; + P_OSTCB pRdyTcb,pCurTcb; + + + pCurTcb = TCBRunning; + pRdyTcb = TCBRdy; + + if((pRdyTcb==Co_NULL) || (pCurTcb != TCBNext) || (OSSchedLock >1) || (OSIntNesting >0)) + { + return; + } + + TaskSchedReq = Co_FALSE; + RunPrio = pCurTcb->prio; + RdyPrio = pRdyTcb->prio; + + /* Is Running task status was changed? */ + if(pCurTcb->state != TASK_RUNNING) + { + TCBNext = pRdyTcb; /* Yes,set TCBNext and reorder READY list */ + pRdyTcb->state = TASK_RUNNING; + RemoveFromTCBRdyList(pRdyTcb); + } + + else if(RdyPrio < RunPrio ) /* Is higher PRI task coming in? */ + { + TCBNext = pRdyTcb; /* Yes,set TCBNext and reorder READY list */ + InsertToTCBRdyList(pCurTcb); + RemoveFromTCBRdyList(pRdyTcb); + pRdyTcb->state = TASK_RUNNING; + } + +#if CFG_ROBIN_EN >0 /* Is time for robinning */ + else if((RunPrio == RdyPrio) && (OSCheckTime == OSTickCnt)) + { + TCBNext = pRdyTcb; /* Yes,set TCBNext and reorder READY list */ + InsertToTCBRdyList(pCurTcb); + RemoveFromTCBRdyList(pRdyTcb); + pRdyTcb->state = TASK_RUNNING; + } +#endif + else + { + return; + } + +#if CFG_ROBIN_EN >0 + if(TCBNext->prio == TCBRdy->prio) /* Reset OSCheckTime for task robinnig */ + OSCheckTime = OSTickCnt + TCBNext->timeSlice; +#endif + + +#if CFG_STK_CHECKOUT_EN > 0 /* Is stack overflow? */ + if((pCurTcb->stkPtr < pCurTcb->stack)||(*(U32*)(pCurTcb->stack) != MAGIC_WORD)) + { + CoStkOverflowHook(pCurTcb->taskID); /* Yes,call handler */ + } +#endif + + SwitchContext(); /* Call task context switch */ +} + + +/** + ******************************************************************************* + * @brief Assign a TCB to task being created + * @param[in] None + * @param[out] None + * + * @retval XXXX + * + * @par Description + * @details This function is called to assign a task control block for task + * being created. + ******************************************************************************* + */ +static P_OSTCB AssignTCB(void) +{ + P_OSTCB ptcb; + + OsSchedLock(); /* Lock schedule */ + if(FreeTCB == 0) /* Is there no free TCB */ + { + OsSchedUnlock(); /* Yes,unlock schedule */ + return 0; /* Error return */ + } + ptcb = FreeTCB; /* Yes,assgin free TCB for this task */ + /* Set next item as the head of free TCB list */ + FreeTCB = FreeTCB->TCBnext; + OsSchedUnlock(); + return ptcb; +} + + +/** + ******************************************************************************* + * @brief Create a task + * @param[in] task Task code entry. + * @param[in] argv The parameter passed to task. + * @param[in] parameter Task priority + stack size + time slice + isWaitting. + * @param[in] stk Pointer to stack top of task. + * @param[out] None + * @retval E_CREATE_FAIL Fail to create a task . + * @retval others Valid task id. + * + * @par Description + * @details This function is called by application to create a task,return a id + * to mark this task. + ******************************************************************************* + */ +OS_TID CreateTask(FUNCPtr task,void *argv,U32 parameter,OS_STK *stk) +{ + OS_STK* stkTopPtr; + P_OSTCB ptcb; + U8 prio; +#if CFG_ROBIN_EN >0 + U16 timeSlice; +#endif + +#if CFG_STK_CHECKOUT_EN >0 /* Check validity of parameter */ + U16 sktSz; + sktSz = (parameter&0xfff00)>>8; +#endif + prio = parameter&0xff; + +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if(task == 0) + { + return E_CREATE_FAIL; + } + if(stk == 0) + { + return E_CREATE_FAIL; + } + if(prio > CFG_LOWEST_PRIO) + { + return E_CREATE_FAIL; + } +#if CFG_STK_CHECKOUT_EN >0 + if(sktSz < 20) + { + return E_CREATE_FAIL; + } +#endif // CFG_STK_CHECKOUT_EN +#endif // CFG_PAR_CHECKOUT_EN + +#if CFG_TASK_SCHEDULE_EN == 0 + if(TCBRunning != 0) + return E_CREATE_FAIL; +#endif + + stkTopPtr = InitTaskContext(task,argv,stk); /* Initialize task context. */ + + ptcb = AssignTCB(); /* Get free TCB to use */ + + if(ptcb == 0) /* Is free TCB equal to Co_NULL? */ + { + return E_CREATE_FAIL; /* Yes,error return */ + } + + ptcb->stkPtr = stkTopPtr; /* Initialize TCB as user set */ + ptcb->prio = prio; +#if CFG_STK_CHECKOUT_EN >0 + ptcb->stack = stk+1 - sktSz; /* Set bottom stack for stack overflow check */ + *(U32*)(ptcb->stack) = MAGIC_WORD; +#endif + +#if CFG_TASK_WAITTING_EN >0 + ptcb->delayTick = INVALID_VALUE; +#endif + +#if CFG_TASK_SCHEDULE_EN == 0 + ptcb->taskFuc = task; + ptcb->taskStk = stk; +#endif + ptcb->TCBnext = 0; /* Initialize TCB link in READY list */ + ptcb->TCBprev = 0; + +#if CFG_ROBIN_EN >0 /* Set task time slice for task robin */ + timeSlice = (parameter&0x7fff0000)>>20; + if(timeSlice == 0) + { + timeSlice = CFG_TIME_SLICE; + } + ptcb->timeSlice = timeSlice; +#endif + +#if CFG_FLAG_EN > 0 + ptcb->pnode = 0; /* Initialize task as no flag waiting */ +#endif + +#if CFG_EVENT_EN > 0 + ptcb->eventID = INVALID_ID; /* Initialize task as no event waiting*/ + ptcb->pmail = 0; + ptcb->waitNext = 0; + ptcb->waitPrev = 0; +#endif + +#if CFG_MUTEX_EN > 0 + /* Initialize task as no mutex holding or waiting */ + ptcb->mutexID = INVALID_ID; +#endif + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + ActiveTaskPri(prio); +#endif + + if((parameter>>31) == 0) /* Is task in waitting state? */ + { /* No,set it into ready list */ + OsSchedLock(); /* Lock schedule */ + InsertToTCBRdyList(ptcb); /* Insert into the READY list */ + OsSchedUnlock(); /* Unlock schedule */ + } + else + { /* Yes,Set task status as TASK_WAITING*/ + ptcb->state = TASK_WAITING; + } + return ptcb->taskID; /* Return task ID */ +} + + +/** + ******************************************************************************* + * @brief Delete Task + * @param[in] taskID Task ID + * @param[out] None + * @retval E_INVALID_ID Invalid task ID. + * @retval E_PROTECTED_TASK Protected task in OS. + * @retval E_OK Delete successful. + * + * @par Description + * @details This function is called to delete assign task. + ******************************************************************************* + */ +StatusType CoDelTask(OS_TID taskID) +{ + P_OSTCB ptcb; + +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if(taskID >= CFG_MAX_USER_TASKS + SYS_TASK_NUM) + { + return E_INVALID_ID; + } +#endif + ptcb = &TCBTbl[taskID]; +#if CFG_PAR_CHECKOUT_EN >0 + if(ptcb->state == TASK_DORMANT) + { + return E_INVALID_ID; + } +#endif + if(taskID == 0) /* Is idle task? */ + { + return E_PROTECTED_TASK; /* Yes,error return */ + } + + if(ptcb->state == TASK_RUNNING) /* Is task running? */ + { + if(OSSchedLock != 0) /* Yes,is OS lock? */ + { + return E_OS_IN_LOCK; /* Yes,error return */ + } + } + +#if CFG_MUTEX_EN >0 /* Do task hold mutex? */ + if(ptcb->mutexID != INVALID_ID) + { + if(MutexTbl[ptcb->mutexID].taskID == ptcb->taskID) + { /* Yes,leave the mutex */ + CoLeaveMutexSection(ptcb->mutexID); + } + } + +#endif + + OsSchedLock(); /* Lock schedule */ + + if(ptcb->state == TASK_READY) /* Is task in READY list? */ + { + RemoveFromTCBRdyList(ptcb); /* Yes,remove task from the READY list*/ + } + +#if CFG_TASK_WAITTING_EN > 0 + else if(ptcb->state == TASK_WAITING)/* Is task in the WAITING list? */ + { + /* Yes,Is task in delay list? */ + if(ptcb->delayTick != INVALID_VALUE) + { + RemoveDelayList(ptcb); /* Yes,remove task from READY list */ + } + +#if CFG_EVENT_EN > 0 + if(ptcb->eventID != INVALID_ID) /* Is task in event waiting list? */ + { + /* Yes,remove task from event waiting list */ + RemoveEventWaittingList(ptcb); + } +#endif + +#if CFG_FLAG_EN > 0 + if(ptcb->pnode != 0) /* Is task in flag waiting list? */ + { + /* Yes,remove task from flag waiting list */ + RemoveLinkNode((P_FLAG_NODE)ptcb->pnode); + } +#endif + +#if CFG_MUTEX_EN >0 + if(ptcb->mutexID != INVALID_ID) /* Is task in mutex waiting list? */ + { + RemoveMutexList(ptcb); /* Yes,remove task from mutex waiting list*/ + } +#endif + } +#endif + ptcb->state = TASK_DORMANT; /* Release TCB */ + TaskSchedReq = Co_TRUE; + +#if CFG_ORDER_LIST_SCHEDULE_EN ==0 + DeleteTaskPri(ptcb->prio); +#endif + +#if CFG_TASK_SCHEDULE_EN >0 + ptcb->TCBnext = FreeTCB; + FreeTCB = ptcb; +#endif + OsSchedUnlock(); /* Unlock schedule */ + return E_OK; /* return OK */ +} + + +/** + ******************************************************************************* + * @brief Exit Task + * @param[in] None + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called to exit current task. + ******************************************************************************* + */ +void CoExitTask(void) +{ + CoDelTask(TCBRunning->taskID); /* Call task delete function */ +} + + +#if CFG_TASK_SCHEDULE_EN ==0 +/** + ******************************************************************************* + * @brief Activate Task + * @param[in] taskID Task ID + * @param[in] argv Task argv + * @param[out] None + * @retval E_INVALID_ID Invalid task ID. + * @retval E_OK Activate task successful. + * + * @par Description + * @details This function is called to activate current task. + ******************************************************************************* + */ +StatusType CoActivateTask(OS_TID taskID,void *argv) +{ + P_OSTCB ptcb; + OS_STK* stkTopPtr; +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if(taskID >= CFG_MAX_USER_TASKS + SYS_TASK_NUM) + { + return E_INVALID_ID; + } +#endif + ptcb = &TCBTbl[taskID]; +#if CFG_PAR_CHECKOUT_EN >0 + if(ptcb->stkPtr == Co_NULL) + return E_INVALID_ID; +#endif + if(ptcb->state != TASK_DORMANT) + return E_OK; + + + /* Initialize task context. */ + stkTopPtr = InitTaskContext(ptcb->taskFuc,argv,ptcb->taskStk); + + ptcb->stkPtr = stkTopPtr; /* Initialize TCB as user set */ + OsSchedLock(); /* Lock schedule */ + InsertToTCBRdyList(ptcb); /* Insert into the READY list */ + OsSchedUnlock(); /* Unlock schedule */ + return E_OK; +} +#endif + + +/** + ******************************************************************************* + * @brief Get current task id + * @param[in] None + * @param[out] None + * @retval ID of the current task. + * + * @par Description + * @details This function is called to get current task id. + ******************************************************************************* + */ +OS_TID CoGetCurTaskID(void) +{ + return (TCBRunning->taskID); /* Return running task ID */ +} + +#if CFG_TASK_SUSPEND_EN >0 +/** + ******************************************************************************* + * @brief Suspend Task + * @param[in] taskID ID of task that want to suspend. + * @param[out] None + * @retval E_OK Task suspend successful. + * @retval E_INVALID_ID Invalid event ID. + * @retval E_PROTECTED_TASK Can't suspend idle task. + * @retval E_ALREADY_IN_WAITING Task now in waiting state. + + * + * @par Description + * @details This function is called to exit current task. + ******************************************************************************* + */ +StatusType CoSuspendTask(OS_TID taskID) +{ + P_OSTCB ptcb; + + if(taskID == 0) /* Is idle task? */ + { + return E_PROTECTED_TASK; /* Yes,error return */ + } +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if(taskID >= CFG_MAX_USER_TASKS + SYS_TASK_NUM) + { + return E_INVALID_ID; + } +#endif + ptcb = &TCBTbl[taskID]; +#if CFG_PAR_CHECKOUT_EN >0 + if(ptcb->state == TASK_DORMANT) + { + return E_INVALID_ID; + } +#endif + if(OSSchedLock != 0) + { + return E_OS_IN_LOCK; + } + if(ptcb->state == TASK_WAITING) /* Is task in WAITING list? */ + { + return E_ALREADY_IN_WAITING; /* Yes,error return */ + } + + OsSchedLock(); + if(ptcb != TCBRunning) /* Is runing task? */ + { + RemoveFromTCBRdyList(ptcb); /* No,Remove task from READY list */ + } + else + { + TaskSchedReq = Co_TRUE; + } + + ptcb->state = TASK_WAITING; /* Set task status as TASK_WAITING */ + OsSchedUnlock(); /* Call task schedule */ + return E_OK; /* Return OK */ +} + + +/** + ******************************************************************************* + * @brief Awake Task + * @param[in] taskID ID of task that will been awaked. + * @param[out] None + * @retval E_OK Task awake successful. + * @retval E_INVALID_ID Invalid task ID. + * @retval E_TASK_NOT_WAITING Task now not in waiting state. + * @retval E_TASK_WAIT_OTHER Task now waiting other awake event. + * @retval E_PROTECTED_TASK Idle task mustn't be awaked. + * + * @par Description + * @details This function is called to awake current task. + ******************************************************************************* + */ +StatusType CoAwakeTask(OS_TID taskID) +{ + P_OSTCB ptcb; + + if(taskID == 0) /* Is idle task? */ + { + return E_PROTECTED_TASK; /* Yes,error return */ + } +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if(taskID >= CFG_MAX_USER_TASKS + SYS_TASK_NUM) + { + return E_INVALID_ID; + } +#endif + ptcb = &TCBTbl[taskID]; +#if CFG_PAR_CHECKOUT_EN >0 + if(ptcb->state == TASK_DORMANT) + { + return E_INVALID_ID; + } +#endif + + if(ptcb->state != TASK_WAITING) /* Is task in WAITING list */ + { + return E_TASK_NOT_WAITING; /* No,error return */ + } + +#if CFG_TASK_WAITTING_EN > 0 + if(ptcb->delayTick != INVALID_VALUE)/* Is task in READY list */ + { + return E_TASK_WAIT_OTHER; /* Yes,error return */ + } + +#if CFG_FLAG_EN > 0 + if(ptcb->pnode != Co_NULL) /* Is task in flag waiting list */ + { + return E_TASK_WAIT_OTHER; /* Yes,error return */ + } +#endif + +#if CFG_EVENT_EN>0 + if(ptcb->eventID != INVALID_ID) /* Is task in event waiting list */ + { + return E_TASK_WAIT_OTHER; /* Yes,error return */ + } +#endif + +#if CFG_MUTEX_EN > 0 + if(ptcb->mutexID != INVALID_ID) /* Is task in mutex waiting list */ + { + return E_TASK_WAIT_OTHER; /* Yes,error return */ + } +#endif + +#endif //CFG_TASK_WAITTING_EN + + /* All no,so WAITING state was set by CoSuspendTask() */ + OsSchedLock(); /* Lock schedule */ + InsertToTCBRdyList(ptcb); /* Insert the task into the READY list*/ + OsSchedUnlock(); /* Unlock schedule */ + return E_OK; /* return OK */ +} +#endif