史穹逊 发表于 2025-6-8 13:10:17

freeRTOS源码解析4--tasks.c 7

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 
  这一篇内容较多,也较难,日后如果有问题的地方,笔者再回来更新。好了,下篇再见!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: freeRTOS源码解析4--tasks.c 7