freeRTOS源码解析4--task.c 3

cnblogs 2024-09-09 08:15:00 阅读 71

4.2.6 任务删除--vTaskDelete

这个接口并不复杂,主要是在判断是否要放到xTasksWaitingTermination列表里,还是直接处理。

1 void vTaskDelete( TaskHandle_t xTaskToDelete )

2 {

3 TCB_t * pxTCB;

4 BaseType_t xDeleteTCBInIdleTask = pdFALSE;

5 BaseType_t xTaskIsRunningOrYielding;

6

7 taskENTER_CRITICAL();

8 {

9 /* If null is passed in here then it is the calling task that is

10 * being deleted. */

11 /* 如果是NULL就是删除自己,否则是删除其他任务 */

12 pxTCB = prvGetTCBFromHandle( xTaskToDelete );

13

14 /* Remove task from the ready/delayed list. */

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

16 {

17 taskRESET_READY_PRIORITY( pxTCB->uxPriority );

18 }

19 else

20 {

21 mtCOVERAGE_TEST_MARKER();

22 }

23

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

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

26 {

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

28 }

29 else

30 {

31 mtCOVERAGE_TEST_MARKER();

32 }

33

34 /* Increment the uxTaskNumber also so kernel aware debuggers can

35 * detect that the task lists need re-generating. This is done before

36 * portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will

37 * not return. */

38 /* 这个变量是用于TRACE相关的,调试用的,先不管,以后看trace的代码再解析 */

39 uxTaskNumber++;

40

41 /* Use temp variable as distinct sequence points for reading volatile

42 * variables prior to a logical operator to ensure compliance with

43 * MISRA C 2012 Rule 13.5. */

44 /* 确定是否正在运行或正在调度到这个任务 */

45 xTaskIsRunningOrYielding = taskTASK_IS_RUNNING_OR_SCHEDULED_TO_YIELD( pxTCB );

46

47 /* If the task is running (or yielding), we must add it to the

48 * termination list so that an idle task can delete it when it is

49 * no longer running. */

50 if( ( xSchedulerRunning != pdFALSE ) && ( xTaskIsRunningOrYielding != pdFALSE ) )

51 {

52 /* A running task or a task which is scheduled to yield is being

53 * deleted. This cannot complete when the task is still running

54 * on a core, as a context switch to another task is required.

55 * Place the task in the termination list. The idle task will check

56 * the termination list and free up any memory allocated by the

57 * scheduler for the TCB and stack of the deleted task. */

58 /* 看注释,不放到终止列表中,无法删除。需要依赖空闲任务来处理

59 * 具体原因暂时还不清楚,看来需要阅读更多源码才能明白。 */

60 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );

61

62 /* Increment the ucTasksDeleted variable so the idle task knows

63 * there is a task that has been deleted and that it should therefore

64 * check the xTasksWaitingTermination list. */

65 ++uxDeletedTasksWaitingCleanUp;

66

67 /* Delete the task TCB in idle task. */

68 xDeleteTCBInIdleTask = pdTRUE;

69

70 /* The pre-delete hook is primarily for the Windows simulator,

71 * in which Windows specific clean up operations are performed,

72 * after which it is not possible to yield away from this task -

73 * hence xYieldPending is used to latch that a context switch is

74 * required. */

75 /* 只有在Windows下才有用,先不分析了 */

76 #if ( configNUMBER_OF_CORES == 1 )

77 portPRE_TASK_DELETE_HOOK( pxTCB, &( xYieldPendings[ 0 ] ) );

78 #endif

79 }

80 else

81 {

82 /* 这里是删除阻塞任务(pxDelayedTaskList)的(xTaskIsRunningOrYielding = pdFALSE) */

83 --uxCurrentNumberOfTasks;

84

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

86 * the task that has just been deleted. */

87 /* 主要用于更新最久阻塞的剩余阻塞时间,防止最近需要运行的就是删除的这个任务 */

88 prvResetNextTaskUnblockTime();

89 }

90 }

91 taskEXIT_CRITICAL();

92

93 /* If the task is not deleting itself, call prvDeleteTCB from outside of

94 * critical section. If a task deletes itself, prvDeleteTCB is called

95 * from prvCheckTasksWaitingTermination which is called from Idle task. */

96 /* 如果删除的是当前运行的任务在空闲任务中处理,阻塞任务在这里处理 */

97 if( xDeleteTCBInIdleTask != pdTRUE )

98 {

99 prvDeleteTCB( pxTCB );

100 }

101

102 /* Force a reschedule if it is the currently running task that has just

103 * been deleted. */

104 /* 如果删除的是当前运行的任务,需要调度,这很明显。 */

105 #if ( configNUMBER_OF_CORES == 1 )

106 {

107 if( xSchedulerRunning != pdFALSE )

108 {

109 if( pxTCB == pxCurrentTCB )

110 {

111 configASSERT( uxSchedulerSuspended == 0 );

112 taskYIELD_WITHIN_API();

113 }

114 else

115 {

116 mtCOVERAGE_TEST_MARKER();

117 }

118 }

119 }

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

121 }

vTaskDelete

1 static void prvDeleteTCB( TCB_t * pxTCB )

2 {

3 #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )

4 {

5 /* The task can only have been allocated dynamically - free both

6 * the stack and TCB. */

7 vPortFreeStack( pxTCB->pxStack );

8 vPortFree( pxTCB );

9 }

10 #elif ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )

11 {

12 /* The task could have been allocated statically or dynamically, so

13 * check what was statically allocated before trying to free the

14 * memory. */

15 /* 按需释放tcb和stack */

16 if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )

17 {

18 /* Both the stack and TCB were allocated dynamically, so both

19 * must be freed. */

20 vPortFreeStack( pxTCB->pxStack );

21 vPortFree( pxTCB );

22 }

23 else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )

24 {

25 /* Only the stack was statically allocated, so the TCB is the

26 * only memory that must be freed. */

27 vPortFree( pxTCB );

28 }

29 else

30 {

31 /* Neither the stack nor the TCB were allocated dynamically, so

32 * nothing needs to be freed. */

33 configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB );

34 mtCOVERAGE_TEST_MARKER();

35 }

36 }

37 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */

38 }

prvDeleteTCB

4.2.7 获取任务状态--eTaskGetState

这个接口可以大致看出任务在哪些情况下会处于什么状态。

首先是返回值的说明:

1 typedef enum

2 {

3 eRunning = 0, /* 运行态. */

4 eReady, /* 就绪态, 任务在 ready or pending ready 列表. */

5 eBlocked, /* 阻塞态. */

6 eSuspended, /* 挂起态, 任务在 挂起列表, 或处于无限延迟的阻塞中. */

7 eDeleted, /* 等待删除. */

8 eInvalid /* Used as an 'invalid state' value. */

9 } eTaskState;

1 eTaskState eTaskGetState( TaskHandle_t xTask )

2 {

3 eTaskState eReturn;

4 List_t const * pxStateList;

5 List_t const * pxEventList;

6 List_t const * pxDelayedList;

7 List_t const * pxOverflowedDelayedList;

8 const TCB_t * const pxTCB = xTask;

9

10 configASSERT( pxTCB );

11

12 #if ( configNUMBER_OF_CORES == 1 )

13 if( pxTCB == pxCurrentTCB )

14 {

15 /* The task calling this function is querying its own state. */

16 /* 当前任务是查询的任务,则处于运行态 */

17 eReturn = eRunning;

18 }

19 else

20 #endif

21 {

22 taskENTER_CRITICAL();

23 {

24 pxStateList = listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) );

25 pxEventList = listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) );

26 pxDelayedList = pxDelayedTaskList;

27 pxOverflowedDelayedList = pxOverflowDelayedTaskList;

28 }

29 taskEXIT_CRITICAL();

30

31 if( pxEventList == &xPendingReadyList )

32 {

33 /* The task has been placed on the pending ready list, so its

34 * state is eReady regardless of what list the task's state list

35 * item is currently placed on. */

36 /* 任务的事件项处于xPendingReadyList中就是就绪态

37 * 说明xPendingReadyList里放的是任务的xEventListItem

38 * 调度器挂起时,任务已ready,调度器运行后,

39 * 会将xPendingReadyList中的任务移至就绪列表中 */

40 eReturn = eReady;

41 }

42 else if( ( pxStateList == pxDelayedList ) || ( pxStateList == pxOverflowedDelayedList ) )

43 {

44 /* The task being queried is referenced from one of the Blocked

45 * lists. */

46 /* pxDelayedTaskList和pxOverflowDelayedTaskList放的是阻塞任务,xStateListItem */

47 eReturn = eBlocked;

48 }

49

50 #if ( INCLUDE_vTaskSuspend == 1 )

51 /* xSuspendedTaskList放的是挂起的任务,xStateListItem */

52 else if( pxStateList == &xSuspendedTaskList )

53 {

54 /* The task being queried is referenced from the suspended

55 * list. Is it genuinely suspended or is it blocked

56 * indefinitely? */

57 /* xEventListItem不在任何列表里 */

58 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )

59 {

60 #if ( configUSE_TASK_NOTIFICATIONS == 1 )

61 {

62 BaseType_t x;

63

64 /* The task does not appear on the event list item of

65 * and of the RTOS objects, but could still be in the

66 * blocked state if it is waiting on its notification

67 * rather than waiting on an object. If not, is

68 * suspended. */

69 /* 说明等通知不是把xEventListItem放到某个列表里,

70 * 而且等通知会把任务放到挂起的列表里 */

71 eReturn = eSuspended;

72

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

74 {

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

76 {

77 eReturn = eBlocked;

78 break;

79 }

80 }

81 }

82 #else /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */

83 {

84 eReturn = eSuspended;

85 }

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

87 }

88 else

89 {

90 /* 如果xStateListItem在挂起列表里且xEventListItem处于某个列表里,则任务会阻塞 */

91 eReturn = eBlocked;

92 }

93 }

94 #endif /* if ( INCLUDE_vTaskSuspend == 1 ) */

95

96 #if ( INCLUDE_vTaskDelete == 1 )

97 else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) )

98 {

99 /* The task being queried is referenced from the deleted

100 * tasks list, or it is not referenced from any lists at

101 * all. */

102 /* 等着被删除,这很明显 */

103 eReturn = eDeleted;

104 }

105 #endif

106

107 else

108 {

109 #if ( configNUMBER_OF_CORES == 1 )

110 {

111 /* If the task is not in any other state, it must be in the

112 * Ready (including pending ready) state. */

113 /* 剩下的就只能是在就绪列表里(pxReadyTasksLists)

114 * pxReadyTasksLists是个列表数组,通过排除法,可以

115 * 免于进行遍历操作。 */

116 eReturn = eReady;

117 }

118 #else /* #if ( configNUMBER_OF_CORES == 1 ) */

119 {

120 if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )

121 {

122 /* Is it actively running on a core? */

123 eReturn = eRunning;

124 }

125 else

126 {

127 /* If the task is not in any other state, it must be in the

128 * Ready (including pending ready) state. */

129 eReturn = eReady;

130 }

131 }

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

133 }

134 }

135

136 /* 简单总结下:xStateListItem会在pxDelayedTaskList、pxOverflowDelayedTaskList、

137 * xSuspendedTaskList和xTasksWaitingTermination里

138 * xEventListItem会在xPendingReadyList里。

139 * 简单分析就是事件、通知来了任务就放到xPendingReadyList里,其他情况就在其他列表里

140 * 具体是不是这样,看后面的源码,会逐渐清晰 */

141

142 return eReturn;

143 }

eTaskGetState

4.2.8 任务延迟,释放CPU--vTaskDelay

这个接口比较熟悉,至少是任务中最常用的接口了。但是正如接口的注释所说的那样,这个接口不提供准确的延迟时间,任务唤醒的周期会受中断、其他任务的影响,并且计时起始于这个接口开始被调用的时候,且时间是大于等于给予的延迟时间。如果想要准确的周期性的任务,那就要调用xTaskDelayUntil接口,这个会在后面讲到。

1 void vTaskDelay( const TickType_t xTicksToDelay )

2 {

3 BaseType_t xAlreadyYielded = pdFALSE;

4

5 /* A delay time of zero just forces a reschedule. */

6 /* 如果延迟tick为0, 则表示强制执行调度 */

7 if( xTicksToDelay > ( TickType_t ) 0U )

8 {

9 vTaskSuspendAll(); // 停止调度器

10 {

11 configASSERT( uxSchedulerSuspended == 1U );

12

13 /* A task that is removed from the event list while the

14 * scheduler is suspended will not get placed in the ready

15 * list or removed from the blocked list until the scheduler

16 * is resumed.

17 *

18 * This task cannot be in an event list as it is the currently

19 * executing task. */

20 /* 在调度器暂停时, 从事件列表中删除的任务将不会被放置在就绪列表中

21 * 或从阻塞列表中删除, 直到调度器恢复。此任务不可能在事件列表中,

22 * 因为它是当前正在执行的任务。 */

23 prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );

24 }

25 xAlreadyYielded = xTaskResumeAll();

26 }

27 else

28 {

29 mtCOVERAGE_TEST_MARKER();

30 }

31

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

33 * have put ourselves to sleep. */

34 /* xTaskResumeAll没有调度, 那在这里手动调度 */

35 if( xAlreadyYielded == pdFALSE )

36 {

37 taskYIELD_WITHIN_API();

38 }

39 else

40 {

41 mtCOVERAGE_TEST_MARKER();

42 }

43 }

44

45 void vTaskSuspendAll( void )

46 {

47 #if ( configNUMBER_OF_CORES == 1 )

48 {

49 /* A critical section is not required as the variable is of type

50 * BaseType_t. Please read Richard Barry's reply in the following link to a

51 * post in the FreeRTOS support forum before reporting this as a bug! -

52 * https://goo.gl/wu4acr */

53

54 /* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that

55 * do not otherwise exhibit real time behaviour. */

56 portSOFTWARE_BARRIER();

57

58 /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment

59 * is used to allow calls to vTaskSuspendAll() to nest. */

60 /* uxSchedulerSuspended非0, 则调度器暂停, 加1是为了嵌套调用(中断也调用) */

61 uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended + 1U );

62

63 /* Enforces ordering for ports and optimised compilers that may otherwise place

64 * the above increment elsewhere. */

65 portMEMORY_BARRIER();

66 }

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

68 }

69

70 static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,

71 const BaseType_t xCanBlockIndefinitely )

72 {

73 TickType_t xTimeToWake;

74 const TickType_t xConstTickCount = xTickCount;

75 List_t * const pxDelayedList = pxDelayedTaskList;

76 List_t * const pxOverflowDelayedList = pxOverflowDelayedTaskList;

77

78 #if ( INCLUDE_xTaskAbortDelay == 1 )

79 {

80 /* About to enter a delayed list, so ensure the ucDelayAborted flag is

81 * reset to pdFALSE so it can be detected as having been set to pdTRUE

82 * when the task leaves the Blocked state. */

83 pxCurrentTCB->ucDelayAborted = ( uint8_t ) pdFALSE;

84 }

85 #endif

86

87 /* Remove the task from the ready list before adding it to the blocked list

88 * as the same list item is used for both lists. */

89 /* 将当前任务移出的列表必然是就绪列表, 移出后的就绪列表的item数量为0, 表示

90 * 就绪列表为空了, 需要重置下uxTopReadyPriority */

91 if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )

92 {

93 /* The current task must be in a ready list, so there is no need to

94 * check, and the port reset macro can be called directly. */

95 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );

96 }

97 else

98 {

99 mtCOVERAGE_TEST_MARKER();

100 }

101

102 #if ( INCLUDE_vTaskSuspend == 1 )

103 {

104 if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )

105 {

106 /* Add the task to the suspended task list instead of a delayed task

107 * list to ensure it is not woken by a timing event. It will block

108 * indefinitely. */

109 /* 无限等待, 就加入到挂起列表里 */

110 listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );

111 }

112 else

113 {

114 /* Calculate the time at which the task should be woken if the event

115 * does not occur. This may overflow but this doesn't matter, the

116 * kernel will manage it correctly. */

117 /* 计算延迟结束的tick */

118 xTimeToWake = xConstTickCount + xTicksToWait;

119

120 /* The list item will be inserted in wake time order. */

121 /* 说明xStateListItem的项里的值, 放的是wake的时间点 */

122 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

123

124 if( xTimeToWake < xConstTickCount )

125 {

126 /* Wake time has overflowed. Place this item in the overflow

127 * list. */

128 /* 处理数值溢出的情况, 说明wake的tick值溢出的话, 任务就在pxOverflowDelayedTaskList

129 * 列表里, 这是freeRTOS处理tick溢出的方式, 即用两个delay列表交替使用来处理 */

130 traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();

131 vListInsert( pxOverflowDelayedList, &( pxCurrentTCB->xStateListItem ) );

132 }

133 else

134 {

135 /* The wake time has not overflowed, so the current block list

136 * is used. */

137 /* 没溢出就放到pxDelayedTaskList列表里, 一般一旦有溢出, 后面的任务

138 * 都是处于溢出的情况, 一旦tick加到0了, 就会交换pxDelayedTaskList

139 * 和pxOverflowDelayedTaskList指向的列表, 这样就解决了溢出的问题 */

140 traceMOVED_TASK_TO_DELAYED_LIST();

141 vListInsert( pxDelayedList, &( pxCurrentTCB->xStateListItem ) );

142

143 /* If the task entering the blocked state was placed at the

144 * head of the list of blocked tasks then xNextTaskUnblockTime

145 * needs to be updated too. */

146 /* 更新最近唤醒任务的时间 */

147 if( xTimeToWake < xNextTaskUnblockTime )

148 {

149 xNextTaskUnblockTime = xTimeToWake;

150 }

151 else

152 {

153 mtCOVERAGE_TEST_MARKER();

154 }

155 }

156 }

157 }

158 #endif /* INCLUDE_vTaskSuspend */

159 }

vTaskDelay

vTaskDelay的流程图如下。

接着是vTaskDelay调用的几个接口,除了xTaskIncrementTick接口没有放进来,这个接口比较重要和复杂,后面专门会进行解析。

4.2.8.1 将当前任务加入到延迟列表--prvAddCurrentTaskToDelayedList

1 static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,

2 const BaseType_t xCanBlockIndefinitely )

3 {

4 TickType_t xTimeToWake;

5 const TickType_t xConstTickCount = xTickCount;

6 List_t * const pxDelayedList = pxDelayedTaskList;

7 List_t * const pxOverflowDelayedList = pxOverflowDelayedTaskList;

8

9 #if ( INCLUDE_xTaskAbortDelay == 1 )

10 {

11 /* About to enter a delayed list, so ensure the ucDelayAborted flag is

12 * reset to pdFALSE so it can be detected as having been set to pdTRUE

13 * when the task leaves the Blocked state. */

14 pxCurrentTCB->ucDelayAborted = ( uint8_t ) pdFALSE;

15 }

16 #endif

17

18 /* Remove the task from the ready list before adding it to the blocked list

19 * as the same list item is used for both lists. */

20 /* 将当前任务移出的列表必然是就绪列表, 移出后的就绪列表的item数量为0, 表示

21 * 就绪列表为空了, 需要重置下uxTopReadyPriority */

22 if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )

23 {

24 /* The current task must be in a ready list, so there is no need to

25 * check, and the port reset macro can be called directly. */

26 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );

27 }

28 else

29 {

30 mtCOVERAGE_TEST_MARKER();

31 }

32

33 #if ( INCLUDE_vTaskSuspend == 1 )

34 {

35 if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )

36 {

37 /* Add the task to the suspended task list instead of a delayed task

38 * list to ensure it is not woken by a timing event. It will block

39 * indefinitely. */

40 /* 无限等待, 就加入到挂起列表里 */

41 listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );

42 }

43 else

44 {

45 /* Calculate the time at which the task should be woken if the event

46 * does not occur. This may overflow but this doesn't matter, the

47 * kernel will manage it correctly. */

48 /* 计算延迟结束的tick */

49 xTimeToWake = xConstTickCount + xTicksToWait;

50

51 /* The list item will be inserted in wake time order. */

52 /* 说明xStateListItem的项里的值, 放的是wake的时间点 */

53 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

54

55 if( xTimeToWake < xConstTickCount )

56 {

57 /* Wake time has overflowed. Place this item in the overflow

58 * list. */

59 /* 处理数值溢出的情况, 说明wake的tick值溢出的话, 任务就在pxOverflowDelayedTaskList

60 * 列表里, 这是freeRTOS处理tick溢出的方式, 即用两个delay列表交替使用来处理 */

61 traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();

62 vListInsert( pxOverflowDelayedList, &( pxCurrentTCB->xStateListItem ) );

63 }

64 else

65 {

66 /* The wake time has not overflowed, so the current block list

67 * is used. */

68 /* 没溢出就放到pxDelayedTaskList列表里, 一般一旦有溢出, 后面的任务

69 * 都是处于溢出的情况, 一旦tick加到0了, 就会交换pxDelayedTaskList

70 * 和pxOverflowDelayedTaskList指向的列表, 这样就解决了溢出的问题 */

71 traceMOVED_TASK_TO_DELAYED_LIST();

72 vListInsert( pxDelayedList, &( pxCurrentTCB->xStateListItem ) );

73

74 /* If the task entering the blocked state was placed at the

75 * head of the list of blocked tasks then xNextTaskUnblockTime

76 * needs to be updated too. */

77 /* 更新最近唤醒任务的时间 */

78 if( xTimeToWake < xNextTaskUnblockTime )

79 {

80 xNextTaskUnblockTime = xTimeToWake;

81 }

82 else

83 {

84 mtCOVERAGE_TEST_MARKER();

85 }

86 }

87 }

88 }

89 #endif /* INCLUDE_vTaskSuspend */

90 }

prvAddCurrentTaskToDelayedList

4.2.8.2 停止所有任务(停止调度器)--vTaskSuspendAll

1 void vTaskSuspendAll( void )

2 {

3 #if ( configNUMBER_OF_CORES == 1 )

4 {

5 /* A critical section is not required as the variable is of type

6 * BaseType_t. Please read Richard Barry's reply in the following link to a

7 * post in the FreeRTOS support forum before reporting this as a bug! -

8 * https://goo.gl/wu4acr */

9

10 /* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that

11 * do not otherwise exhibit real time behaviour. */

12 portSOFTWARE_BARRIER();

13

14 /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment

15 * is used to allow calls to vTaskSuspendAll() to nest. */

16 /* uxSchedulerSuspended非0, 则调度器暂停, 加1是为了嵌套调用(中断也调用) */

17 uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended + 1U );

18

19 /* Enforces ordering for ports and optimised compilers that may otherwise place

20 * the above increment elsewhere. */

21 portMEMORY_BARRIER();

22 }

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

24 }

vTaskSuspendAll

4.2.8.3 继续所有任务(继续调度器)--xTaskResumeAll

这个接口返回的是否已经调度过。

1 BaseType_t xTaskResumeAll( void )

2 {

3 TCB_t * pxTCB = NULL;

4 BaseType_t xAlreadyYielded = pdFALSE;

5

6 {

7 /* It is possible that an ISR caused a task to be removed from an event

8 * list while the scheduler was suspended. If this was the case then the

9 * removed task will have been added to the xPendingReadyList. Once the

10 * scheduler has been resumed it is safe to move all the pending ready

11 * tasks from this list into their appropriate ready list. */

12 taskENTER_CRITICAL();

13 {

14 BaseType_t xCoreID;

15 xCoreID = ( BaseType_t ) portGET_CORE_ID(); // 单核默认返回0

16

17 /* If uxSchedulerSuspended is zero then this function does not match a

18 * previous call to vTaskSuspendAll(). */

19 /* vTaskSuspendAll和xTaskResumeAll成对调用, 所以前面必然是调用过了

20 * vTaskSuspendAll, 那么uxSchedulerSuspended必然大于0的 */

21 configASSERT( uxSchedulerSuspended != 0U );

22

23 uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended - 1U );

24 portRELEASE_TASK_LOCK();

25

26 if( uxSchedulerSuspended == ( UBaseType_t ) 0U )

27 {

28 if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )

29 {

30 /* Move any readied tasks from the pending list into the

31 * appropriate ready list. */

32 /* 为什么是xPendingReadyList, 因为调用vTaskSuspendAll后调度器暂停了,

33 * 如果在调用本接口前(本接口会进入临界区, 临界区会禁止所有系统中断)

34 * 有任务就绪了(中断、事件、通知等), 就会把任务放xPendingReadyList列表里 */

35 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )

36 {

37 /* 把xPendingReadyList里的所有任务一个一个放到就绪列表中 */

38 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );

39 listREMOVE_ITEM( &( pxTCB->xEventListItem ) );

40 portMEMORY_BARRIER();

41 listREMOVE_ITEM( &( pxTCB->xStateListItem ) );

42 prvAddTaskToReadyList( pxTCB );

43

44 #if ( configNUMBER_OF_CORES == 1 )

45 {

46 /* If the moved task has a priority higher than the current

47 * task then a yield must be performed. */

48 /* 如果取出来的任务有优先级比当前任务高的, 就需要调度, 先置标志位 */

49 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )

50 {

51 xYieldPendings[ xCoreID ] = pdTRUE;

52 }

53 else

54 {

55 mtCOVERAGE_TEST_MARKER();

56 }

57 }

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

59 }

60

61 if( pxTCB != NULL )

62 {

63 /* A task was unblocked while the scheduler was suspended,

64 * which may have prevented the next unblock time from being

65 * re-calculated, in which case re-calculate it now. Mainly

66 * important for low power tickless implementations, where

67 * this can prevent an unnecessary exit from low power

68 * state. */

69 /* 任务在调度器暂停时解除阻塞, 立即计算可以防止下一个解除阻塞

70 * 时间被重新计算, 这对于低功耗无障碍实现非常重要,因为这可以

71 * 防止不必要地退出低功耗 */

72 prvResetNextTaskUnblockTime();

73 }

74

75 /* If any ticks occurred while the scheduler was suspended then

76 * they should be processed now. This ensures the tick count does

77 * not slip, and that any delayed tasks are resumed at the correct

78 * time.

79 *

80 * It should be safe to call xTaskIncrementTick here from any core

81 * since we are in a critical section and xTaskIncrementTick itself

82 * protects itself within a critical section. Suspending the scheduler

83 * from any core causes xTaskIncrementTick to increment uxPendedCounts. */

84 /* 在调度器停止的时候, tick增加是增加xPendedTicks这个值, 在这里恢复调度器

85 * 的时候需要把这些增加的xPendedTicks值处理掉, 在临界区调用xTaskIncrementTick

86 * 是安全的, 至于为什么在解析xTaskIncrementTick后应该会清楚 */

87 {

88 TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */

89

90 if( xPendedCounts > ( TickType_t ) 0U )

91 {

92 do

93 {

94 if( xTaskIncrementTick() != pdFALSE )

95 {

96 /* Other cores are interrupted from

97 * within xTaskIncrementTick(). */

98 xYieldPendings[ xCoreID ] = pdTRUE;

99 }

100 else

101 {

102 mtCOVERAGE_TEST_MARKER();

103 }

104

105 --xPendedCounts;

106 } while( xPendedCounts > ( TickType_t ) 0U );

107

108 xPendedTicks = 0;

109 }

110 else

111 {

112 mtCOVERAGE_TEST_MARKER();

113 }

114 }

115

116 /* 需要调度的话, 这里立即开始调度(实际应该是

117 * 等退出临界区后进入pendSV中断), 我暂时也不确定,

118 * 等有空了仿真调式看看 */

119 if( xYieldPendings[ xCoreID ] != pdFALSE )

120 {

121 #if ( configUSE_PREEMPTION != 0 )

122 {

123 xAlreadyYielded = pdTRUE;

124 }

125 #endif /* #if ( configUSE_PREEMPTION != 0 ) */

126

127 #if ( configNUMBER_OF_CORES == 1 )

128 {

129 taskYIELD_TASK_CORE_IF_USING_PREEMPTION( pxCurrentTCB );

130 }

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

132 }

133 else

134 {

135 mtCOVERAGE_TEST_MARKER();

136 }

137 }

138 }

139 else

140 {

141 mtCOVERAGE_TEST_MARKER();

142 }

143 }

144 taskEXIT_CRITICAL();

145 }

146

147 return xAlreadyYielded;

148 }

xTaskResumeAll

这篇就解析到这里,里面有不少遗留的问题,相信在逐步解析的过程中会慢慢解决的。下一篇开始解析xTaskDelayUntil和vTaskPrioritySet等接口,一些简单的接口如uxTaskBasePriorityGet这些,应该会选一个举例,其他的可能就一笔带过了。

那么,下一篇再见。



声明

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