/* --------------------- MUTUAL EXCLUSION SEMAPHORES ------------------- */ #define OS_CFG_MUTEX_EN 1u /* Enable (1) or Disable (0) code generation for MUTEX */ #define OS_CFG_MUTEX_DEL_EN 1u /* Include code for OSMutexDel() */ #define OS_CFG_MUTEX_PEND_ABORT_EN 1u /* Include code for OSMutexPendAbort() */
/* --------------------------- MESSAGE QUEUES -------------------------- */ #define OS_CFG_Q_EN 1u /* Enable (1) or Disable (0) code generation for QUEUES */ #define OS_CFG_Q_DEL_EN 1u /* Include code for OSQDel() */ #define OS_CFG_Q_FLUSH_EN 1u /* Include code for OSQFlush() */ #define OS_CFG_Q_PEND_ABORT_EN 1u /* Include code for OSQPendAbort() */
/* ----------------------------- SEMAPHORES ---------------------------- */ #define OS_CFG_SEM_EN 1u /* Enable (1) or Disable (0) code generation for SEMAPHORES */ #define OS_CFG_SEM_DEL_EN 1u /* Include code for OSSemDel() */ #define OS_CFG_SEM_PEND_ABORT_EN 1u /* Include code for OSSemPendAbort() */ #define OS_CFG_SEM_SET_EN 1u /* Include code for OSSemSet() */
/* -------------------------- TASK MANAGEMENT -------------------------- */ #define OS_CFG_STAT_TASK_EN 1u /* Enable (1) or Disable(0) the statistics task */ #define OS_CFG_STAT_TASK_STK_CHK_EN 1u /* Check task stacks from statistic task */
#define OS_CFG_TASK_CHANGE_PRIO_EN 1u /* Include code for OSTaskChangePrio() */ #define OS_CFG_TASK_DEL_EN 1u /* Include code for OSTaskDel() */ #define OS_CFG_TASK_Q_EN 1u /* Include code for OSTaskQXXXX() */ #define OS_CFG_TASK_Q_PEND_ABORT_EN 1u /* Include code for OSTaskQPendAbort() */ #define OS_CFG_TASK_PROFILE_EN 1u /* Include variables in OS_TCB for profiling */ #define OS_CFG_TASK_REG_TBL_SIZE 1u /* Number of task specific registers */ #define OS_CFG_TASK_SEM_PEND_ABORT_EN 1u /* Include code for OSTaskSemPendAbort() */ #define OS_CFG_TASK_SUSPEND_EN 1u /* Include code for OSTaskSuspend() and OSTaskResume() */
/* -------------------------- TIME MANAGEMENT -------------------------- */ #define OS_CFG_TIME_DLY_HMSM_EN 1u /* Include code for OSTimeDlyHMSM() */ #define OS_CFG_TIME_DLY_RESUME_EN 1u /* Include code for OSTimeDlyResume() */
/* ------------------- TASK LOCAL STORAGE MANAGEMENT ------------------- */ #define OS_CFG_TLS_TBL_SIZE 0u /* Include code for Task Local Storage (TLS) registers */
/* ------------------------- TIMER MANAGEMENT -------------------------- */ #define OS_CFG_TMR_EN 1u /* Enable (1) or Disable (0) code generation for TIMERS */ #define OS_CFG_TMR_DEL_EN 1u /* Enable (1) or Disable (0) code generation for OSTmrDel() */
OS_TASK_PTR TaskEntryAddr; /* Pointer to task entry point address */ void *TaskEntryArg; /* Argument passed to task when it was created */
OS_PEND_DATA *PendDataTblPtr; /* Pointer to list containing objects pended on */ OS_STATE PendOn; /* Indicates what task is pending on */ OS_STATUS PendStatus; /* Pend status */
OS_STATE TaskState; /* See OS_TASK_STATE_xxx */ OS_PRIO Prio; /* Task priority (0 == highest) */ CPU_STK_SIZE StkSize; /* Size of task stack (in number of stack elements) */ OS_OPT Opt; /* Task options as passed by OSTaskCreate() */
OS_OBJ_QTY PendDataTblEntries; /* Size of array of objects to pend on */
CPU_TS TS; /* Timestamp */
OS_SEM_CTR SemCtr; /* Task specific semaphore counter */
/* DELAY / TIMEOUT */ OS_TICK TickCtrPrev; /* Previous time when task was ready */ OS_TICK TickCtrMatch; /* Absolute time when task is going to be ready */ OS_TICK TickRemain; /* Number of ticks remaining for a match (updated at ... */ /* ... run-time by OS_StatTask() */ OS_TICK TimeQuanta; OS_TICK TimeQuantaCtr;
#if OS_CFG_TASK_Q_EN > 0u OS_MSG_Q MsgQ; /* Message queue associated with task */ #if OS_CFG_TASK_PROFILE_EN > 0u CPU_TS MsgQPendTime; /* Time it took for signal to be received */ CPU_TS MsgQPendTimeMax; /* Max amount of time it took for signal to be received */ #endif #endif
#if OS_CFG_FLAG_EN > 0u OS_FLAGS FlagsPend; /* Event flag(s) to wait on */ OS_FLAGS FlagsRdy; /* Event flags that made task ready to run */ OS_OPT FlagsOpt; /* Options (See OS_OPT_FLAG_xxx) */ #endif
#if OS_CFG_TASK_PROFILE_EN > 0u OS_CPU_USAGE CPUUsage; /* CPU Usage of task (0.00-100.00%) */ OS_CPU_USAGE CPUUsageMax; /* CPU Usage of task (0.00-100.00%) - Peak */ OS_CTX_SW_CTR CtxSwCtr; /* Number of time the task was switched in */ CPU_TS CyclesDelta; /* value of OS_TS_GET() - .CyclesStart */ CPU_TS CyclesStart; /* Snapshot of cycle counter at start of task resumption */ OS_CYCLES CyclesTotal; /* Total number of # of cycles the task has been running */ OS_CYCLES CyclesTotalPrev; /* Snapshot of previous # of cycles */
CPU_TS SemPendTime; /* Time it took for signal to be received */ CPU_TS SemPendTimeMax; /* Max amount of time it took for signal to be received */ #endif
#if OS_CFG_STAT_TASK_STK_CHK_EN > 0u CPU_STK_SIZE StkUsed; /* Number of stack elements used from the stack */ CPU_STK_SIZE StkFree; /* Number of stack elements free on the stack */ #endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN CPU_TS IntDisTimeMax; /* Maximum interrupt disable time */ #endif #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u CPU_TS SchedLockTimeMax; /* Maximum scheduler lock time */ #endif
while (DEF_ON) { (void)OSTaskSemPend((OS_TICK )0, (OS_OPT )OS_OPT_PEND_BLOCKING, (CPU_TS *)&ts, (OS_ERR *)&err); /* Wait for signal from tick interrupt */ if (err == OS_ERR_NONE) { if (OSRunning == OS_STATE_OS_RUNNING) { OS_TickListUpdate(); /* Update all tasks waiting for time */ } } } }
p_arg = p_arg; /* Not using 'p_arg', prevent compiler warning */ while (DEF_ON) { (void)OSTaskSemPend((OS_TICK )0, /* Wait for signal indicating time to update tmrs */ (OS_OPT )OS_OPT_PEND_BLOCKING, (CPU_TS *)&ts, (OS_ERR *)&err);
OSSchedLock(&err); ts_start = OS_TS_GET(); OSTmrTickCtr++; /* Increment the current time */ spoke = (OS_TMR_SPOKE_IX)(OSTmrTickCtr % OSCfg_TmrWheelSize); p_spoke = &OSCfg_TmrWheel[spoke]; p_tmr = p_spoke->FirstPtr; done = DEF_FALSE; while (done == DEF_FALSE) { if (p_tmr != (OS_TMR *)0) { p_tmr_next = (OS_TMR *)p_tmr->NextPtr; /* Point to next tmr to update because current ... */ /* ... timer could get unlinked from the wheel. */ if (OSTmrTickCtr == p_tmr->Match) { /* Process each timer that expires */ OS_TmrUnlink(p_tmr); /* Remove from current wheel spoke */ if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) { OS_TmrLink(p_tmr, OS_OPT_LINK_PERIODIC); /* Recalculate new position of timer in wheel */ } else { p_tmr->State = OS_TMR_STATE_COMPLETED; /* Indicate that the timer has completed */ } p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available */ if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { (*p_fnct)((void *)p_tmr, p_tmr->CallbackPtrArg); } p_tmr = p_tmr_next; /* See if next timer matches */ } else { done = DEF_TRUE; } } else { done = DEF_TRUE; } } ts_end = OS_TS_GET() - ts_start; /* Measure execution time of timer task */ OSSchedUnlock(&err); if (OSTmrTaskTimeMax < ts_end) { OSTmrTaskTimeMax = ts_end; } } }
CPU_DATA OSPrioTbl[OS_PRIO_TBL_SIZE]; /* Declare the array local to this file to allow for ... */ /* ... optimization. In other words, this allows the ... */ /* ... table to be located in fast memory */
/* ************************************************************************************************************************ * GET HIGHEST PRIORITY TASK WAITING * * Description: This function is called by other uC/OS-III services to determine the highest priority task * waiting on the event. * * Arguments : none * * Returns : The priority of the Highest Priority Task (HPT) waiting for the event * * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. ************************************************************************************************************************ */
prio = (OS_PRIO)0; p_tbl = &OSPrioTbl[0]; while (*p_tbl == (CPU_DATA)0) { /* Search the bitmap table for the highest priority */ prio += DEF_INT_CPU_NBR_BITS; /* Compute the step of each CPU_DATA entry */ p_tbl++; } prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); /* Find the position of the first bit set at the entry */ return (prio); }
structos_rdy_list { OS_TCB *HeadPtr; /* Pointer to task that will run at selected priority */ OS_TCB *TailPtr; /* Pointer to last task at selected priority */ OS_OBJ_QTY NbrEntries; /* Number of entries at selected priority */ };
CPU_INT_DIS(); OSPrioHighRdy = OS_PrioGetHighest(); /* Find the highest priority ready */ OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task is still highest priority task? */ CPU_INT_EN(); /* Yes ... no need to context switch */ return; }
#if OS_CFG_TASK_PROFILE_EN > 0u OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches to this task */ #endif OSTaskCtxSwCtr++; /* Increment context switch counter */
if (OSRunning != OS_STATE_OS_RUNNING) { /* Has the OS started? */ return; /* No */ }
CPU_INT_DIS(); if (OSIntNestingCtr == (OS_NESTING_CTR)0) { /* Prevent OSIntNestingCtr from wrapping */ CPU_INT_EN(); return; } OSIntNestingCtr--; if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ISRs still nested? */ CPU_INT_EN(); /* Yes */ return; }
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Scheduler still locked? */ CPU_INT_EN(); /* Yes */ return; }
OSPrioHighRdy = OS_PrioGetHighest(); /* Find highest priority */ OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* Get highest priority task ready-to-run */ if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task still the highest priority? */ CPU_INT_EN(); /* Yes */ return; }
#if OS_CFG_TASK_PROFILE_EN > 0u OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches for this new task */ #endif OSTaskCtxSwCtr++; /* Keep track of the total number of ctx switches */
;******************************************************************************************************** ; PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw() ; ; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function ; triggers the PendSV exception which is where the real work is done. ;********************************************************************************************************
OSCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR
;******************************************************************************************************** ; PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw() ; ; Note(s) : 1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as ; the result of an interrupt. This function simply triggers a PendSV exception which will ; be handled when there are no more interrupts active and interrupts are enabled. ;********************************************************************************************************
OSIntCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR
if (OSRunning != OS_STATE_OS_RUNNING) { /* Has the OS started? */ return; /* No */ }
CPU_INT_DIS(); if (OSIntNestingCtr == (OS_NESTING_CTR)0) { /* Prevent OSIntNestingCtr from wrapping */ CPU_INT_EN(); return; } OSIntNestingCtr--; if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ISRs still nested? */ CPU_INT_EN(); /* Yes */ return; }
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Scheduler still locked? */ CPU_INT_EN(); /* Yes */ return; }
OSPrioHighRdy = OS_PrioGetHighest(); /* Find highest priority */ OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* Get highest priority task ready-to-run */ if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task still the highest priority? */ CPU_INT_EN(); /* Yes */ return; }
#if OS_CFG_TASK_PROFILE_EN > 0u OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches for this new task */ #endif OSTaskCtxSwCtr++; /* Keep track of the total number of ctx switches */
CPU_CRITICAL_ENTER(); if (OSIntQNbrEntries < OSCfg_IntQSize) { /* Make sure we haven't already filled the ISR queue */ OSIntQNbrEntries++;
if (OSIntQNbrEntriesMax < OSIntQNbrEntries) { OSIntQNbrEntriesMax = OSIntQNbrEntries; }
OSIntQInPtr->Type = type; /* Save object type being posted */ OSIntQInPtr->ObjPtr = p_obj; /* Save pointer to object being posted */ OSIntQInPtr->MsgPtr = p_void; /* Save pointer to message if posting to a message queue */ OSIntQInPtr->MsgSize = msg_size; /* Save the message size if posting to a message queue */ OSIntQInPtr->Flags = flags; /* Save the flags if posting to an event flag group */ OSIntQInPtr->Opt = opt; /* Save post options */ OSIntQInPtr->TS = ts; /* Save time stamp */
OSIntQInPtr = OSIntQInPtr->NextPtr; /* Point to the next interrupt handler queue entry */
OSRdyList[0].NbrEntries = (OS_OBJ_QTY)1; /* Make the interrupt handler task ready to run */ OSRdyList[0].HeadPtr = &OSIntQTaskTCB; OSRdyList[0].TailPtr = &OSIntQTaskTCB; OS_PrioInsert(0u); /* Add task priority 0 in the priority table */ if (OSPrioCur != 0) { /* Chk if OSIntQTask is not running */ OSPrioSaved = OSPrioCur; /* Save current priority */ }
*p_err = OS_ERR_NONE; } else { OSIntQOvfCtr++; /* Count the number of ISR queue overflows */ *p_err = OS_ERR_INT_Q_FULL; } CPU_CRITICAL_EXIT(); }
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TIME_DLY_ISR; return; } #endif
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */ *p_err = OS_ERR_SCHED_LOCKED; return; }
switch (opt) { case OS_OPT_TIME_DLY: // 相对模式 case OS_OPT_TIME_TIMEOUT: // 绝对模式 case OS_OPT_TIME_PERIODIC: // 周期模式 if (dly == (OS_TICK)0u) { /* 0 means no delay! */ *p_err = OS_ERR_TIME_ZERO_DLY; return; } break;
case OS_OPT_TIME_MATCH: break;
default: *p_err = OS_ERR_OPT_INVALID; return; }
OS_CRITICAL_ENTER(); OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY; OS_TickListInsert(OSTCBCurPtr, dly, opt, p_err); if (*p_err != OS_ERR_NONE) { OS_CRITICAL_EXIT_NO_SCHED(); return; } OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */ OS_CRITICAL_EXIT_NO_SCHED(); OSSched(); /* Find next task to run! */ *p_err = OS_ERR_NONE; }
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TIME_DLY_ISR; return; } #endif
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */ *p_err = OS_ERR_SCHED_LOCKED; return; }
opt_time = opt & OS_OPT_TIME_MASK; /* Retrieve time options only. */ switch (opt_time) { case OS_OPT_TIME_DLY: case OS_OPT_TIME_TIMEOUT: case OS_OPT_TIME_PERIODIC: if (milli == (CPU_INT32U)0u) { /* Make sure we didn't specify a 0 delay */ if (seconds == (CPU_INT16U)0u) { if (minutes == (CPU_INT16U)0u) { if (hours == (CPU_INT16U)0u) { *p_err = OS_ERR_TIME_ZERO_DLY; return; } } } } break;
case OS_OPT_TIME_MATCH: break;
default: *p_err = OS_ERR_OPT_INVALID; return; }
#if OS_CFG_ARG_CHK_EN > 0u /* Validate arguments to be within range */ opt_invalid = DEF_BIT_IS_SET_ANY(opt, ~OS_OPT_TIME_OPTS_MASK); if (opt_invalid == DEF_YES) { *p_err = OS_ERR_OPT_INVALID; return; }
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TIME_DLY_RESUME_ISR; return; } #endif
#if OS_CFG_ARG_CHK_EN > 0u if (p_tcb == (OS_TCB *)0) { /* Not possible for the running task to be delayed! */ *p_err = OS_ERR_TASK_NOT_DLY; return; } #endif
CPU_CRITICAL_ENTER(); if (p_tcb == OSTCBCurPtr) { /* Not possible for the running task to be delayed! */ *p_err = OS_ERR_TASK_NOT_DLY; CPU_CRITICAL_EXIT(); return; }
switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: /* Cannot Abort delay if task is ready */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break;
case OS_TASK_STATE_DLY: OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); p_tcb->TaskState = OS_TASK_STATE_RDY; OS_TickListRemove(p_tcb); /* Remove task from tick list */ OS_RdyListInsert(p_tcb); /* Add to ready list */ OS_CRITICAL_EXIT_NO_SCHED(); *p_err = OS_ERR_NONE; break;
case OS_TASK_STATE_PEND: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break;
case OS_TASK_STATE_PEND_TIMEOUT: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break;
case OS_TASK_STATE_SUSPENDED: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break;
case OS_TASK_STATE_DLY_SUSPENDED: OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; OS_TickListRemove(p_tcb); /* Remove task from tick list */ OS_CRITICAL_EXIT_NO_SCHED(); *p_err = OS_ERR_TASK_SUSPENDED; break;
case OS_TASK_STATE_PEND_SUSPENDED: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break;
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break;
structos_tick_spoke { OS_TCB *FirstPtr; /* Pointer to list of tasks in tick spoke */ OS_OBJ_QTY NbrEntries; /* Current number of entries in the tick spoke */ OS_OBJ_QTY NbrEntriesMax; /* Peak number of entries in the tick spoke */ };
CPU_CRITICAL_ENTER(); if (OSIntQNbrEntries < OSCfg_IntQSize) { /* Make sure we haven't already filled the ISR queue */ OSIntQNbrEntries++;
if (OSIntQNbrEntriesMax < OSIntQNbrEntries) { OSIntQNbrEntriesMax = OSIntQNbrEntries; }
OSIntQInPtr->Type = type; /* Save object type being posted */ OSIntQInPtr->ObjPtr = p_obj; /* Save pointer to object being posted */ OSIntQInPtr->MsgPtr = p_void; /* Save pointer to message if posting to a message queue */ OSIntQInPtr->MsgSize = msg_size; /* Save the message size if posting to a message queue */ OSIntQInPtr->Flags = flags; /* Save the flags if posting to an event flag group */ OSIntQInPtr->Opt = opt; /* Save post options */ OSIntQInPtr->TS = ts; /* Save time stamp */
OSIntQInPtr = OSIntQInPtr->NextPtr; /* Point to the next interrupt handler queue entry */
OSRdyList[0].NbrEntries = (OS_OBJ_QTY)1; /* Make the interrupt handler task ready to run */ OSRdyList[0].HeadPtr = &OSIntQTaskTCB; OSRdyList[0].TailPtr = &OSIntQTaskTCB; OS_PrioInsert(0u); /* Add task priority 0 in the priority table */ if (OSPrioCur != 0) { /* Chk if OSIntQTask is not running */ OSPrioSaved = OSPrioCur; /* Save current priority */ }
*p_err = OS_ERR_NONE; } else { OSIntQOvfCtr++; /* Count the number of ISR queue overflows */ *p_err = OS_ERR_INT_Q_FULL; } CPU_CRITICAL_EXIT(); }
/*$PAGE*/ /* ************************************************************************************************************************ * POST TO ISR QUEUE * * Description: This function places contents of posts into an intermediate queue to help defer processing of interrupts * at the task level. * * Arguments : type is the type of kernel object the post is destined to: * * OS_OBJ_TYPE_SEM * OS_OBJ_TYPE_Q * OS_OBJ_TYPE_FLAG * OS_OBJ_TYPE_TASK_MSG * OS_OBJ_TYPE_TASK_SIGNAL * * p_obj is a pointer to the kernel object to post to. This can be a pointer to a semaphore, * ----- a message queue or a task control clock. * * p_void is a pointer to a message that is being posted. This is used when posting to a message * queue or directly to a task. * * msg_size is the size of the message being posted * * flags if the post is done to an event flag group then this corresponds to the flags being * posted * * ts is a timestamp as to when the post was done * * opt this corresponds to post options and applies to: * * OSFlagPost() * OSSemPost() * OSQPost() * OSTaskQPost() * * p_err is a pointer to a variable that will contain an error code returned by this function. * * OS_ERR_NONE if the post to the ISR queue was successful * OS_ERR_INT_Q_FULL if the ISR queue is full and cannot accepts any further posts. This * generally indicates that you are receiving interrupts faster than you * can process them or, that you didn't make the ISR queue large enough. * * Returns : none * * Note(s) : none ************************************************************************************************************************ */
再下面是interrupt queue结构的定义:
1 2 3 4 5 6 7 8 9 10
structos_int_q { OS_OBJ_TYPE Type; /* Type of object placed in the circular list */ OS_INT_Q *NextPtr; /* Pointer to next OS_INT_Q in circular list */ void *ObjPtr; /* Pointer to object placed in the queue */ void *MsgPtr; /* Pointer to message if posting to a message queue */ OS_MSG_SIZE MsgSize; /* Message Size if posting to a message queue */ OS_FLAGS Flags; /* Value of flags if posting to an event flag group */ OS_OPT Opt; /* Post Options */ CPU_TS TS; /* Timestamp */ };
while (DEF_ON) { (void)OSTaskSemPend((OS_TICK )0, (OS_OPT )OS_OPT_PEND_BLOCKING, (CPU_TS *)&ts, (OS_ERR *)&err); /* Wait for signal from tick interrupt */ if (err == OS_ERR_NONE) { if (OSRunning == OS_STATE_OS_RUNNING) { OS_TickListUpdate(); /* Update all tasks waiting for time */ } } } }
OS_CRITICAL_ENTER(); ts_start = OS_TS_GET(); OSTickCtr++; /* Keep track of the number of ticks */ spoke = (OS_TICK_SPOKE_IX)(OSTickCtr % OSCfg_TickWheelSize); p_spoke = &OSCfg_TickWheel[spoke]; p_tcb = p_spoke->FirstPtr; done = DEF_FALSE; while (done == DEF_FALSE) { if (p_tcb != (OS_TCB *)0) { p_tcb_next = p_tcb->TickNextPtr; /* Point to next TCB to update */ switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: case OS_TASK_STATE_PEND: case OS_TASK_STATE_SUSPENDED: case OS_TASK_STATE_PEND_SUSPENDED: break;
case OS_TASK_STATE_DLY: p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */ - OSTickCtr; if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */ p_tcb->TaskState = OS_TASK_STATE_RDY; OS_TaskRdy(p_tcb); /* Make task ready to run */ } else { done = DEF_TRUE; /* Don't find a match, we're done! */ } break;
case OS_TASK_STATE_PEND_TIMEOUT: p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */ - OSTickCtr; if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */ #if (OS_MSG_EN > 0u) p_tcb->MsgPtr = (void *)0; p_tcb->MsgSize = (OS_MSG_SIZE)0u; #endif p_tcb->TS = OS_TS_GET(); OS_PendListRemove(p_tcb); /* Remove from wait list */ OS_TaskRdy(p_tcb); p_tcb->TaskState = OS_TASK_STATE_RDY; p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT; /* Indicate pend timed out */ p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ } else { done = DEF_TRUE; /* Don't find a match, we're done! */ } break;
case OS_TASK_STATE_DLY_SUSPENDED: p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */ - OSTickCtr; if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */ p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; OS_TickListRemove(p_tcb); /* Remove from current wheel spoke */ } else { done = DEF_TRUE; /* Don't find a match, we're done! */ } break;
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */ - OSTickCtr; if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */ #if (OS_MSG_EN > 0u) p_tcb->MsgPtr = (void *)0; p_tcb->MsgSize = (OS_MSG_SIZE)0u; #endif p_tcb->TS = OS_TS_GET(); OS_PendListRemove(p_tcb); /* Remove from wait list */ OS_TickListRemove(p_tcb); /* Remove from current wheel spoke */ p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT; /* Indicate pend timed out */ p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ } else { done = DEF_TRUE; /* Don't find a match, we're done! */ } break;
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to be called from an ISR */ *p_err = OS_ERR_CREATE_ISR; return; } #endif
// 开始进入临界区,关中断or关调度器 OS_CRITICAL_ENTER(); // 下面是给信号量数据结构进行赋值 p_sem->Type = OS_OBJ_TYPE_SEM; /* Mark the data structure as a semaphore */ p_sem->Ctr = cnt; /* Set semaphore value */ p_sem->TS = (CPU_TS)0; p_sem->NamePtr = p_name; /* Save the name of the semaphore */ // 初始化一个信号量的pend list,当有任务pend这个信号量而其ctr=0时,会被加入到这个队列进行挂起等待 OS_PendListInit(&p_sem->PendList); /* Initialize the waiting list */
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_PEND_ISR; return ((OS_SEM_CTR)0); } #endif
#if OS_CFG_OBJ_TYPE_CHK_EN > 0u if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */ *p_err = OS_ERR_OBJ_TYPE; return ((OS_SEM_CTR)0); } #endif
if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS)0; /* Initialize the returned timestamp */ } // 从进入临界区开始分析 CPU_CRITICAL_ENTER(); if (p_sem->Ctr > (OS_SEM_CTR)0) { /* Resource available? */ // 当信号量的ctr>0时,可获取 p_sem->Ctr--; /* Yes, caller may proceed */ if (p_ts != (CPU_TS *)0) { *p_ts = p_sem->TS; /* get timestamp of last post */ } ctr = p_sem->Ctr; CPU_CRITICAL_EXIT(); *p_err = OS_ERR_NONE; // 返回了信号量剩余的值 return (ctr); } // 下面sem->ctr=0的情况 // 信号量不可用是否阻塞? if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */ ctr = p_sem->Ctr; /* No */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_PEND_WOULD_BLOCK; return (ctr); } else { /* Yes */ if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't pend when the scheduler is locked */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_SCHED_LOCKED; return ((OS_SEM_CTR)0); } } // 准备阻塞任务了 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */ OS_Pend(&pend_data, /* Block task pending on Semaphore */ (OS_PEND_OBJ *)((void *)p_sem), OS_TASK_PEND_ON_SEM, timeout);
OS_CRITICAL_EXIT_NO_SCHED();
OSSched(); /* Find the next highest priority task ready to run */
CPU_CRITICAL_ENTER(); switch (OSTCBCurPtr->PendStatus) { case OS_STATUS_PEND_OK: /* We got the semaphore */ if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_NONE; break;
case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */ if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_PEND_ABORT; break;
case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get semaphore within timeout */ if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS )0; } *p_err = OS_ERR_TIMEOUT; break;
case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */ if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_OBJ_DEL; break;
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to be called from an ISR */ *p_err = OS_ERR_CREATE_ISR; return; } #endif
OS_CRITICAL_ENTER(); p_mutex->Type = OS_OBJ_TYPE_MUTEX; /* Mark the data structure as a mutex */ p_mutex->NamePtr = p_name; p_mutex->OwnerTCBPtr = (OS_TCB *)0; p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0; /* Mutex is available */ p_mutex->TS = (CPU_TS )0; p_mutex->OwnerOriginalPrio = OS_CFG_PRIO_MAX; OS_PendListInit(&p_mutex->PendList); /* Initialize the waiting list */
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_PEND_ISR; return; } #endif
if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) { /* See if current task is already the owner of the mutex */ p_mutex->OwnerNestingCtr++; if (p_ts != (CPU_TS *)0) { *p_ts = p_mutex->TS; } CPU_CRITICAL_EXIT(); *p_err = OS_ERR_MUTEX_OWNER; /* Indicate that current task already owns the mutex */ return; }
if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */ return; } else { if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't pend when the scheduler is locked */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_SCHED_LOCKED; return; } }
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */ p_tcb = p_mutex->OwnerTCBPtr; /* Point to the TCB of the Mutex owner */ if (p_tcb->Prio > OSTCBCurPtr->Prio) { /* See if mutex owner has a lower priority than current */ switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: OS_RdyListRemove(p_tcb); /* Remove from ready list at current priority */ p_tcb->Prio = OSTCBCurPtr->Prio; /* Raise owner's priority */ OS_PrioInsert(p_tcb->Prio); OS_RdyListInsertHead(p_tcb); /* Insert in ready list at new priority */ break;
case OS_TASK_STATE_DLY: case OS_TASK_STATE_DLY_SUSPENDED: case OS_TASK_STATE_SUSPENDED: p_tcb->Prio = OSTCBCurPtr->Prio; /* Only need to raise the owner's priority */ break;
case OS_TASK_STATE_PEND: /* Change the position of the task in the wait list */ case OS_TASK_STATE_PEND_TIMEOUT: case OS_TASK_STATE_PEND_SUSPENDED: case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: OS_PendListChangePrio(p_tcb, OSTCBCurPtr->Prio); break;
OSSched(); /* Find the next highest priority task ready to run */
CPU_CRITICAL_ENTER(); switch (OSTCBCurPtr->PendStatus) { case OS_STATUS_PEND_OK: /* We got the mutex */ if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_NONE; break;
case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */ if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_PEND_ABORT; break;
case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get mutex within timeout */ if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS )0; } *p_err = OS_ERR_TIMEOUT; break;
case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */ if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_OBJ_DEL; break;
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_POST_ISR; return; } #endif
#if OS_CFG_OBJ_TYPE_CHK_EN > 0u if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { /* Make sure mutex was created */ *p_err = OS_ERR_OBJ_TYPE; return; } #endif
CPU_CRITICAL_ENTER(); if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) { /* Make sure the mutex owner is releasing the mutex */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_MUTEX_NOT_OWNER; return; }
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); ts = OS_TS_GET(); /* Get timestamp */ p_mutex->TS = ts; p_mutex->OwnerNestingCtr--; /* Decrement owner's nesting counter */ if (p_mutex->OwnerNestingCtr > (OS_NESTING_CTR)0) { /* Are we done with all nestings? */ OS_CRITICAL_EXIT(); /* No */ *p_err = OS_ERR_MUTEX_NESTING; return; }
p_pend_list = &p_mutex->PendList; if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { /* Any task waiting on mutex? */ p_mutex->OwnerTCBPtr = (OS_TCB *)0; /* No */ p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0; OS_CRITICAL_EXIT(); *p_err = OS_ERR_NONE; return; } /* Yes */ if (OSTCBCurPtr->Prio != p_mutex->OwnerOriginalPrio) { OS_RdyListRemove(OSTCBCurPtr); OSTCBCurPtr->Prio = p_mutex->OwnerOriginalPrio; /* Lower owner's priority back to its original one */ OS_PrioInsert(OSTCBCurPtr->Prio); OS_RdyListInsertTail(OSTCBCurPtr); /* Insert owner in ready list at new priority */ OSPrioCur = OSTCBCurPtr->Prio; } /* Get TCB from head of pend list */ p_tcb = p_pend_list->HeadPtr->TCBPtr; p_mutex->OwnerTCBPtr = p_tcb; /* Give mutex to new owner */ p_mutex->OwnerOriginalPrio = p_tcb->Prio; p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)1; /* Post to mutex */ OS_Post((OS_PEND_OBJ *)((void *)p_mutex), (OS_TCB *)p_tcb, (void *)0, (OS_MSG_SIZE )0, (CPU_TS )ts);
OS_CRITICAL_EXIT_NO_SCHED();
if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) { OSSched(); /* Run the scheduler */ }
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to delete a mutex from an ISR */ *p_err = OS_ERR_DEL_ISR; return ((OS_OBJ_QTY)0); } #endif
#if OS_CFG_OBJ_TYPE_CHK_EN > 0u if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { /* Make sure mutex was created */ *p_err = OS_ERR_OBJ_TYPE; return ((OS_OBJ_QTY)0); } #endif
OS_CRITICAL_ENTER(); p_pend_list = &p_mutex->PendList; cnt = p_pend_list->NbrEntries; nbr_tasks = cnt; switch (opt) { case OS_OPT_DEL_NO_PEND: /* Delete mutex only if no task waiting */ if (nbr_tasks == (OS_OBJ_QTY)0) { #if OS_CFG_DBG_EN > 0u OS_MutexDbgListRemove(p_mutex); #endif OSMutexQty--; OS_MutexClr(p_mutex); OS_CRITICAL_EXIT(); *p_err = OS_ERR_NONE; } else { OS_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_WAITING; } break;
case OS_OPT_DEL_ALWAYS: /* Always delete the mutex */ p_tcb_owner = p_mutex->OwnerTCBPtr; /* Did we had to change the prio of owner? */ if ((p_tcb_owner != (OS_TCB *)0) && (p_tcb_owner->Prio != p_mutex->OwnerOriginalPrio)) { switch (p_tcb_owner->TaskState) { /* yes */ case OS_TASK_STATE_RDY: OS_RdyListRemove(p_tcb_owner); p_tcb_owner->Prio = p_mutex->OwnerOriginalPrio; /* Lower owner's prio back */ OS_PrioInsert(p_tcb_owner->Prio); OS_RdyListInsertTail(p_tcb_owner); /* Insert owner in ready list at new prio */ break;
case OS_TASK_STATE_DLY: case OS_TASK_STATE_SUSPENDED: case OS_TASK_STATE_DLY_SUSPENDED: p_tcb_owner->Prio = p_mutex->OwnerOriginalPrio; /* Not in any pend list, change the prio */ break;
case OS_TASK_STATE_PEND: case OS_TASK_STATE_PEND_TIMEOUT: case OS_TASK_STATE_PEND_SUSPENDED: case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: OS_PendListChangePrio(p_tcb_owner, /* Owner is pending on another object */ p_mutex->OwnerOriginalPrio); break;
#if OS_CFG_OBJ_TYPE_CHK_EN > 0u if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { /* Make sure mutex was created */ *p_err = OS_ERR_OBJ_TYPE; return ((OS_OBJ_QTY)0u); } #endif
CPU_CRITICAL_ENTER(); p_pend_list = &p_mutex->PendList; if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0u) { /* Any task waiting on mutex? */ CPU_CRITICAL_EXIT(); /* No */ *p_err = OS_ERR_PEND_ABORT_NONE; return ((OS_OBJ_QTY)0u); }
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); nbr_tasks = 0u; ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ while (p_pend_list->NbrEntries > (OS_OBJ_QTY)0u) { p_tcb = p_pend_list->HeadPtr->TCBPtr; OS_PendAbort((OS_PEND_OBJ *)((void *)p_mutex), p_tcb, ts); nbr_tasks++; if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */ break; /* No */ } } OS_CRITICAL_EXIT_NO_SCHED();
if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0u) { OSSched(); /* Run the scheduler */ }