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

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

昆拗干 2025-6-7 09:15:23
4.2.13 继续任务--vTaskResume

接口:
void vTaskResume( TaskHandle_t xTaskToResume )
形参1:xTaskToResume ,想要继续的任务handle;
首先是vTaskResume调用的一个内部函数:static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ),用于检查任务是否是挂起状态,只有挂起的任务才能继续,否则是等待事件、通知等处于阻塞态,那就不能放到就绪列表,必须继续等待。这个接口逻辑非常简单,就直接看代码即可。
1.gif
2.gif
  1. 1 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask )
  2. 2 {
  3. 3     BaseType_t xReturn = pdFALSE;
  4. 4     const TCB_t * const pxTCB = xTask;
  5. 5
  6. 6     /* Accesses xPendingReadyList so must be called from a critical
  7. 7      * section. */
  8. 8
  9. 9     /* It does not make sense to check if the calling task is suspended. */
  10. 10     configASSERT( xTask );
  11. 11
  12. 12     /* Is the task being resumed actually in the suspended list? */
  13. 13     /* 检查任务是否在挂起列表, 不在则说明任务未挂起 */
  14. 14     if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE )
  15. 15     {
  16. 16         /* Has the task already been resumed from within an ISR? */
  17. 17         /* 任务在挂起列表里, 但在调度器暂停时被移至等待就绪列表中, 则说明任务未挂起 */
  18. 18         if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE )
  19. 19         {
  20. 20             /* Is it in the suspended list because it is in the Suspended
  21. 21              * state, or because it is blocked with no timeout? */
  22. 22             /* 任务在挂起列表里, 但在等待事件, 则说明任务未挂起 */
  23. 23             if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
  24. 24             {
  25. 25                 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
  26. 26                 {
  27. 27                     BaseType_t x;
  28. 28
  29. 29                     /* The task does not appear on the event list item of
  30. 30                      * and of the RTOS objects, but could still be in the
  31. 31                      * blocked state if it is waiting on its notification
  32. 32                      * rather than waiting on an object.  If not, is
  33. 33                      * suspended. */
  34. 34                     /* 任务在挂起列表里, 且未等待事件, 那么如果在等待通知则未挂起, 否则挂起 */
  35. 35                     xReturn = pdTRUE;
  36. 36
  37. 37                     for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
  38. 38                     {
  39. 39                         if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
  40. 40                         {
  41. 41                             xReturn = pdFALSE;
  42. 42                             break;
  43. 43                         }
  44. 44                     }
  45. 45                 }
  46. 46                 #else /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
  47. 47                 {
  48. 48                     xReturn = pdTRUE;
  49. 49                 }
  50. 50                 #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
  51. 51             }
  52. 52             else
  53. 53             {
  54. 54                 mtCOVERAGE_TEST_MARKER();
  55. 55             }
  56. 56         }
  57. 57         else
  58. 58         {
  59. 59             mtCOVERAGE_TEST_MARKER();
  60. 60         }
  61. 61     }
  62. 62     else
  63. 63     {
  64. 64         mtCOVERAGE_TEST_MARKER();
  65. 65     }
  66. 66
  67. 67     /* 总结下来就是任务若在挂起列表里, 如果不是在等待事件或通知, 则是挂起状态, 否则不是 */
  68. 68
  69. 69     return xReturn;
  70. 70 }
复制代码
prvTaskIsTaskSuspended
3.gif
4.gif
  1. 1 void vTaskResume( TaskHandle_t xTaskToResume )
  2. 2 {
  3. 3     TCB_t * const pxTCB = xTaskToResume;
  4. 4
  5. 5     /* It does not make sense to resume the calling task. */
  6. 6     configASSERT( xTaskToResume );
  7. 7
  8. 8     #if ( configNUMBER_OF_CORES == 1 )
  9. 9         /* The parameter cannot be NULL as it is impossible to resume the
  10. 10          * currently executing task. */
  11. 11         if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
  12. 12     #endif
  13. 13     {
  14. 14         taskENTER_CRITICAL();
  15. 15         {
  16. 16             if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
  17. 17             {
  18. 18                 /* The ready list can be accessed even if the scheduler is
  19. 19                  * suspended because this is inside a critical section. */
  20. 20                 /* 只有任务处于挂起状态才能继续 */
  21. 21                 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
  22. 22                 prvAddTaskToReadyList( pxTCB );
  23. 23
  24. 24                 /* This yield may not cause the task just resumed to run,
  25. 25                  * but will leave the lists in the correct state for the
  26. 26                  * next yield. */
  27. 27                 /* 保证各任务列表处于正常的状态 */
  28. 28                 taskYIELD_ANY_CORE_IF_USING_PREEMPTION( pxTCB );
  29. 29             }
  30. 30             else
  31. 31             {
  32. 32                 mtCOVERAGE_TEST_MARKER();
  33. 33             }
  34. 34         }
  35. 35         taskEXIT_CRITICAL();
  36. 36     }
  37. 37     else
  38. 38     {
  39. 39         mtCOVERAGE_TEST_MARKER();
  40. 40     }
  41. 41 }
复制代码
vTaskResume
5.jpg

4.2.14 启动调度--vTaskStartScheduler

 这个接口会创建空闲任务和软定时器任务,之后就是允许第一个任务,这个接口永远也不会返回,也是main中调用的最后一个接口。
这里补充一下,下面代码注释里说的禁止中断,在启动任务的时候会自动使能中断,是因为任务栈中最底层的第一个值就是XPSR的值为0x01000000,这里把xpsr里的primask清0了,就是表示使能中断。
这在《Cortex M3与M4权威指南》中描述XPSR寄存器的章节下有说明。
6.gif
7.gif
  1. 1 void vTaskStartScheduler( void )
  2. 2 {
  3. 3     BaseType_t xReturn;
  4. 4
  5. 5     /* 创建空闲任务 */
  6. 6     xReturn = prvCreateIdleTasks();
  7. 7
  8. 8     #if ( configUSE_TIMERS == 1 )
  9. 9     {
  10. 10         if( xReturn == pdPASS )
  11. 11         {
  12. 12             xReturn = xTimerCreateTimerTask();    // 创建软定时器任务
  13. 13         }
  14. 14         else
  15. 15         {
  16. 16             mtCOVERAGE_TEST_MARKER();
  17. 17         }
  18. 18     }
  19. 19     #endif /* configUSE_TIMERS */
  20. 20
  21. 21     if( xReturn == pdPASS )
  22. 22     {
  23. 23         /* Interrupts are turned off here, to ensure a tick does not occur
  24. 24          * before or during the call to xPortStartScheduler().  The stacks of
  25. 25          * the created tasks contain a status word with interrupts switched on
  26. 26          * so interrupts will automatically get re-enabled when the first task
  27. 27          * starts to run. */
  28. 28         /* 关闭中断, 保证在调用xPortStartScheduler前不会发生tick中断, 所有创建
  29. 29          * 的任务的栈中都包含一个中断开启的状态字, 所以第一个任务运行时, 中断
  30. 30          * 会自动开启 */
  31. 31         /* 暂时没看懂这个注释的意思, 但这个接口只是设置了中断优先级屏蔽寄存器,
  32. 32          * 实际的中断并未关闭, 系统中断被屏蔽了 */
  33. 33         portDISABLE_INTERRUPTS();
  34. 34
  35. 35         xNextTaskUnblockTime = portMAX_DELAY;
  36. 36         xSchedulerRunning = pdTRUE;
  37. 37         xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
  38. 38
  39. 39         /* If configGENERATE_RUN_TIME_STATS is defined then the following
  40. 40          * macro must be defined to configure the timer/counter used to generate
  41. 41          * the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS
  42. 42          * is set to 0 and the following line fails to build then ensure you do not
  43. 43          * have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
  44. 44          * FreeRTOSConfig.h file. */
  45. 45         portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
  46. 46
  47. 47         /* Setting up the timer tick is hardware specific and thus in the
  48. 48          * portable interface. */
  49. 49
  50. 50         /* The return value for xPortStartScheduler is not required
  51. 51          * hence using a void datatype. */
  52. 52         /* 真正的启动调度器, 即启动了第一个任务 */
  53. 53         ( void ) xPortStartScheduler();
  54. 54
  55. 55         /* In most cases, xPortStartScheduler() will not return. If it
  56. 56          * returns pdTRUE then there was not enough heap memory available
  57. 57          * to create either the Idle or the Timer task. If it returned
  58. 58          * pdFALSE, then the application called xTaskEndScheduler().
  59. 59          * Most ports don't implement xTaskEndScheduler() as there is
  60. 60          * nothing to return to. */
  61. 61     }
  62. 62     else
  63. 63     {
  64. 64         /* This line will only be reached if the kernel could not be started,
  65. 65          * because there was not enough FreeRTOS heap to create the idle task
  66. 66          * or the timer task. */
  67. 67         configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
  68. 68     }
  69. 69
  70. 70     /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
  71. 71      * meaning xIdleTaskHandles are not used anywhere else. */
  72. 72     ( void ) xIdleTaskHandles;
  73. 73
  74. 74     /* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority
  75. 75      * from getting optimized out as it is no longer used by the kernel. */
  76. 76     ( void ) uxTopUsedPriority;
  77. 77 }
复制代码
vTaskStartScheduler 
4.2.15 停止调度--vTaskEndScheduler

这个接口和上一个相对,而且这个接口一定是在某个任务中调用的,因为系统不会主动停止调度器,而正常运行中始终只有某个任务和系统在运行,所以必然是某个任务主动调用的。
这里也是一样。
8.gif
9.gif
  1. 1 void vTaskEndScheduler( void )
  2. 2 {
  3. 3     #if ( INCLUDE_vTaskDelete == 1 )
  4. 4     {
  5. 5         BaseType_t xCoreID;
  6. 6
  7. 7         #if ( configUSE_TIMERS == 1 )
  8. 8         {
  9. 9             /* Delete the timer task created by the kernel. */
  10. 10             /* 删除软定时器任务 */
  11. 11             vTaskDelete( xTimerGetTimerDaemonTaskHandle() );
  12. 12         }
  13. 13         #endif /* #if ( configUSE_TIMERS == 1 ) */
  14. 14
  15. 15         /* Delete Idle tasks created by the kernel.*/
  16. 16         for( xCoreID = 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ )
  17. 17         {
  18. 18             vTaskDelete( xIdleTaskHandles[ xCoreID ] );    // 删除空闲任务
  19. 19         }
  20. 20
  21. 21         /* Idle task is responsible for reclaiming the resources of the tasks in
  22. 22          * xTasksWaitingTermination list. Since the idle task is now deleted and
  23. 23          * no longer going to run, we need to reclaim resources of all the tasks
  24. 24          * in the xTasksWaitingTermination list. */
  25. 25         /* 本应由空闲任务回收待删除任务的资源, 但现在空闲任务被删除了, 就在这里处理 */
  26. 26         prvCheckTasksWaitingTermination();
  27. 27     }
  28. 28     #endif /* #if ( INCLUDE_vTaskDelete == 1 ) */
  29. 29
  30. 30     /* Stop the scheduler interrupts and call the portable scheduler end
  31. 31      * routine so the original ISRs can be restored if necessary.  The port
  32. 32      * layer must ensure interrupts enable  bit is left in the correct state. */
  33. 33     /* 这跟启动调度器时关中断一样的疑问 */
  34. 34     portDISABLE_INTERRUPTS();
  35. 35     xSchedulerRunning = pdFALSE;
  36. 36
  37. 37     /* This function must be called from a task and the application is
  38. 38      * responsible for deleting that task after the scheduler is stopped. */
  39. 39     vPortEndScheduler();
  40. 40 }
复制代码
vTaskEndScheduler 
  好了,下一篇讲xTaskAbortDelay和xTaskIncrementTick接口,这两个接口较为复杂。
  下篇再见。

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