/** ******************************************************************************* * @file task.c * @version V1.12 * @date 2010.03.01 * @brief task management implementation code of CooCox CoOS kernel. ******************************************************************************* * @copy * * INTERNAL FILE,DON'T PUBLIC. * *

© COPYRIGHT 2009 CooCox

******************************************************************************* */ /*---------------------------- Include ---------------------------------------*/ #include /*---------------------------- 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 = NULL; /*!< pointer to free TCB */ P_OSTCB TCBRdy = NULL; /*!< Pointer to the READY list. */ P_OSTCB TCBNext = NULL; /*!< Poniter to task that next scheduled by OS */ P_OSTCB TCBRunning = NULL; /*!< 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 = NULL; 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 TRUE Assign priority in priority queue. * 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 TRUE; } else if (pri < ActivePri[num]) { seqNum = num; num = tmpNum; } else { num++; } } *SequenceNum = num; return 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<=num*8; cnt--) { if( (tmp&(1<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. ******************************************************************************* */ static 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 != NULL) /* No,TCBRunning == 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) == 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 = TRUE; if(ptcb == 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 != NULL) { ptcbNext->TCBprev = tcbInsert; } #else ptcb = TCBRdy; if (ptcb == NULL) /* Is ready list NULL? */ { TaskSchedReq = 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 = 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 != 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 != 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 = FALSE; prio = ptcb->prio; GetPriSeqNum(prio,&seqNum); #endif /* Is there only one item in READY list? */ if((ptcb->TCBnext == NULL) && (ptcb->TCBprev == NULL) ) { TCBRdy = NULL; /* Yes,set READY list as NULL */ #if CFG_ORDER_LIST_SCHEDULE_EN ==0 isChange = TRUE; #endif } else if(ptcb->TCBprev == NULL) /* 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 = NULL; TCBRdy->TCBprev = NULL; #if CFG_ORDER_LIST_SCHEDULE_EN ==0 if(TCBRdy->prio != prio) isChange = TRUE; #endif } else if( ptcb->TCBnext == NULL) /* 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 = TRUE; else RdyTaskPri[seqNum] = ptcb->TCBprev->taskID; #endif ptcb->TCBprev->TCBnext = NULL; ptcb->TCBprev = NULL; } else /* No, remove task from list */ { #if CFG_ORDER_LIST_SCHEDULE_EN ==0 if((ptcb->TCBprev->prio != prio) && (ptcb->TCBnext->prio != prio)) isChange = 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 = NULL; ptcb->TCBprev = NULL; } #if CFG_ORDER_LIST_SCHEDULE_EN ==0 if(isChange == 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 = 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 != 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==NULL) || (pCurTcb != TCBNext) || (OSSchedLock >1) || (OSIntNesting >0)) { return; } TaskSchedReq = 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 == NULL) /* Is there no free TCB */ { OsSchedUnlock(); /* Yes,unlock schedule */ return NULL; /* 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 == NULL) { return E_CREATE_FAIL; } if(stk == NULL) { 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 != NULL) return E_CREATE_FAIL; #endif stkTopPtr = InitTaskContext(task,argv,stk); /* Initialize task context. */ ptcb = AssignTCB(); /* Get free TCB to use */ if(ptcb == NULL) /* Is free TCB equal to 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 = NULL; /* Initialize TCB link in READY list */ ptcb->TCBprev = NULL; #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 = NULL; /* Initialize task as no flag waiting */ #endif #if CFG_EVENT_EN > 0 ptcb->eventID = INVALID_ID; /* Initialize task as no event waiting*/ ptcb->pmail = NULL; ptcb->waitNext = NULL; ptcb->waitPrev = NULL; #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 != NULL) /* Is task in flag waiting list? */ { /* Yes,remove task from flag waiting list */ RemoveLinkNode(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 = 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 == 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 = 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 != 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