4.2.20 空闲任务调用1--prvCheckTasksWaitingTermination
删除所有终止的任务, 释放资源。简单描述就是清空xTasksWaitingTermination列表,释放资源,递减uxCurrentNumberOfTasks和uxDeletedTasksWaitingCleanUp。
接口:
static void prvCheckTasksWaitingTermination( void )
接口代码如下:
- 1 static void prvCheckTasksWaitingTermination( void )
- 2 {
- 3 /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/
- 4
- 5 #if ( INCLUDE_vTaskDelete == 1 )
- 6 {
- 7 TCB_t * pxTCB;
- 8
- 9 /* uxDeletedTasksWaitingCleanUp is used to prevent taskENTER_CRITICAL()
- 10 * being called too often in the idle task. */
- 11 while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
- 12 {
- 13 #if ( configNUMBER_OF_CORES == 1 )
- 14 {
- 15 taskENTER_CRITICAL();
- 16 {
- 17 {
- 18 /* 从终止列表中取出任务 */
- 19 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
- 20 /* 将任务从终止列表中移出 */
- 21 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
- 22 --uxCurrentNumberOfTasks;
- 23 --uxDeletedTasksWaitingCleanUp;
- 24 }
- 25 }
- 26 taskEXIT_CRITICAL();
- 27
- 28 prvDeleteTCB( pxTCB ); // 释放任务资源
- 29 }
- 30 #endif /* #if( configNUMBER_OF_CORES == 1 ) */
- 31 }
- 32 }
- 33 #endif /* INCLUDE_vTaskDelete */
- 34 }
复制代码 prvCheckTasksWaitingTermination4.2.21 空闲任务调用2--prvGetExpectedIdleTime
这个用于低功耗,主要作用是获取期望睡眠的tick时间。
接口:
static TickType_t prvGetExpectedIdleTime( void )
返回:实际返回的是最近唤醒任务的剩余tick数,即最多能够睡眠这么多tick数后就要苏醒了,因为有任务延迟结束需要唤醒了。
接口代码如下:
- 1 static TickType_t prvGetExpectedIdleTime( void )
- 2 {
- 3 TickType_t xReturn;
- 4 UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;
- 5
- 6 /* uxHigherPriorityReadyTasks takes care of the case where
- 7 * configUSE_PREEMPTION is 0, so there may be tasks above the idle priority
- 8 * task that are in the Ready state, even though the idle task is
- 9 * running. */
- 10 /* uxHigherPriorityReadyTasks用于configUSE_PREEMPTION为0的情况, 因为有可能
- 11 * 存在空闲任务在运行时, 也有高于空闲任务优先级的任务处于就绪态。如果是抢占
- 12 * 式的调度的话, 则不可能会有更高优先级的任务就绪, 否则根本轮不到空闲任务
- 13 * 运行。 */
- 14 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
- 15 {
- 16 if( uxTopReadyPriority > tskIDLE_PRIORITY )
- 17 {
- 18 uxHigherPriorityReadyTasks = pdTRUE;
- 19 }
- 20 }
- 21 #else
- 22 {
- 23 const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;
- 24
- 25 /* When port optimised task selection is used the uxTopReadyPriority
- 26 * variable is used as a bit map. If bits other than the least
- 27 * significant bit are set then there are tasks that have a priority
- 28 * above the idle priority that are in the Ready state. This takes
- 29 * care of the case where the co-operative scheduler is in use. */
- 30 if( uxTopReadyPriority > uxLeastSignificantBit )
- 31 {
- 32 uxHigherPriorityReadyTasks = pdTRUE;
- 33 }
- 34 }
- 35 #endif /* if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) */
- 36
- 37 /* 这里一样, 抢占式的话当前任务就是空闲任务, 所以下面的判断除了最后的else,
- 38 * 其他都只有非抢占式的才有可能进, 抢占式的就直接看最后的else即可。 */
- 39 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
- 40 {
- 41 xReturn = 0;
- 42 }
- 43 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1U )
- 44 {
- 45 /* There are other idle priority tasks in the ready state. If
- 46 * time slicing is used then the very next tick interrupt must be
- 47 * processed. */
- 48 /* 和空闲任务同优先级的话, 应该也是先运行其他任务最后运行空闲任务 */
- 49 xReturn = 0;
- 50 }
- 51 else if( uxHigherPriorityReadyTasks != pdFALSE )
- 52 {
- 53 /* There are tasks in the Ready state that have a priority above the
- 54 * idle priority. This path can only be reached if
- 55 * configUSE_PREEMPTION is 0. */
- 56 xReturn = 0;
- 57 }
- 58 else
- 59 {
- 60 /* 这里算出来的值是最近唤醒的任务的剩余tick数 */
- 61 xReturn = xNextTaskUnblockTime;
- 62 xReturn -= xTickCount;
- 63 }
- 64
- 65 return xReturn;
- 66 }
复制代码 prvGetExpectedIdleTime 4.2.22 空闲任务调用3--vPortSuppressTicksAndSleep
这个接口就是用于进入低功耗模式的,由于这个和具体的平台相关,所以定义在port.c中,这里只看cortex-m3和m4核的代码。
这个接口个人认为非常复杂,里面有一些计算流程本人也不是很明白,还需要以后反复开发和阅读才能理解。
接口:
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
__weak:如果没有__weak修饰的相同接口定义了,则用新定义的接口,否则就使用该接口,类似与多态,需要编译器支持,非c标准。
参数1:xExpectedIdleTime,4.2.21的接口计算返回的tick数。
前置接口1:eSleepModeStatus eTaskConfirmSleepModeStatus( void ),用于确定是否真的需要进入低功耗模式。
返回:eSleepModeStatus,eAbortSleep:不进入,eStandardSleep:进入但休眠时间不高于xExpectedIdleTime,eNoTasksWaitingTimeout:进入但只能依靠外部中断唤醒。- 1 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
- 2 {
- 3 #if ( INCLUDE_vTaskSuspend == 1 )
- 4 /* The idle task exists in addition to the application tasks. */
- 5 const UBaseType_t uxNonApplicationTasks = configNUMBER_OF_CORES;
- 6 #endif /* INCLUDE_vTaskSuspend */
- 7
- 8 eSleepModeStatus eReturn = eStandardSleep;
- 9
- 10 /* This function must be called from a critical section. */
- 11
- 12 /* 此时调度器暂停, 有必要检查一下是否有任务就绪了, 或者调度延迟了,
- 13 * 或者有tick中断处理被延迟了 */
- 14 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0U )
- 15 {
- 16 /* A task was made ready while the scheduler was suspended. */
- 17 eReturn = eAbortSleep;
- 18 }
- 19 else if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )
- 20 {
- 21 /* A yield was pended while the scheduler was suspended. */
- 22 eReturn = eAbortSleep;
- 23 }
- 24 else if( xPendedTicks != 0U )
- 25 {
- 26 /* A tick interrupt has already occurred but was held pending
- 27 * because the scheduler is suspended. */
- 28 eReturn = eAbortSleep;
- 29 }
- 30
- 31 #if ( INCLUDE_vTaskSuspend == 1 )
- 32 else if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
- 33 {
- 34 /* If all the tasks are in the suspended list (which might mean they
- 35 * have an infinite block time rather than actually being suspended)
- 36 * then it is safe to turn all clocks off and just wait for external
- 37 * interrupts. */
- 38 /* 如果所有的任务都在挂起列表中(即使是那些等待事件且无限延迟的任务有),
- 39 * 那么可以停止时钟并等待外部中断 */
- 40 eReturn = eNoTasksWaitingTimeout;
- 41 }
- 42 #endif /* INCLUDE_vTaskSuspend */
- 43 else
- 44 {
- 45 mtCOVERAGE_TEST_MARKER();
- 46 }
- 47
- 48 return eReturn;
- 49 }
复制代码 前置接口2:void vTaskStepTick( TickType_t xTicksToJump )
参数:xTicksToJump--休眠的tick数,用于更新xTickCount值。
- 1 void vTaskStepTick( TickType_t xTicksToJump )
- 2 {
- 3 TickType_t xUpdatedTickCount;
- 4
- 5 /* Correct the tick count value after a period during which the tick
- 6 * was suppressed. Note this does *not* call the tick hook function for
- 7 * each stepped tick. */
- 8 xUpdatedTickCount = xTickCount + xTicksToJump;
- 9 configASSERT( xUpdatedTickCount <= xNextTaskUnblockTime );
- 10
- 11 if( xUpdatedTickCount == xNextTaskUnblockTime )
- 12 {
- 13 /* Arrange for xTickCount to reach xNextTaskUnblockTime in
- 14 * xTaskIncrementTick() when the scheduler resumes. This ensures
- 15 * that any delayed tasks are resumed at the correct time. */
- 16 /* 有任务到达唤醒时间了, 使xPendedTicks自增, 让xTaskIncrementTick()
- 17 * 接口去实现任务的唤醒 */
- 18 configASSERT( uxSchedulerSuspended != ( UBaseType_t ) 0U );
- 19 configASSERT( xTicksToJump != ( TickType_t ) 0 );
- 20
- 21 /* Prevent the tick interrupt modifying xPendedTicks simultaneously. */
- 22 taskENTER_CRITICAL();
- 23 {
- 24 xPendedTicks++;
- 25 }
- 26 taskEXIT_CRITICAL();
- 27 xTicksToJump--; // xPendedTicks已自增了, xTicksToJump就需要少算一个
- 28 }
- 29 else
- 30 {
- 31 mtCOVERAGE_TEST_MARKER();
- 32 }
- 33
- 34 // 更新xTickCount值
- 35 xTickCount += xTicksToJump;
- 36 }
复制代码 vPortSuppressTicksAndSleep
这一篇内容较多,也较难,日后如果有问题的地方,笔者再回来更新。好了,下篇再见!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |