时间管理
延时函数 vTaskDelay
表示延时多少个系统节拍
- 挂起任务调度器
- 将延时任务添加到延时列表中 prvAddCurrentTaskToDelayedList
- 恢复任务调度器
- 任务切换
将延时任务添加到延时列表中
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
{
TickType_t xTimeToWake;
//获取当前时钟节拍值
const TickType_t xConstTickCount = xTickCount;
//将当前任务列表项从就绪列表中移除
if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
/* 当前任务必须在就绪列表中,因此无需检查,可以直接调用端口重置宏 */
portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
#if ( INCLUDE_vTaskSuspend == 1 )
{
//判断
if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
{
/* 如果等待时间为最大值,且可以被阻塞;挂起任务,将任务挂载到挂起列表末端 */
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
//计算唤醒时间
xTimeToWake = xConstTickCount + xTicksToWait;
//将任务状态列表项的值设为唤醒时间
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
//判断是否溢出
if( xTimeToWake < xConstTickCount )
{
//xTimeToWake溢出,将任务移到溢出列表(pxOverflowDelayedTaskList)中
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
//没有溢出,移到延时列表(pxDelayedTaskList)中
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
//更新xNextTaskUnblockTime(取消延时,唤醒任务的最近时刻)
if( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
}
OS系统时钟节拍
BaseType_t xTaskIncrementTick( void )
{
TCB_t * pxTCB;
TickType_t xItemValue;
BaseType_t xSwitchRequired = pdFALSE;
/* 每个时钟节拍中断调用一次本函数,增加时钟节拍计数器xTickCount的值,并检查是否有任务需要取消阻塞 */
traceTASK_INCREMENT_TICK( xTickCount );
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
/* 增加系统时钟节拍计数器 */
const TickType_t xConstTickCount = xTickCount + 1;
xTickCount = xConstTickCount;
//如果溢出则交换延时列表指针和溢出列表指针
if( xConstTickCount == ( TickType_t ) 0U )
{
taskSWITCH_DELAYED_LISTS();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 查看是否有任务延时时间到了 */
if( xConstTickCount >= xNextTaskUnblockTime )
{
for( ;; )
{
if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
{
/* 延时列表为空,设置xNextTaskUnblockTime为最大值 */
xNextTaskUnblockTime = portMAX_DELAY;
break;
}
else
{
/* 延时列表不为空 */
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
/* 判断任务延时是否到了 */
if( xConstTickCount < xItemValue )
{
/* 没到,更新xNextTaskUnblockTime */
xNextTaskUnblockTime = xItemValue;
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 到了,需要唤醒任务 */
/* 将任务从延时列表中移出 */
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
/* 判断任务是否在等待其他事件,比如信号量等;如果有则移出相应列表 */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 将任务加入到就绪列表 */
prvAddTaskToReadyList( pxTCB );
/* 抢占式调度? */
#if ( configUSE_PREEMPTION == 1 )
{
/* 抢占式调度器的话,判断解除阻塞状态的任务优先级和当前任务的优先级;解除的任务优先级更高的话进行一次任务切换 */
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_PREEMPTION */
}
}
}
/* 使能了时间片的话还需要处理同优先级下的任务之间的调度 */
#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
{
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
//使能了时间钩子?
#if ( configUSE_TICK_HOOK == 1 )
{
if( uxPendedTicks == ( UBaseType_t ) 0U )
{
vApplicationTickHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_TICK_HOOK */
}
else
{
++uxPendedTicks;
/* The tick hook gets called at regular intervals, even if the
scheduler is locked. */
#if ( configUSE_TICK_HOOK == 1 )
{
vApplicationTickHook();
}
#endif
}
#if ( configUSE_PREEMPTION == 1 )
{
if( xYieldPending != pdFALSE )
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_PREEMPTION */
return xSwitchRequired;
}