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

cnblogs 2024-09-11 08:15:00 阅读 54

4.2.9 周期任务用的延迟--xTaskDelayUntil

接口:BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )

形参1:pxPreviousWakeTime,上一次唤醒时间,第一次需要用接口xTaskGetTickCount()获取;

形参2:xTimeIncrement,想要延迟的时间。

返回值:用于判读任务是否确实需要delay。

1 BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,

2 const TickType_t xTimeIncrement )

3 {

4 TickType_t xTimeToWake;

5 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;

6

7 configASSERT( pxPreviousWakeTime );

8 configASSERT( ( xTimeIncrement > 0U ) );

9

10 vTaskSuspendAll();

11 {

12 /* Minor optimisation. The tick count cannot change in this

13 * block. */

14 const TickType_t xConstTickCount = xTickCount;

15

16 configASSERT( uxSchedulerSuspended == 1U );

17

18 /* Generate the tick time at which the task wants to wake. */

19 /* 计算任务下次唤醒的时间 */

20 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;

21

22 if( xConstTickCount < *pxPreviousWakeTime )

23 {

24 /* The tick count has overflowed since this function was

25 * lasted called. In this case the only time we should ever

26 * actually delay is if the wake time has also overflowed,

27 * and the wake time is greater than the tick time. When this

28 * is the case it is as if neither time had overflowed. */

29 /* tick值已经溢出了, 只有xTimeToWake也溢出并大于xConstTickCount

30 * 时, 才需要延迟 */

31 /* 假设tick是8位的, 当前值为0x5(从FF加到5), pxPreviousWakeTime为0xFD,

32 * 当xTimeIncrement为1时, xTimeToWake未溢出, 当xTimeIncrement为0x15时,

33 * xTimeToWake溢出。 显然当xTimeIncrement为1时, xTimeToWake比

34 * pxPreviousWakeTime和xConstTickCount都大, 但不需要延迟, 因为tick已过,

35 * 当xTimeIncrement为0x15时, xTimeToWake比pxPreviousWakeTime小但比xConstTickCount

36 * 大, tick要等到0x12才到延迟时间, 所以需要进行延迟. */

37 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )

38 {

39 xShouldDelay = pdTRUE;

40 }

41 else

42 {

43 mtCOVERAGE_TEST_MARKER();

44 }

45 }

46 else

47 {

48 /* The tick time has not overflowed. In this case we will

49 * delay if either the wake time has overflowed, and/or the

50 * tick time is less than the wake time. */

51 /* tick没有溢出, 那么xTimeToWake溢出或比xConstTickCount小,

52 * 必然是需要延迟的. */

53 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )

54 {

55 xShouldDelay = pdTRUE;

56 }

57 else

58 {

59 mtCOVERAGE_TEST_MARKER();

60 }

61 }

62

63 /* Update the wake time ready for the next call. */

64 *pxPreviousWakeTime = xTimeToWake;

65

66 if( xShouldDelay != pdFALSE )

67 {

68 /* prvAddCurrentTaskToDelayedList() needs the block time, not

69 * the time to wake, so subtract the current tick count. */

70 /* 延迟列表记录的是阻塞时间而不是唤醒时间, 所以需要减去tick. */

71 prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );

72 }

73 else

74 {

75 mtCOVERAGE_TEST_MARKER();

76 }

77 }

78 xAlreadyYielded = xTaskResumeAll();

79

80 /* Force a reschedule if xTaskResumeAll has not already done so, we may

81 * have put ourselves to sleep. */

82 if( xAlreadyYielded == pdFALSE )

83 {

84 taskYIELD_WITHIN_API();

85 }

86 else

87 {

88 mtCOVERAGE_TEST_MARKER();

89 }

90

91 return xShouldDelay;

92 }

xTaskDelayUntil

4.2.10 成对的信息获取接口,一般的和带有FromISR后缀的

这类接口比较简单,主要用于获取TCB中的某些参数,这里挑选任务优先级获取接口为例,重点在于带有FromISR的接口。一般的接口很简单,这里就直接放出来即可。

1 UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )

2 {

3 TCB_t const * pxTCB;

4 UBaseType_t uxReturn;

5

6 taskENTER_CRITICAL();

7 {

8 /* If null is passed in here then it is the priority of the task

9 * that called uxTaskPriorityGet() that is being queried. */

10 pxTCB = prvGetTCBFromHandle( xTask );

11 uxReturn = pxTCB->uxPriority;

12 }

13 taskEXIT_CRITICAL();

14

15 return uxReturn;

16 }

1 UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask )

2 {

3 TCB_t const * pxTCB;

4 UBaseType_t uxReturn;

5 UBaseType_t uxSavedInterruptStatus;

6

7 /* RTOS ports that support interrupt nesting have the concept of a

8 * maximum system call (or maximum API call) interrupt priority.

9 * Interrupts that are above the maximum system call priority are keep

10 * permanently enabled, even when the RTOS kernel is in a critical section,

11 * but cannot make any calls to FreeRTOS API functions. If configASSERT()

12 * is defined in FreeRTOSConfig.h then

13 * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion

14 * failure if a FreeRTOS API function is called from an interrupt that has

15 * been assigned a priority above the configured maximum system call

16 * priority. Only FreeRTOS functions that end in FromISR can be called

17 * from interrupts that have been assigned a priority at or (logically)

18 * below the maximum system call interrupt priority. FreeRTOS maintains a

19 * separate interrupt safe API to ensure interrupt entry is as fast and as

20 * simple as possible. More information (albeit Cortex-M specific) is

21 * provided on the following link:

22 * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */

23 /* 检查调用带有FromISR后缀的中断优先级是否高于

24 * configMAX_SYSCALL_INTERRUPT_PRIORITY, 是的话会进入assert */

25 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

26

27 /* MISRA Ref 4.7.1 [Return value shall be checked] */

28 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */

29 /* coverity[misra_c_2012_directive_4_7_violation] */

30 /* 获取当前中断屏蔽优先级, 并设置中断屏蔽优先级为configMAX_SYSCALL_INTERRUPT_PRIORITY

31 * 相当于进入了临界区并返回了当前中断屏蔽优先级 */

32 uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();

33 {

34 /* If null is passed in here then it is the priority of the calling

35 * task that is being queried. */

36 pxTCB = prvGetTCBFromHandle( xTask );

37 uxReturn = pxTCB->uxPriority;

38 }

39 /* 将保存的中断屏蔽优先级设置回去, 相当于退出临界区 */

40 taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );

41

42 return uxReturn;

43 }

4.2.11 设置任务优先级--vTaskPrioritySet

接口虽然较长,但注释较多,且逻辑较为简单,直接看代码里的注释即可。

1 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )

2 {

3 TCB_t * pxTCB;

4 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;

5 BaseType_t xYieldRequired = pdFALSE;

6

7 configASSERT( uxNewPriority < configMAX_PRIORITIES );

8

9 /* Ensure the new priority is valid. */

10 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )

11 {

12 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;

13 }

14 else

15 {

16 mtCOVERAGE_TEST_MARKER();

17 }

18

19 taskENTER_CRITICAL();

20 {

21 /* If null is passed in here then it is the priority of the calling

22 * task that is being changed. */

23 pxTCB = prvGetTCBFromHandle( xTask );

24

25 #if ( configUSE_MUTEXES == 1 )

26 {

27 uxCurrentBasePriority = pxTCB->uxBasePriority;

28 }

29 #else

30 {

31 uxCurrentBasePriority = pxTCB->uxPriority;

32 }

33 #endif

34

35 if( uxCurrentBasePriority != uxNewPriority )

36 {

37 /* The priority change may have readied a task of higher

38 * priority than a running task. */

39 if( uxNewPriority > uxCurrentBasePriority )

40 {

41 /* 提升优先级 */

42 #if ( configNUMBER_OF_CORES == 1 )

43 {

44 if( pxTCB != pxCurrentTCB )

45 {

46 /* The priority of a task other than the currently

47 * running task is being raised. Is the priority being

48 * raised above that of the running task? */

49 /* 设置的优先级比当前运行的任务高, 需要yield */

50 if( uxNewPriority > pxCurrentTCB->uxPriority )

51 {

52 xYieldRequired = pdTRUE;

53 }

54 else

55 {

56 mtCOVERAGE_TEST_MARKER();

57 }

58 }

59 else

60 {

61 /* The priority of the running task is being raised,

62 * but the running task must already be the highest

63 * priority task able to run so no yield is required. */

64 }

65 }

66 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */

67 }

68 else if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )

69 {

70 /* Setting the priority of a running task down means

71 * there may now be another task of higher priority that

72 * is ready to execute. */

73 /* 降低当前运行任务的优先级, 则更高优先级的就绪任务需要抢占 */

74 #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )

75 if( pxTCB->xPreemptionDisable == pdFALSE )

76 #endif

77 {

78 xYieldRequired = pdTRUE;

79 }

80 }

81 else

82 {

83 /* Setting the priority of any other task down does not

84 * require a yield as the running task must be above the

85 * new priority of the task being modified. */

86 }

87

88 /* Remember the ready list the task might be referenced from

89 * before its uxPriority member is changed so the

90 * taskRESET_READY_PRIORITY() macro can function correctly. */

91 /* 获取任务当前的优先级, 有可能是继承来的优先级 */

92 uxPriorityUsedOnEntry = pxTCB->uxPriority;

93

94 #if ( configUSE_MUTEXES == 1 )

95 {

96 /* Only change the priority being used if the task is not

97 * currently using an inherited priority or the new priority

98 * is bigger than the inherited priority. */

99 /* 只有非继承来的优先级, 或提升优先级才可以直接修改pxTCB->uxPriority */

100 if( ( pxTCB->uxBasePriority == pxTCB->uxPriority ) || ( uxNewPriority > pxTCB->uxPriority ) )

101 {

102 pxTCB->uxPriority = uxNewPriority;

103 }

104 else

105 {

106 mtCOVERAGE_TEST_MARKER();

107 }

108

109 /* The base priority gets set whatever. */

110 pxTCB->uxBasePriority = uxNewPriority;

111 }

112 #else /* if ( configUSE_MUTEXES == 1 ) */

113 {

114 pxTCB->uxPriority = uxNewPriority;

115 }

116 #endif /* if ( configUSE_MUTEXES == 1 ) */

117

118 /* Only reset the event list item value if the value is not

119 * being used for anything else. */

120 /* xEventListItem的值未被使用, 才允许更新这个值 */

121 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == ( ( TickType_t ) 0U ) )

122 {

123 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) );

124 }

125 else

126 {

127 mtCOVERAGE_TEST_MARKER();

128 }

129

130 /* If the task is in the blocked or suspended list we need do

131 * nothing more than change its priority variable. However, if

132 * the task is in a ready list it needs to be removed and placed

133 * in the list appropriate to its new priority. */

134 /* 如果任务处于就绪列表, 则需要将其放到修改后的优先级就绪列表 */

135 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )

136 {

137 /* The task is currently in its ready list - remove before

138 * adding it to its new ready list. As we are in a critical

139 * section we can do this even if the scheduler is suspended. */

140 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )

141 {

142 /* It is known that the task is in its ready list so

143 * there is no need to check again and the port level

144 * reset macro can be called directly. */

145 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );

146 }

147 else

148 {

149 mtCOVERAGE_TEST_MARKER();

150 }

151

152 prvAddTaskToReadyList( pxTCB );

153 }

154 else

155 {

156 #if ( configNUMBER_OF_CORES == 1 )

157 {

158 mtCOVERAGE_TEST_MARKER();

159 }

160 #endif

161 }

162

163 if( xYieldRequired != pdFALSE )

164 {

165 /* The running task priority is set down. Request the task to yield. */

166 /* 开始yield, 但是在退出临界区后才会进入sv中断? */

167 taskYIELD_TASK_CORE_IF_USING_PREEMPTION( pxTCB );

168 }

169 else

170 {

171 mtCOVERAGE_TEST_MARKER();

172 }

173

174 /* Remove compiler warning about unused variables when the port

175 * optimised task selection is not being used. */

176 ( void ) uxPriorityUsedOnEntry;

177 }

178 }

179 taskEXIT_CRITICAL();

180 }

vTaskPrioritySet

4.2.12 挂起任务--vTaskSuspend

还是直接看代码注释,解释得比较清楚了,接口功能可以顾名思义,逻辑也还好不复杂。

1 void vTaskSuspend( TaskHandle_t xTaskToSuspend )

2 {

3 TCB_t * pxTCB;

4

5 taskENTER_CRITICAL();

6 {

7 /* If null is passed in here then it is the running task that is

8 * being suspended. */

9 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );

10

11 /* Remove task from the ready/delayed list and place in the

12 * suspended list. */

13 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )

14 {

15 taskRESET_READY_PRIORITY( pxTCB->uxPriority );

16 }

17 else

18 {

19 mtCOVERAGE_TEST_MARKER();

20 }

21

22 /* Is the task waiting on an event also? */

23 /* 任务挂起, 任务就不管是否在等待事件 */

24 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )

25 {

26 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );

27 }

28 else

29 {

30 mtCOVERAGE_TEST_MARKER();

31 }

32

33 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );

34

35 /* 如果在等待通知, 也直接退出等待 */

36 #if ( configUSE_TASK_NOTIFICATIONS == 1 )

37 {

38 BaseType_t x;

39

40 for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )

41 {

42 if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )

43 {

44 /* The task was blocked to wait for a notification, but is

45 * now suspended, so no notification was received. */

46 pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;

47 }

48 }

49 }

50 #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */

51 }

52 taskEXIT_CRITICAL();

53

54 #if ( configNUMBER_OF_CORES == 1 )

55 {

56 UBaseType_t uxCurrentListLength;

57

58 if( xSchedulerRunning != pdFALSE )

59 {

60 /* Reset the next expected unblock time in case it referred to the

61 * task that is now in the Suspended state. */

62 /* 如果下个解除阻塞的时间对应的任务正好是挂起的任务,

63 * 无论如何重置一下下个解除阻塞的时间 */

64 taskENTER_CRITICAL();

65 {

66 prvResetNextTaskUnblockTime();

67 }

68 taskEXIT_CRITICAL();

69 }

70 else

71 {

72 mtCOVERAGE_TEST_MARKER();

73 }

74

75 if( pxTCB == pxCurrentTCB )

76 {

77 if( xSchedulerRunning != pdFALSE )

78 {

79 /* The current task has just been suspended. */

80 /* 当前运行的任务挂起, 需要yield */

81 configASSERT( uxSchedulerSuspended == 0 );

82 portYIELD_WITHIN_API();

83 }

84 else

85 {

86 /* The scheduler is not running, but the task that was pointed

87 * to by pxCurrentTCB has just been suspended and pxCurrentTCB

88 * must be adjusted to point to a different task. */

89

90 /* Use a temp variable as a distinct sequence point for reading

91 * volatile variables prior to a comparison to ensure compliance

92 * with MISRA C 2012 Rule 13.2. */

93 uxCurrentListLength = listCURRENT_LIST_LENGTH( &xSuspendedTaskList );

94

95 if( uxCurrentListLength == uxCurrentNumberOfTasks )

96 {

97 /* No other tasks are ready, so set pxCurrentTCB back to

98 * NULL so when the next task is created pxCurrentTCB will

99 * be set to point to it no matter what its relative priority

100 * is. */

101 /* 所有创建的任务处于挂起状态, 只能等新任务创建了 */

102 pxCurrentTCB = NULL;

103 }

104 else

105 {

106 /* 切换下上下文, 因为挂起的是当前任务, 也有可能就绪列表为空,

107 * 会导致pxCurrentTCB = idle, 否则会选择就绪列表中优先级最高

108 * 任务, 这个接口在这里只是设置了pxCurrentTCB参数, 并pend了

109 * yield, 因为当前调度器处于暂停状态 */

110 vTaskSwitchContext();

111 }

112 }

113 }

114 else

115 {

116 mtCOVERAGE_TEST_MARKER();

117 }

118 }

119 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */

120 }

vTaskSuspend

这篇就到这里了,内容也比较多,下篇开始vTaskResume和vTaskStartScheduler。

下篇再见!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。