FreeRTOS的Tickless低功耗源码分析

FreeRTOS的Tickless低功耗源码分析

vTaskDelay

#if ( INCLUDE_vTaskDelay == 1 )

 

void vTaskDelay( const TickType_t xTicksToDelay )  //相对延时函数

{

BaseType_t xAlreadyYielded = pdFALSE;

 

/* A delay time of zero just forces a reschedule. */

if( xTicksToDelay > ( TickType_t ) 0U ) //xTicksToDelay0,则直接任务调度

{

configASSERT( uxSchedulerSuspended == 0 );

vTaskSuspendAll();

{

traceTASK_DELAY();

 

/* A task that is removed from the event list while the

scheduler is suspended will not get placed in the ready

list or removed from the blocked list until the scheduler

is resumed.

 

This task cannot be in an event list as it is the currently

executing task. */

prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE ); //加入延时表

}

xAlreadyYielded = xTaskResumeAll();

}

else

{

mtCOVERAGE_TEST_MARKER();

}

 

/* Force a reschedule if xTaskResumeAll has not already done so, we may

have put ourselves to sleep. */

if( xAlreadyYielded == pdFALSE )

{

portYIELD_WITHIN_API(); //需要进行任务调度

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

 

#endif /* INCLUDE_vTaskDelay */

 

 

 

 

 

prvAddCurrentTaskToDelayedList

static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )

{

TickType_t xTimeToWake;

const TickType_t xConstTickCount = xTickCount; //保存进入时间

 

#if( INCLUDE_xTaskAbortDelay == 1 )

{

/* About to enter a delayed list, so ensure the ucDelayAborted flag is

reset to pdFALSE so it can be detected as having been set to pdTRUE

when the task leaves the Blocked state. */

pxCurrentTCB->ucDelayAborted = pdFALSE;

}

#endif

 

/* Remove the task from the ready list before adding it to the blocked list

as the same list item is used for both lists. */

//从就绪表删除

if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )

{

/* The current task must be in a ready list, so there is no need to

check, and the port reset macro can be called directly. */

//如果当前优先级下再没有其他同优先级任务,清除优先级位 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );

}

else

{

mtCOVERAGE_TEST_MARKER();

}

 

#if ( INCLUDE_vTaskSuspend == 1 )

{

if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )

{

/* Add the task to the suspended task list instead of a delayed task

list to ensure it is not woken by a timing event.  It will block

indefinitely. */

//延时时间是最大延时且允许任务阻塞,则任务挂接到挂起任务状态表 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );

}

else

{

/* Calculate the time at which the task should be woken if the event

does not occur.  This may overflow but this doesn't matter, the

kernel will manage it correctly. */

//若是正常的延时时间,唤醒时间就等于当前时间加上延时时间

xTimeToWake = xConstTickCount + xTicksToWait;

 

/* The list item will be inserted in wake time order. */

//修改列表项当中的时间为唤醒时间listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

// xTimeToWake发生了计数器溢出,挂接到溢出延时状态表

if( xTimeToWake < xConstTickCount )

{

/* Wake time has overflowed.  Place this item in the overflow

list. */

vListInsert( pxOverflowDelayedTaskList,&( pxCurrentTCB->xStateListItem ) );

}

else

{

/* The wake time has not overflowed, so the current block list

is used. */

//xTimeToWake没有发生计数溢出,直接挂入延时状态表 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

 

/* If the task entering the blocked state was placed at the

head of the list of blocked tasks then xNextTaskUnblockTime

needs to be updated too. */

//当前新的延时任务的唤醒时间小于最新任务唤醒时间标记的,更新最新任

//务唤醒时间标记xNextTaskUnblockTime

if( xTimeToWake < xNextTaskUnblockTime )

{

xNextTaskUnblockTime = xTimeToWake;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

}

}

#else /* INCLUDE_vTaskSuspend *///同上

{

/* Calculate the time at which the task should be woken if the event

does not occur.  This may overflow but this doesn't matter, the kernel

will manage it correctly. */

xTimeToWake = xConstTickCount + xTicksToWait;

 

/* The list item will be inserted in wake time order. */

listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

 

if( xTimeToWake < xConstTickCount )

{

/* Wake time has overflowed.  Place this item in the overflow list. */

vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

}

else

{

/* The wake time has not overflowed, so the current block list is used. */

vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

 

/* If the task entering the blocked state was placed at the head of the

list of blocked tasks then xNextTaskUnblockTime needs to be updated

too. */

if( xTimeToWake < xNextTaskUnblockTime )

{

xNextTaskUnblockTime = xTimeToWake;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

 

/* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */

( void ) xCanBlockIndefinitely;

}

#endif /* INCLUDE_vTaskSuspend */

}

 

vTaskDelayUntil

#if ( INCLUDE_vTaskDelayUntil == 1 )

 

void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) //绝对延时函数

{

TickType_t xTimeToWake;

BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;

 

configASSERT( pxPreviousWakeTime );

configASSERT( ( xTimeIncrement > 0U ) );

configASSERT( uxSchedulerSuspended == 0 );

 

vTaskSuspendAll(); //挂起标志置位,xTaskIncrementTick中将执行挂起流程

 

{

/* Minor optimisation.  The tick count cannot change in this

block. */

const TickType_t xConstTickCount = xTickCount;//记录进入时间点

 

/* Generate the tick time at which the task wants to wake. */

xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;//相对上次唤醒的增量时间

 

if( xConstTickCount < *pxPreviousWakeTime )

{

/* The tick count has overflowed since this function was

lasted called.  In this case the only time we should ever

actually delay is if the wake time has alsooverflowed,

and the wake time is greater than the tick time.  When this

is the case it is as if neither time had overflowed. */

if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )

{

xShouldDelay = pdTRUE;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

else

{

/* The tick time has not overflowed.  In this case we will

delay if either the wake time has overflowed, and/or the

tick time is less than the wake time. */

if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )

{

xShouldDelay = pdTRUE;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

 

/* Update the wake time ready for the next call. */

*pxPreviousWakeTime = xTimeToWake; //更新上次唤醒时间

 

if( xShouldDelay != pdFALSE ) //需要延时,计算相对延时

{

traceTASK_DELAY_UNTIL( xTimeToWake );

 

/* prvAddCurrentTaskToDelayedList() needs the block time, not

the time to wake, so subtract the current tick count. */

//加入延时表

prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

xAlreadyYielded = xTaskResumeAll(); //恢复所有任务

 

/* Force a reschedule if xTaskResumeAll has not already done so, we may

have put ourselves to sleep. */

if( xAlreadyYielded == pdFALSE ) //任务调度

{

portYIELD_WITHIN_API();

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

 

#endif /* INCLUDE_vTaskDelayUntil */

 

 

 

 

xTaskIncrementTick

BaseType_t xTaskIncrementTick( void )

{

TCB_t * pxTCB;

TickType_t xItemValue;

BaseType_t xSwitchRequired = pdFALSE;

 

/* Called by the portable layer each time a tick interrupt occurs.

Increments the tick then checks to see if the new tick value will cause any

tasks to be unblocked. */

traceTASK_INCREMENT_TICK( xTickCount );

if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) //判断调度器是否挂起

{

/* Minor optimisation.  The tick count cannot change in this

block. */

const TickType_t xConstTickCount = xTickCount + 1; //时钟节拍加1并保存

 

/* Increment the RTOS tick, switching the delayed and overflowed

delayed lists if it wraps to 0. */

xTickCount = xConstTickCount;

 

if( xConstTickCount == ( TickType_t ) 0U ) //发生了计数溢出,切换延时表和溢出表

{

taskSWITCH_DELAYED_LISTS();

}

else

{

mtCOVERAGE_TEST_MARKER();

}

 

/* See if this tick has made a timeout expire.  Tasks are stored in

thequeue in the order of their wake time - meaning once one task

has been found whose block time has not expired there is no need to

look any further down the list. */

if( xConstTickCount >= xNextTaskUnblockTime )//当前计数值大于解锁时间,进行任务解锁

{

for( ;; )

{

if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )

{

/* The delayed list is empty.  Set xNextTaskUnblockTime

to the maximum possible value so it is extremely

unlikely that the

if( xTickCount >= xNextTaskUnblockTime ) test will pass

next time through. */

xNextTaskUnblockTime = portMAX_DELAY;

//延时表为空,即没有待解锁任务,解锁时间设为最大值

/*lint !e961 MISRA exception as the casts are only redundant for some ports. */

break;

}

else

{

/* The delayed list is not empty, get the value of the

item at the head of the delayed list.  This is the time

at which the task at the head of the delayed list must

be removed from the Blocked state. */

//延时表不为空,获取最近解锁任务列表项值

pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );

xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

 

if( xConstTickCount < xItemValue )

{

/* It is not time to unblock this item yet, but the

item value is the time at which the task at the head

of the blocked list must be removed from the Blocked

state -so record the item value in

xNextTaskUnblockTime. */

//若该列表项值大于当前时间即更新最新任务解锁值,并退出

xNextTaskUnblockTime = xItemValue;

break;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

 

/* It is time to remove the item from the Blocked state. */

//否则,任务解锁时间到,从延时表删除,若存在于事件表,可能为设置的超时时间到,从事件表删除事件,加入就绪表

( void ) uxListRemove( &( pxTCB->xStateListItem ) );

 

/* Is the task waiting on an event also?  If so remove

it from the event list. */

if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )

{

( void ) uxListRemove( &( pxTCB->xEventListItem ) );

}

else

{

mtCOVERAGE_TEST_MARKER();

}

 

/* Place the unblocked task into the appropriate ready

list. */

prvAddTaskToReadyList( pxTCB );

 

/* A task being unblocked cannot cause an immediate

context switch if preemption is turned off. */

#if (  configUSE_PREEMPTION == 1 )

{

/* Preemption is on, but a context switch should

only be performed if the unblocked task has a

priority that is equal to or higher than the

currently executing task. */

//根据优先级情况酌情调度

if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) {

xSwitchRequired = pdTRUE;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

#endif /* configUSE_PREEMPTION */

}

}

}

 

/* Tasks of equal priority to the currently running task will share

processing time (time slice) if preemption is on, and the application

writer has not explicitly turned time slicing off. */

#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 )

{

/* Guard against the tick hook being called when the pended tick

count is being unwound (when the scheduler is being unlocked). */

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;

}

/*-----------------------------------------------------------*/

 

 

xTaskResumeAll

BaseType_t xTaskResumeAll( void )

{

TCB_t *pxTCB = NULL;

BaseType_t xAlreadyYielded = pdFALSE;

 

/* If uxSchedulerSuspended is zero then this function does not match a

previous call to vTaskSuspendAll(). */

configASSERT( uxSchedulerSuspended );

 

/* It is possible that an ISR caused a task to be removed from an event

list while the scheduler was suspended.  If this was the case then the

removed task will have been added to the xPendingReadyList.  Once the

scheduler has been resumed it is safe to move all the pending ready

tasks from this list into their appropriate ready list. */

taskENTER_CRITICAL();

{

--uxSchedulerSuspended; //调度器挂起标记减1

 

if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) //如果调度器挂起被完全释放

{

if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ) //且当前有注册的任务

{

/* Move any readied tasks from the pending list into the

appropriate ready list. */

while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )//挂起表中有任务

{

//找到挂起表,所有列表项从挂起表脱离,并脱离状态表,加入就绪表

pxTCB = ( TCB_t * )listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );

( void ) uxListRemove( &( pxTCB->xEventListItem ) );

( void ) uxListRemove( &( pxTCB->xStateListItem ) );

prvAddTaskToReadyList( pxTCB );

 

/* If the moved task has a priority higher than the current

task then a yield must be performed. */

if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )

{

xYieldPending = pdTRUE;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

//vTaskSuspendAll调用之前,如果有一个任务被单独Suspend,就会导致

//xNextTaskUnblockTime需要被刷新(如果该任务刚好是下一个要被解锁的任//),而如果正好在这个时候调度器将任务调度到了另一个任务中,且该任务//依次调用TaskSuspendAll,xTaskResumeAll,到了这里就需要重置//xNextTaskUnblockTime值,否则可能导致唤醒提前发生[若全局挂起过程很短又没有产生uxPendedTicks计数,且现在只有Idle任务就绪]

if( pxTCB != NULL )

{

/* A task was unblocked while the scheduler was suspended,

which may have prevented the next unblock time from being

re-calculated, in which case re-calculate it now.  Mainly

important for low power tickless implementations, where

this can prevent an unnecessary exit from low power

state. */

prvResetNextTaskUnblockTime();

}

 

/* If any ticks occurred while the scheduler was suspended then

they should be processed now.  This ensures the tick count does

notslip, and that any delayed tasks are resumed at the correct

time. */

{

UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */

 

if( uxPendedCounts > ( UBaseType_t ) 0U )

{

//根据挂起过程中uxPendedCounts的计数,循环触发xTaskIncrementTick //进行系统节拍计数。

do

{

if( xTaskIncrementTick() != pdFALSE ) //有任务解锁进入就绪态

{

xYieldPending = pdTRUE;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

--uxPendedCounts;

} while( uxPendedCounts > ( UBaseType_t ) 0U );

 

uxPendedTicks = 0;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

 

if( xYieldPending != pdFALSE )

{

#if( configUSE_PREEMPTION != 0 )

{

xAlreadyYielded = pdTRUE;

}

#endif

taskYIELD_IF_USING_PREEMPTION();

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

taskEXIT_CRITICAL();

 

return xAlreadyYielded;

}

 

 


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值