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

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

讹过畔 前天 09:15
4.2.9 周期任务用的延迟--xTaskDelayUntil

接口:BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
形参1:pxPreviousWakeTime,上一次唤醒时间,第一次需要用接口xTaskGetTickCount()获取;
形参2:xTimeIncrement,想要延迟的时间。
返回值:用于判读任务是否确实需要delay。
1.gif
2.gif
  1. 1 BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
  2. 2                                 const TickType_t xTimeIncrement )
  3. 3 {
  4. 4     TickType_t xTimeToWake;
  5. 5     BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
  6. 6
  7. 7     configASSERT( pxPreviousWakeTime );
  8. 8     configASSERT( ( xTimeIncrement > 0U ) );
  9. 9
  10. 10     vTaskSuspendAll();
  11. 11     {
  12. 12         /* Minor optimisation. The tick count cannot change in this
  13. 13          * block. */
  14. 14         const TickType_t xConstTickCount = xTickCount;
  15. 15
  16. 16         configASSERT( uxSchedulerSuspended == 1U );
  17. 17
  18. 18         /* Generate the tick time at which the task wants to wake. */
  19. 19         /* 计算任务下次唤醒的时间 */
  20. 20         xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
  21. 21
  22. 22         if( xConstTickCount < *pxPreviousWakeTime )
  23. 23         {
  24. 24             /* The tick count has overflowed since this function was
  25. 25              * lasted called.  In this case the only time we should ever
  26. 26              * actually delay is if the wake time has also  overflowed,
  27. 27              * and the wake time is greater than the tick time.  When this
  28. 28              * is the case it is as if neither time had overflowed. */
  29. 29             /* tick值已经溢出了, 只有xTimeToWake也溢出并大于xConstTickCount
  30. 30              * 时, 才需要延迟 */
  31. 31             /* 假设tick是8位的, 当前值为0x5(从FF加到5), pxPreviousWakeTime为0xFD,
  32. 32              * 当xTimeIncrement为1时, xTimeToWake未溢出, 当xTimeIncrement为0x15时,
  33. 33              * xTimeToWake溢出。 显然当xTimeIncrement为1时, xTimeToWake比
  34. 34              * pxPreviousWakeTime和xConstTickCount都大, 但不需要延迟, 因为tick已过,
  35. 35              * 当xTimeIncrement为0x15时, xTimeToWake比pxPreviousWakeTime小但比xConstTickCount
  36. 36              * 大, tick要等到0x12才到延迟时间, 所以需要进行延迟. */
  37. 37             if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
  38. 38             {
  39. 39                 xShouldDelay = pdTRUE;
  40. 40             }
  41. 41             else
  42. 42             {
  43. 43                 mtCOVERAGE_TEST_MARKER();
  44. 44             }
  45. 45         }
  46. 46         else
  47. 47         {
  48. 48             /* The tick time has not overflowed.  In this case we will
  49. 49              * delay if either the wake time has overflowed, and/or the
  50. 50              * tick time is less than the wake time. */
  51. 51             /* tick没有溢出, 那么xTimeToWake溢出或比xConstTickCount小,
  52. 52              * 必然是需要延迟的. */
  53. 53             if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
  54. 54             {
  55. 55                 xShouldDelay = pdTRUE;
  56. 56             }
  57. 57             else
  58. 58             {
  59. 59                 mtCOVERAGE_TEST_MARKER();
  60. 60             }
  61. 61         }
  62. 62
  63. 63         /* Update the wake time ready for the next call. */
  64. 64         *pxPreviousWakeTime = xTimeToWake;
  65. 65
  66. 66         if( xShouldDelay != pdFALSE )
  67. 67         {
  68. 68             /* prvAddCurrentTaskToDelayedList() needs the block time, not
  69. 69              * the time to wake, so subtract the current tick count. */
  70. 70             /* 延迟列表记录的是阻塞时间而不是唤醒时间, 所以需要减去tick. */
  71. 71             prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
  72. 72         }
  73. 73         else
  74. 74         {
  75. 75             mtCOVERAGE_TEST_MARKER();
  76. 76         }
  77. 77     }
  78. 78     xAlreadyYielded = xTaskResumeAll();
  79. 79
  80. 80     /* Force a reschedule if xTaskResumeAll has not already done so, we may
  81. 81      * have put ourselves to sleep. */
  82. 82     if( xAlreadyYielded == pdFALSE )
  83. 83     {
  84. 84         taskYIELD_WITHIN_API();
  85. 85     }
  86. 86     else
  87. 87     {
  88. 88         mtCOVERAGE_TEST_MARKER();
  89. 89     }
  90. 90
  91. 91     return xShouldDelay;
  92. 92 }
复制代码
xTaskDelayUntil 4.2.10 成对的信息获取接口,一般的和带有FromISR后缀的

这类接口比较简单,主要用于获取TCB中的某些参数,这里挑选任务优先级获取接口为例,重点在于带有FromISR的接口。一般的接口很简单,这里就直接放出来即可。
  1. 1 UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
  2. 2 {
  3. 3     TCB_t const * pxTCB;
  4. 4     UBaseType_t uxReturn;
  5. 5
  6. 6     taskENTER_CRITICAL();
  7. 7     {
  8. 8         /* If null is passed in here then it is the priority of the task
  9. 9          * that called uxTaskPriorityGet() that is being queried. */
  10. 10         pxTCB = prvGetTCBFromHandle( xTask );
  11. 11         uxReturn = pxTCB->uxPriority;
  12. 12     }
  13. 13     taskEXIT_CRITICAL();
  14. 14
  15. 15     return uxReturn;
  16. 16 }
复制代码
  1. 1 UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask )
  2. 2 {
  3. 3     TCB_t const * pxTCB;
  4. 4     UBaseType_t uxReturn;
  5. 5     UBaseType_t uxSavedInterruptStatus;
  6. 6
  7. 7     /* RTOS ports that support interrupt nesting have the concept of a
  8. 8      * maximum  system call (or maximum API call) interrupt priority.
  9. 9      * Interrupts that are  above the maximum system call priority are keep
  10. 10      * permanently enabled, even when the RTOS kernel is in a critical section,
  11. 11      * but cannot make any calls to FreeRTOS API functions.  If configASSERT()
  12. 12      * is defined in FreeRTOSConfig.h then
  13. 13      * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
  14. 14      * failure if a FreeRTOS API function is called from an interrupt that has
  15. 15      * been assigned a priority above the configured maximum system call
  16. 16      * priority.  Only FreeRTOS functions that end in FromISR can be called
  17. 17      * from interrupts  that have been assigned a priority at or (logically)
  18. 18      * below the maximum system call interrupt priority.  FreeRTOS maintains a
  19. 19      * separate interrupt safe API to ensure interrupt entry is as fast and as
  20. 20      * simple as possible.  More information (albeit Cortex-M specific) is
  21. 21      * provided on the following link:
  22. 22      * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
  23. 23     /* 检查调用带有FromISR后缀的中断优先级是否高于
  24. 24      * configMAX_SYSCALL_INTERRUPT_PRIORITY, 是的话会进入assert */
  25. 25     portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
  26. 26
  27. 27     /* MISRA Ref 4.7.1 [Return value shall be checked] */
  28. 28     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
  29. 29     /* coverity[misra_c_2012_directive_4_7_violation] */
  30. 30     /* 获取当前中断屏蔽优先级, 并设置中断屏蔽优先级为configMAX_SYSCALL_INTERRUPT_PRIORITY
  31. 31      * 相当于进入了临界区并返回了当前中断屏蔽优先级 */
  32. 32     uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();
  33. 33     {
  34. 34         /* If null is passed in here then it is the priority of the calling
  35. 35          * task that is being queried. */
  36. 36         pxTCB = prvGetTCBFromHandle( xTask );
  37. 37         uxReturn = pxTCB->uxPriority;
  38. 38     }
  39. 39     /* 将保存的中断屏蔽优先级设置回去, 相当于退出临界区 */
  40. 40     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
  41. 41
  42. 42     return uxReturn;
  43. 43 }
复制代码
4.2.11 设置任务优先级--vTaskPrioritySet

接口虽然较长,但注释较多,且逻辑较为简单,直接看代码里的注释即可。
3.gif
4.gif
  1.   1 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
  2.   2 {
  3.   3     TCB_t * pxTCB;
  4.   4     UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
  5.   5     BaseType_t xYieldRequired = pdFALSE;
  6.   6
  7.   7     configASSERT( uxNewPriority < configMAX_PRIORITIES );
  8.   8
  9.   9     /* Ensure the new priority is valid. */
  10. 10     if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
  11. 11     {
  12. 12         uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
  13. 13     }
  14. 14     else
  15. 15     {
  16. 16         mtCOVERAGE_TEST_MARKER();
  17. 17     }
  18. 18
  19. 19     taskENTER_CRITICAL();
  20. 20     {
  21. 21         /* If null is passed in here then it is the priority of the calling
  22. 22          * task that is being changed. */
  23. 23         pxTCB = prvGetTCBFromHandle( xTask );
  24. 24
  25. 25         #if ( configUSE_MUTEXES == 1 )
  26. 26         {
  27. 27             uxCurrentBasePriority = pxTCB->uxBasePriority;
  28. 28         }
  29. 29         #else
  30. 30         {
  31. 31             uxCurrentBasePriority = pxTCB->uxPriority;
  32. 32         }
  33. 33         #endif
  34. 34
  35. 35         if( uxCurrentBasePriority != uxNewPriority )
  36. 36         {
  37. 37             /* The priority change may have readied a task of higher
  38. 38              * priority than a running task. */
  39. 39             if( uxNewPriority > uxCurrentBasePriority )
  40. 40             {
  41. 41                 /* 提升优先级 */
  42. 42                 #if ( configNUMBER_OF_CORES == 1 )
  43. 43                 {
  44. 44                     if( pxTCB != pxCurrentTCB )
  45. 45                     {
  46. 46                         /* The priority of a task other than the currently
  47. 47                          * running task is being raised.  Is the priority being
  48. 48                          * raised above that of the running task? */
  49. 49                         /* 设置的优先级比当前运行的任务高, 需要yield */
  50. 50                         if( uxNewPriority > pxCurrentTCB->uxPriority )
  51. 51                         {
  52. 52                             xYieldRequired = pdTRUE;
  53. 53                         }
  54. 54                         else
  55. 55                         {
  56. 56                             mtCOVERAGE_TEST_MARKER();
  57. 57                         }
  58. 58                     }
  59. 59                     else
  60. 60                     {
  61. 61                         /* The priority of the running task is being raised,
  62. 62                          * but the running task must already be the highest
  63. 63                          * priority task able to run so no yield is required. */
  64. 64                     }
  65. 65                 }
  66. 66                 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
  67. 67             }
  68. 68             else if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
  69. 69             {
  70. 70                 /* Setting the priority of a running task down means
  71. 71                  * there may now be another task of higher priority that
  72. 72                  * is ready to execute. */
  73. 73                 /* 降低当前运行任务的优先级, 则更高优先级的就绪任务需要抢占 */
  74. 74                 #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
  75. 75                     if( pxTCB->xPreemptionDisable == pdFALSE )
  76. 76                 #endif
  77. 77                 {
  78. 78                     xYieldRequired = pdTRUE;
  79. 79                 }
  80. 80             }
  81. 81             else
  82. 82             {
  83. 83                 /* Setting the priority of any other task down does not
  84. 84                  * require a yield as the running task must be above the
  85. 85                  * new priority of the task being modified. */
  86. 86             }
  87. 87
  88. 88             /* Remember the ready list the task might be referenced from
  89. 89              * before its uxPriority member is changed so the
  90. 90              * taskRESET_READY_PRIORITY() macro can function correctly. */
  91. 91             /* 获取任务当前的优先级, 有可能是继承来的优先级 */
  92. 92             uxPriorityUsedOnEntry = pxTCB->uxPriority;
  93. 93
  94. 94             #if ( configUSE_MUTEXES == 1 )
  95. 95             {
  96. 96                 /* Only change the priority being used if the task is not
  97. 97                  * currently using an inherited priority or the new priority
  98. 98                  * is bigger than the inherited priority. */
  99. 99                 /* 只有非继承来的优先级, 或提升优先级才可以直接修改pxTCB->uxPriority */
  100. 100                 if( ( pxTCB->uxBasePriority == pxTCB->uxPriority ) || ( uxNewPriority > pxTCB->uxPriority ) )
  101. 101                 {
  102. 102                     pxTCB->uxPriority = uxNewPriority;
  103. 103                 }
  104. 104                 else
  105. 105                 {
  106. 106                     mtCOVERAGE_TEST_MARKER();
  107. 107                 }
  108. 108
  109. 109                 /* The base priority gets set whatever. */
  110. 110                 pxTCB->uxBasePriority = uxNewPriority;
  111. 111             }
  112. 112             #else /* if ( configUSE_MUTEXES == 1 ) */
  113. 113             {
  114. 114                 pxTCB->uxPriority = uxNewPriority;
  115. 115             }
  116. 116             #endif /* if ( configUSE_MUTEXES == 1 ) */
  117. 117
  118. 118             /* Only reset the event list item value if the value is not
  119. 119              * being used for anything else. */
  120. 120             /* xEventListItem的值未被使用, 才允许更新这个值 */
  121. 121             if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == ( ( TickType_t ) 0U ) )
  122. 122             {
  123. 123                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) );
  124. 124             }
  125. 125             else
  126. 126             {
  127. 127                 mtCOVERAGE_TEST_MARKER();
  128. 128             }
  129. 129
  130. 130             /* If the task is in the blocked or suspended list we need do
  131. 131              * nothing more than change its priority variable. However, if
  132. 132              * the task is in a ready list it needs to be removed and placed
  133. 133              * in the list appropriate to its new priority. */
  134. 134             /* 如果任务处于就绪列表, 则需要将其放到修改后的优先级就绪列表 */
  135. 135             if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
  136. 136             {
  137. 137                 /* The task is currently in its ready list - remove before
  138. 138                  * adding it to its new ready list.  As we are in a critical
  139. 139                  * section we can do this even if the scheduler is suspended. */
  140. 140                 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
  141. 141                 {
  142. 142                     /* It is known that the task is in its ready list so
  143. 143                      * there is no need to check again and the port level
  144. 144                      * reset macro can be called directly. */
  145. 145                     portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
  146. 146                 }
  147. 147                 else
  148. 148                 {
  149. 149                     mtCOVERAGE_TEST_MARKER();
  150. 150                 }
  151. 151
  152. 152                 prvAddTaskToReadyList( pxTCB );
  153. 153             }
  154. 154             else
  155. 155             {
  156. 156                 #if ( configNUMBER_OF_CORES == 1 )
  157. 157                 {
  158. 158                     mtCOVERAGE_TEST_MARKER();
  159. 159                 }
  160. 160                 #endif
  161. 161             }
  162. 162
  163. 163             if( xYieldRequired != pdFALSE )
  164. 164             {
  165. 165                 /* The running task priority is set down. Request the task to yield. */
  166. 166                 /* 开始yield, 但是在退出临界区后才会进入sv中断? */
  167. 167                 taskYIELD_TASK_CORE_IF_USING_PREEMPTION( pxTCB );
  168. 168             }
  169. 169             else
  170. 170             {
  171. 171                 mtCOVERAGE_TEST_MARKER();
  172. 172             }
  173. 173
  174. 174             /* Remove compiler warning about unused variables when the port
  175. 175              * optimised task selection is not being used. */
  176. 176             ( void ) uxPriorityUsedOnEntry;
  177. 177         }
  178. 178     }
  179. 179     taskEXIT_CRITICAL();
  180. 180 }
复制代码
vTaskPrioritySet  补个流程图
5.jpg

 
4.2.12 挂起任务--vTaskSuspend

还是直接看代码注释,解释得比较清楚了,接口功能可以顾名思义,逻辑也还好不复杂。
6.gif
7.gif
  1.   1 void vTaskSuspend( TaskHandle_t xTaskToSuspend )
  2.   2 {
  3.   3     TCB_t * pxTCB;
  4.   4
  5.   5     taskENTER_CRITICAL();
  6.   6     {
  7.   7         /* If null is passed in here then it is the running task that is
  8.   8          * being suspended. */
  9.   9         pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
  10. 10
  11. 11         /* Remove task from the ready/delayed list and place in the
  12. 12          * suspended list. */
  13. 13         if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
  14. 14         {
  15. 15             taskRESET_READY_PRIORITY( pxTCB->uxPriority );
  16. 16         }
  17. 17         else
  18. 18         {
  19. 19             mtCOVERAGE_TEST_MARKER();
  20. 20         }
  21. 21
  22. 22         /* Is the task waiting on an event also? */
  23. 23         /* 任务挂起, 任务就不管是否在等待事件 */
  24. 24         if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
  25. 25         {
  26. 26             ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
  27. 27         }
  28. 28         else
  29. 29         {
  30. 30             mtCOVERAGE_TEST_MARKER();
  31. 31         }
  32. 32
  33. 33         vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
  34. 34
  35. 35         /* 如果在等待通知, 也直接退出等待 */
  36. 36         #if ( configUSE_TASK_NOTIFICATIONS == 1 )
  37. 37         {
  38. 38             BaseType_t x;
  39. 39
  40. 40             for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
  41. 41             {
  42. 42                 if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
  43. 43                 {
  44. 44                     /* The task was blocked to wait for a notification, but is
  45. 45                      * now suspended, so no notification was received. */
  46. 46                     pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;
  47. 47                 }
  48. 48             }
  49. 49         }
  50. 50         #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
  51. 51     }
  52. 52     taskEXIT_CRITICAL();
  53. 53
  54. 54     #if ( configNUMBER_OF_CORES == 1 )
  55. 55     {
  56. 56         UBaseType_t uxCurrentListLength;
  57. 57
  58. 58         if( xSchedulerRunning != pdFALSE )
  59. 59         {
  60. 60             /* Reset the next expected unblock time in case it referred to the
  61. 61              * task that is now in the Suspended state. */
  62. 62             /* 如果下个解除阻塞的时间对应的任务正好是挂起的任务,
  63. 63              * 无论如何重置一下下个解除阻塞的时间 */
  64. 64             taskENTER_CRITICAL();
  65. 65             {
  66. 66                 prvResetNextTaskUnblockTime();
  67. 67             }
  68. 68             taskEXIT_CRITICAL();
  69. 69         }
  70. 70         else
  71. 71         {
  72. 72             mtCOVERAGE_TEST_MARKER();
  73. 73         }
  74. 74
  75. 75         if( pxTCB == pxCurrentTCB )
  76. 76         {
  77. 77             if( xSchedulerRunning != pdFALSE )
  78. 78             {
  79. 79                 /* The current task has just been suspended. */
  80. 80                 /* 当前运行的任务挂起, 需要yield */
  81. 81                 configASSERT( uxSchedulerSuspended == 0 );
  82. 82                 portYIELD_WITHIN_API();
  83. 83             }
  84. 84             else
  85. 85             {
  86. 86                 /* The scheduler is not running, but the task that was pointed
  87. 87                  * to by pxCurrentTCB has just been suspended and pxCurrentTCB
  88. 88                  * must be adjusted to point to a different task. */
  89. 89
  90. 90                 /* Use a temp variable as a distinct sequence point for reading
  91. 91                  * volatile variables prior to a comparison to ensure compliance
  92. 92                  * with MISRA C 2012 Rule 13.2. */
  93. 93                 uxCurrentListLength = listCURRENT_LIST_LENGTH( &xSuspendedTaskList );
  94. 94
  95. 95                 if( uxCurrentListLength == uxCurrentNumberOfTasks )
  96. 96                 {
  97. 97                     /* No other tasks are ready, so set pxCurrentTCB back to
  98. 98                      * NULL so when the next task is created pxCurrentTCB will
  99. 99                      * be set to point to it no matter what its relative priority
  100. 100                      * is. */
  101. 101                     /* 所有创建的任务处于挂起状态, 只能等新任务创建了 */
  102. 102                     pxCurrentTCB = NULL;
  103. 103                 }
  104. 104                 else
  105. 105                 {
  106. 106                     /* 切换下上下文, 因为挂起的是当前任务, 也有可能就绪列表为空,
  107. 107                      * 会导致pxCurrentTCB = idle, 否则会选择就绪列表中优先级最高
  108. 108                      * 任务, 这个接口在这里只是设置了pxCurrentTCB参数, 并pend了
  109. 109                      * yield, 因为当前调度器处于暂停状态 */
  110. 110                     vTaskSwitchContext();
  111. 111                 }
  112. 112             }
  113. 113         }
  114. 114         else
  115. 115         {
  116. 116             mtCOVERAGE_TEST_MARKER();
  117. 117         }
  118. 118     }
  119. 119     #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
  120. 120 }
复制代码
vTaskSuspend 
  这篇就到这里了,内容也比较多,下篇开始vTaskResume和vTaskStartScheduler。
下篇再见!

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