/** ******************************************************************************* * @brief Start multitask * @param[in] None * @param[out] None * @retval None * * @par Description * @details This function is called to start multitask.After it is called, * OS start schedule task by priority or/and time slice. * @note This function must be called to start OS when you use CoOS,and must * call after CoOsInit(). ******************************************************************************* */ void CoStartOS(void) { TCBRunning = &TCBTbl[0]; /* Get running task */ TCBNext = TCBRunning; /* Set next scheduled task as running task */ TCBRunning->state = TASK_RUNNING; /* Set running task status to RUNNING */ RemoveFromTCBRdyList(TCBRunning); /* Remove running task from READY list */ OsSchedUnlock(); /* Enable Schedule,call task schedule */ }
/** ******************************************************************************* * @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 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; }
/** ******************************************************************************* * @brief Enter a critical area * @param[in] mutexID Specify mutex. * @param[out] None * @retval E_INVALID_ID Invalid mutex id. * @retval E_CALL Error call in ISR. * @retval E_OK Enter critical area successful. * * @par Description * @details This function is called when entering a critical area. * @note ******************************************************************************* */ StatusType CoEnterMutexSection(OS_MutexID mutexID) { P_OSTCB ptcb,pCurTcb; P_MUTEX pMutex; #if CFG_EVENT_EN >0 P_ECB pecb; #endif if(OSIntNesting > 0) /* If the caller is ISR */ { return E_CALL; } if(OSSchedLock != 0) /* Is OS lock? */ { return E_OS_IN_LOCK; /* Yes,error return */ } #if CFG_PAR_CHECKOUT_EN >0 if(mutexID >= MutexFreeID) /* Invalid 'mutexID' */ { return E_INVALID_ID; } #endif OsSchedLock(); pCurTcb = TCBRunning; pMutex = &MutexTbl[mutexID]; pCurTcb->mutexID = mutexID; if(pMutex->mutexFlag == MUTEX_FREE) /* If mutex is available */ { pMutex->originalPrio = pCurTcb->prio; /* Save priority of owning task */ pMutex->taskID = pCurTcb->taskID; /* Acquire the resource */ pMutex->hipriTaskID = pCurTcb->taskID; pMutex->mutexFlag = MUTEX_OCCUPY; /* Occupy the mutex resource*/ } /* If the mutex resource had been occupied */ else if(pMutex->mutexFlag == MUTEX_OCCUPY) { ptcb = &TCBTbl[pMutex->taskID]; if(ptcb->prio > pCurTcb->prio) /* Need to promote priority of owner? */ { #if CFG_ORDER_LIST_SCHEDULE_EN ==0 DeleteTaskPri(ptcb->prio); ActiveTaskPri(pCurTcb->prio); #endif ptcb->prio = pCurTcb->prio; /* Promote prio of owner */ /* Upgarde the highest priority about the mutex */ pMutex->hipriTaskID = pCurTcb->taskID; if(ptcb->state == TASK_READY) /* If the task is ready to run */ { RemoveFromTCBRdyList(ptcb); /* Remove the task from READY list*/ InsertToTCBRdyList(ptcb); /* Insert the task into READY list*/ } #if CFG_EVENT_EN >0 /* If the task is waiting on a event */ else if(ptcb->eventID != INVALID_ID) { pecb = &EventTbl[ptcb->eventID]; /* If the event waiting type is preemptive Priority */ if(pecb->eventSortType == EVENT_SORT_TYPE_PRIO) { /* Remove the task from event waiting list */ RemoveEventWaittingList(ptcb); /* Insert the task into event waiting list */ EventTaskToWait(pecb,ptcb); } } #endif } pCurTcb->state = TASK_WAITING; /* Block current task */ TaskSchedReq = Co_TRUE; pCurTcb->TCBnext = Co_NULL; pCurTcb->TCBprev = Co_NULL; ptcb = pMutex->waittingList; if(ptcb == Co_NULL) /* If the event waiting list is empty */ { pMutex->waittingList = pCurTcb; /* Insert the task to head */ } else /* If the event waiting list is not empty */ { while(ptcb->TCBnext != Co_NULL) /* Insert the task to tail */ { ptcb = ptcb->TCBnext; } ptcb->TCBnext = pCurTcb; pCurTcb->TCBprev = ptcb; pCurTcb->TCBnext = Co_NULL; } } OsSchedUnlock(); return E_OK; }