找回密码
 立即注册
首页 业界区 安全 freeRTOS源码解析4--tasks.c 7

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

史穹逊 2025-6-8 13:10:17
4.2.20 空闲任务调用1--prvCheckTasksWaitingTermination

删除所有终止的任务, 释放资源。简单描述就是清空xTasksWaitingTermination列表,释放资源,递减uxCurrentNumberOfTasks和uxDeletedTasksWaitingCleanUp。
接口:
static void prvCheckTasksWaitingTermination( void )
接口代码如下:
1.gif
2.gif
  1. 1 static void prvCheckTasksWaitingTermination( void )
  2. 2 {
  3. 3     /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/
  4. 4
  5. 5     #if ( INCLUDE_vTaskDelete == 1 )
  6. 6     {
  7. 7         TCB_t * pxTCB;
  8. 8
  9. 9         /* uxDeletedTasksWaitingCleanUp is used to prevent taskENTER_CRITICAL()
  10. 10          * being called too often in the idle task. */
  11. 11         while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
  12. 12         {
  13. 13             #if ( configNUMBER_OF_CORES == 1 )
  14. 14             {
  15. 15                 taskENTER_CRITICAL();
  16. 16                 {
  17. 17                     {
  18. 18                         /* 从终止列表中取出任务 */
  19. 19                         pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
  20. 20                         /* 将任务从终止列表中移出 */
  21. 21                         ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
  22. 22                         --uxCurrentNumberOfTasks;
  23. 23                         --uxDeletedTasksWaitingCleanUp;
  24. 24                     }
  25. 25                 }
  26. 26                 taskEXIT_CRITICAL();
  27. 27
  28. 28                 prvDeleteTCB( pxTCB );    // 释放任务资源
  29. 29             }
  30. 30             #endif /* #if( configNUMBER_OF_CORES == 1 ) */
  31. 31         }
  32. 32     }
  33. 33     #endif /* INCLUDE_vTaskDelete */
  34. 34 }
复制代码
prvCheckTasksWaitingTermination4.2.21 空闲任务调用2--prvGetExpectedIdleTime

这个用于低功耗,主要作用是获取期望睡眠的tick时间。
接口:
static TickType_t prvGetExpectedIdleTime( void )
返回:实际返回的是最近唤醒任务的剩余tick数,即最多能够睡眠这么多tick数后就要苏醒了,因为有任务延迟结束需要唤醒了。
接口代码如下:
3.gif
4.gif
  1. 1 static TickType_t prvGetExpectedIdleTime( void )
  2. 2 {
  3. 3     TickType_t xReturn;
  4. 4     UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;
  5. 5
  6. 6     /* uxHigherPriorityReadyTasks takes care of the case where
  7. 7      * configUSE_PREEMPTION is 0, so there may be tasks above the idle priority
  8. 8      * task that are in the Ready state, even though the idle task is
  9. 9      * running. */
  10. 10     /* uxHigherPriorityReadyTasks用于configUSE_PREEMPTION为0的情况, 因为有可能
  11. 11      * 存在空闲任务在运行时, 也有高于空闲任务优先级的任务处于就绪态。如果是抢占
  12. 12      * 式的调度的话, 则不可能会有更高优先级的任务就绪, 否则根本轮不到空闲任务
  13. 13      * 运行。 */
  14. 14     #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
  15. 15     {
  16. 16         if( uxTopReadyPriority > tskIDLE_PRIORITY )
  17. 17         {
  18. 18             uxHigherPriorityReadyTasks = pdTRUE;
  19. 19         }
  20. 20     }
  21. 21     #else
  22. 22     {
  23. 23         const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;
  24. 24
  25. 25         /* When port optimised task selection is used the uxTopReadyPriority
  26. 26          * variable is used as a bit map.  If bits other than the least
  27. 27          * significant bit are set then there are tasks that have a priority
  28. 28          * above the idle priority that are in the Ready state.  This takes
  29. 29          * care of the case where the co-operative scheduler is in use. */
  30. 30         if( uxTopReadyPriority > uxLeastSignificantBit )
  31. 31         {
  32. 32             uxHigherPriorityReadyTasks = pdTRUE;
  33. 33         }
  34. 34     }
  35. 35     #endif /* if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) */
  36. 36
  37. 37     /* 这里一样, 抢占式的话当前任务就是空闲任务, 所以下面的判断除了最后的else,
  38. 38      * 其他都只有非抢占式的才有可能进, 抢占式的就直接看最后的else即可。 */
  39. 39     if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
  40. 40     {
  41. 41         xReturn = 0;
  42. 42     }
  43. 43     else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1U )
  44. 44     {
  45. 45         /* There are other idle priority tasks in the ready state.  If
  46. 46          * time slicing is used then the very next tick interrupt must be
  47. 47          * processed. */
  48. 48         /* 和空闲任务同优先级的话, 应该也是先运行其他任务最后运行空闲任务 */
  49. 49         xReturn = 0;
  50. 50     }
  51. 51     else if( uxHigherPriorityReadyTasks != pdFALSE )
  52. 52     {
  53. 53         /* There are tasks in the Ready state that have a priority above the
  54. 54          * idle priority.  This path can only be reached if
  55. 55          * configUSE_PREEMPTION is 0. */
  56. 56         xReturn = 0;
  57. 57     }
  58. 58     else
  59. 59     {
  60. 60         /* 这里算出来的值是最近唤醒的任务的剩余tick数 */
  61. 61         xReturn = xNextTaskUnblockTime;
  62. 62         xReturn -= xTickCount;
  63. 63     }
  64. 64
  65. 65     return xReturn;
  66. 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. 1 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
  2. 2 {
  3. 3     #if ( INCLUDE_vTaskSuspend == 1 )
  4. 4         /* The idle task exists in addition to the application tasks. */
  5. 5         const UBaseType_t uxNonApplicationTasks = configNUMBER_OF_CORES;
  6. 6     #endif /* INCLUDE_vTaskSuspend */
  7. 7
  8. 8     eSleepModeStatus eReturn = eStandardSleep;
  9. 9
  10. 10     /* This function must be called from a critical section. */
  11. 11
  12. 12     /* 此时调度器暂停, 有必要检查一下是否有任务就绪了, 或者调度延迟了,
  13. 13      * 或者有tick中断处理被延迟了 */
  14. 14     if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0U )
  15. 15     {
  16. 16         /* A task was made ready while the scheduler was suspended. */
  17. 17         eReturn = eAbortSleep;
  18. 18     }
  19. 19     else if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )
  20. 20     {
  21. 21         /* A yield was pended while the scheduler was suspended. */
  22. 22         eReturn = eAbortSleep;
  23. 23     }
  24. 24     else if( xPendedTicks != 0U )
  25. 25     {
  26. 26         /* A tick interrupt has already occurred but was held pending
  27. 27          * because the scheduler is suspended. */
  28. 28         eReturn = eAbortSleep;
  29. 29     }
  30. 30
  31. 31     #if ( INCLUDE_vTaskSuspend == 1 )
  32. 32         else if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
  33. 33         {
  34. 34             /* If all the tasks are in the suspended list (which might mean they
  35. 35              * have an infinite block time rather than actually being suspended)
  36. 36              * then it is safe to turn all clocks off and just wait for external
  37. 37              * interrupts. */
  38. 38             /* 如果所有的任务都在挂起列表中(即使是那些等待事件且无限延迟的任务有),
  39. 39              * 那么可以停止时钟并等待外部中断 */
  40. 40             eReturn = eNoTasksWaitingTimeout;
  41. 41         }
  42. 42     #endif /* INCLUDE_vTaskSuspend */
  43. 43     else
  44. 44     {
  45. 45         mtCOVERAGE_TEST_MARKER();
  46. 46     }
  47. 47
  48. 48     return eReturn;
  49. 49 }
复制代码
   前置接口2:void vTaskStepTick( TickType_t xTicksToJump )
  参数:xTicksToJump--休眠的tick数,用于更新xTickCount值。
 
  1. 1 void vTaskStepTick( TickType_t xTicksToJump )
  2. 2 {
  3. 3     TickType_t xUpdatedTickCount;
  4. 4
  5. 5     /* Correct the tick count value after a period during which the tick
  6. 6      * was suppressed.  Note this does *not* call the tick hook function for
  7. 7      * each stepped tick. */
  8. 8     xUpdatedTickCount = xTickCount + xTicksToJump;
  9. 9     configASSERT( xUpdatedTickCount <= xNextTaskUnblockTime );
  10. 10
  11. 11     if( xUpdatedTickCount == xNextTaskUnblockTime )
  12. 12     {
  13. 13         /* Arrange for xTickCount to reach xNextTaskUnblockTime in
  14. 14          * xTaskIncrementTick() when the scheduler resumes.  This ensures
  15. 15          * that any delayed tasks are resumed at the correct time. */
  16. 16         /* 有任务到达唤醒时间了, 使xPendedTicks自增, 让xTaskIncrementTick()
  17. 17          * 接口去实现任务的唤醒 */
  18. 18         configASSERT( uxSchedulerSuspended != ( UBaseType_t ) 0U );
  19. 19         configASSERT( xTicksToJump != ( TickType_t ) 0 );
  20. 20
  21. 21         /* Prevent the tick interrupt modifying xPendedTicks simultaneously. */
  22. 22         taskENTER_CRITICAL();
  23. 23         {
  24. 24             xPendedTicks++;
  25. 25         }
  26. 26         taskEXIT_CRITICAL();
  27. 27         xTicksToJump--;    // xPendedTicks已自增了, xTicksToJump就需要少算一个
  28. 28     }
  29. 29     else
  30. 30     {
  31. 31         mtCOVERAGE_TEST_MARKER();
  32. 32     }
  33. 33
  34. 34     // 更新xTickCount值
  35. 35     xTickCount += xTicksToJump;
  36. 36 }
复制代码
vPortSuppressTicksAndSleep 
  这一篇内容较多,也较难,日后如果有问题的地方,笔者再回来更新。好了,下篇再见!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册