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

cnblogs 2024-09-30 08:15:00 阅读 73

4.2.14 退出阻塞--xTaskAbortDelay

接口:

BaseType_t xTaskAbortDelay( TaskHandle_t xTask )

形参1:xTask ,想要退出阻塞态的任务;

返回:pdPASS:退出成功;pdFAIL:退出失败。

1 BaseType_t xTaskAbortDelay( TaskHandle_t xTask )

2 {

3 TCB_t * pxTCB = xTask;

4 BaseType_t xReturn;

5

6 configASSERT( pxTCB );

7

8 vTaskSuspendAll();

9 {

10 /* A task can only be prematurely removed from the Blocked state if

11 * it is actually in the Blocked state. */

12 /* 任务只有真的在阻塞态才能提前移出阻塞态 */

13 if( eTaskGetState( xTask ) == eBlocked )

14 {

15 xReturn = pdPASS;

16

17 /* Remove the reference to the task from the blocked list. An

18 * interrupt won't touch the xStateListItem because the

19 * scheduler is suspended. */

20 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );

21

22 /* Is the task waiting on an event also? If so remove it from

23 * the event list too. Interrupts can touch the event list item,

24 * even though the scheduler is suspended, so a critical section

25 * is used. */

26 /* 如果任务在等待事件, 则移出事件列表, 因为调度器暂停时, 中断仍

27 * 能访问事件列表, 所以需要进入临界区 */

28 taskENTER_CRITICAL();

29 {

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

31 {

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

33

34 /* This lets the task know it was forcibly removed from the

35 * blocked state so it should not re-evaluate its block time and

36 * then block again. */

37 /* 让任务知道是被强制移出阻塞态的, 防止被重新计算阻塞时间再次进入

38 * 阻塞态 */

39 pxTCB->ucDelayAborted = ( uint8_t ) pdTRUE;

40 }

41 else

42 {

43 mtCOVERAGE_TEST_MARKER();

44 }

45 }

46 taskEXIT_CRITICAL();

47

48 /* Place the unblocked task into the appropriate ready list. */

49 prvAddTaskToReadyList( pxTCB );

50

51 /* A task being unblocked cannot cause an immediate context

52 * switch if preemption is turned off. */

53 #if ( configUSE_PREEMPTION == 1 )

54 {

55 #if ( configNUMBER_OF_CORES == 1 )

56 {

57 /* Preemption is on, but a context switch should only be

58 * performed if the unblocked task has a priority that is

59 * higher than the currently executing task. */

60 /* 比当前任务优先级高, 等调度器运行后, 需要进行yield */

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

62 {

63 /* Pend the yield to be performed when the scheduler

64 * is unsuspended. */

65 xYieldPendings[ 0 ] = pdTRUE;

66 }

67 else

68 {

69 mtCOVERAGE_TEST_MARKER();

70 }

71 }

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

73 }

74 #endif /* #if ( configUSE_PREEMPTION == 1 ) */

75 }

76 else

77 {

78 xReturn = pdFAIL;

79 }

80 }

81 ( void ) xTaskResumeAll();

82

83 return xReturn;

84 }

xTaskAbortDelay

这个接口主要就是强制将在阻塞态的任务变成就绪态。

4.2.15 系统滴答时钟处理--xTaskIncrementTick

接口:

BaseType_t xTaskIncrementTick( void )

返回:pdPASS:需要切换上下文;pdFAIL:不需要切换上下文。

接口代码如下:

1 BaseType_t xTaskIncrementTick( void )

2 {

3 TCB_t * pxTCB;

4 TickType_t xItemValue;

5 BaseType_t xSwitchRequired = pdFALSE;

6

7 /* Tick increment should occur on every kernel timer event. Core 0 has the

8 * responsibility to increment the tick, or increment the pended ticks if the

9 * scheduler is suspended. If pended ticks is greater than zero, the core that

10 * calls xTaskResumeAll has the responsibility to increment the tick. */

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

12 {

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

14 * block. */

15 const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;

16

17 /* Increment the RTOS tick, switching the delayed and overflowed

18 * delayed lists if it wraps to 0. */

19 xTickCount = xConstTickCount;

20

21 /* tick溢出了, 交换下delay列表 */

22 if( xConstTickCount == ( TickType_t ) 0U )

23 {

24 taskSWITCH_DELAYED_LISTS();

25 }

26 else

27 {

28 mtCOVERAGE_TEST_MARKER();

29 }

30

31 /* See if this tick has made a timeout expire. Tasks are stored in

32 * the queue in the order of their wake time - meaning once one task

33 * has been found whose block time has not expired there is no need to

34 * look any further down the list. */

35 /* 因为delay列表的项是按唤醒时间从小到大排序的, 所以遍历过程中一旦发现

36 * 任务唤醒时间没到, 就可以停止了 */

37 if( xConstTickCount >= xNextTaskUnblockTime )

38 {

39 for( ; ; )

40 {

41 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )

42 {

43 /* The delayed list is empty. Set xNextTaskUnblockTime

44 * to the maximum possible value so it is extremely

45 * unlikely that the

46 * if( xTickCount >= xNextTaskUnblockTime ) test will pass

47 * next time through. */

48 xNextTaskUnblockTime = portMAX_DELAY;

49 break;

50 }

51 else

52 {

53 /* The delayed list is not empty, get the value of the

54 * item at the head of the delayed list. This is the time

55 * at which the task at the head of the delayed list must

56 * be removed from the Blocked state. */

57 /* MISRA Ref 11.5.3 [Void pointer assignment] */

58 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */

59 /* coverity[misra_c_2012_rule_11_5_violation] */

60 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );

61 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );

62

63 if( xConstTickCount < xItemValue )

64 {

65 /* It is not time to unblock this item yet, but the

66 * item value is the time at which the task at the head

67 * of the blocked list must be removed from the Blocked

68 * state - so record the item value in

69 * xNextTaskUnblockTime. */

70 /* 这个任务未到唤醒时间, 但因为前面的都移出了, 所以这一定

71 * 是下次最近唤醒的时间, 记录下来 */

72 xNextTaskUnblockTime = xItemValue;

73 break;

74 }

75 else

76 {

77 mtCOVERAGE_TEST_MARKER();

78 }

79

80 /* It is time to remove the item from the Blocked state. */

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

82

83 /* Is the task waiting on an event also? If so remove

84 * it from the event list. */

85 /* 等待事件的话, 移出事件列表 */

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

87 {

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

89 }

90 else

91 {

92 mtCOVERAGE_TEST_MARKER();

93 }

94

95 /* Place the unblocked task into the appropriate ready

96 * list. */

97 prvAddTaskToReadyList( pxTCB );

98

99 /* A task being unblocked cannot cause an immediate

100 * context switch if preemption is turned off. */

101 #if ( configUSE_PREEMPTION == 1 )

102 {

103 #if ( configNUMBER_OF_CORES == 1 )

104 {

105 /* Preemption is on, but a context switch should

106 * only be performed if the unblocked task's

107 * priority is higher than the currently executing

108 * task.

109 * The case of equal priority tasks sharing

110 * processing time (which happens when both

111 * preemption and time slicing are on) is

112 * handled below.*/

113 /* 移出的任务优先级比当前运行的任务高, 需要上下文切换 */

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

115 {

116 xSwitchRequired = pdTRUE;

117 }

118 else

119 {

120 mtCOVERAGE_TEST_MARKER();

121 }

122 }

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

124 }

125 #endif /* #if ( configUSE_PREEMPTION == 1 ) */

126 }

127 }

128 }

129

130 /* Tasks of equal priority to the currently running task will share

131 * processing time (time slice) if preemption is on, and the application

132 * writer has not explicitly turned time slicing off. */

133 /* 相同优先级的任务用时间片运行, 每个时间片长是一个tick. 这里不用管更高

134 * 优先级的任务是否唤醒, 一是上面已经判断过了, 二是只是需要知道是否要上

135 * 下文切换, 这样判断就足够了, 在上下文切换的时候自然会选择合适的任务运行 */

136 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )

137 {

138 #if ( configNUMBER_OF_CORES == 1 )

139 {

140 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > 1U )

141 {

142 xSwitchRequired = pdTRUE;

143 }

144 else

145 {

146 mtCOVERAGE_TEST_MARKER();

147 }

148 }

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

150 }

151 #endif /* #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */

152

153 #if ( configUSE_TICK_HOOK == 1 )

154 {

155 /* Guard against the tick hook being called when the pended tick

156 * count is being unwound (when the scheduler is being unlocked). */

157 if( xPendedTicks == ( TickType_t ) 0 )

158 {

159 vApplicationTickHook();

160 }

161 else

162 {

163 mtCOVERAGE_TEST_MARKER();

164 }

165 }

166 #endif /* configUSE_TICK_HOOK */

167

168 #if ( configUSE_PREEMPTION == 1 )

169 {

170 #if ( configNUMBER_OF_CORES == 1 )

171 {

172 /* For single core the core ID is always 0. */

173 if( xYieldPendings[ 0 ] != pdFALSE )

174 {

175 xSwitchRequired = pdTRUE;

176 }

177 else

178 {

179 mtCOVERAGE_TEST_MARKER();

180 }

181 }

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

183 }

184 #endif /* #if ( configUSE_PREEMPTION == 1 ) */

185 }

186 else

187 {

188 /* 调度器处于暂停中, 在xTaskResumeAll接口中检查xPendedTicks的值,

189 * 并调用本接口处理tick值. */

190 xPendedTicks += 1U;

191

192 /* The tick hook gets called at regular intervals, even if the

193 * scheduler is locked. */

194 #if ( configUSE_TICK_HOOK == 1 )

195 {

196 vApplicationTickHook();

197 }

198 #endif

199 }

200

201 return xSwitchRequired;

202 }

xTaskIncrementTick

接口比较复杂,流程图就不贴了,太长。这个接口简单来讲就是如果调度器未停止,就检查每个阻塞的任务是否到了等待时间,包括本身延迟的时间和等待事件的超时时间,并加入到就绪列表中。

4.2.16 切换上下文--vTaskSwitchContext

切换上下文,主要作用是挑选出需要切换过去的任务。

接口:

void vTaskSwitchContext( void )

接口代码如下:

1 void vTaskSwitchContext( void )

2 {

3 if( uxSchedulerSuspended != ( UBaseType_t ) 0U )

4 {

5 /* The scheduler is currently suspended - do not allow a context

6 * switch. */

7 /* 调度器暂停时, 不允许上下文切换 */

8 xYieldPendings[ 0 ] = pdTRUE;

9 }

10 else

11 {

12 xYieldPendings[ 0 ] = pdFALSE;

13

14 /* Check for stack overflow, if configured. */

15 /* 就是检查当前栈的位置有没有超过栈顶位置 */

16 taskCHECK_FOR_STACK_OVERFLOW();

17

18 /* Before the currently running task is switched out, save its errno. */

19 #if ( configUSE_POSIX_ERRNO == 1 )

20 {

21 pxCurrentTCB->iTaskErrno = FreeRTOS_errno;

22 }

23 #endif

24

25 /* Select a new task to run using either the generic C or port

26 * optimised asm code. */

27 /* MISRA Ref 11.5.3 [Void pointer assignment] */

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

29 /* coverity[misra_c_2012_rule_11_5_violation] */

30 /* 选择就绪列表中优先级最高的任务 */

31 taskSELECT_HIGHEST_PRIORITY_TASK();

32

33 /* Macro to inject port specific behaviour immediately after

34 * switching tasks, such as setting an end of stack watchpoint

35 * or reconfiguring the MPU. */

36 portTASK_SWITCH_HOOK( pxCurrentTCB );

37

38 /* After the new task is switched in, update the global errno. */

39 #if ( configUSE_POSIX_ERRNO == 1 )

40 {

41 FreeRTOS_errno = pxCurrentTCB->iTaskErrno;

42 }

43 #endif

44 }

45 }

vTaskSwitchContext

最核心的就是“taskSELECT_HIGHEST_PRIORITY_TASK();”调用。

4.2.17 加入到事件列表--vTaskPlaceOnEventList

把当前任务放到事件列表中,主要用于队列的实现。

接口:

void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )

形参1:pxEventList,事件列表;

形参2:xTicksToWait ,最长等待时间。

接口代码如下:

1 void vTaskPlaceOnEventList( List_t * const pxEventList,

2 const TickType_t xTicksToWait )

3 {

4 configASSERT( pxEventList );

5

6 /* THIS FUNCTION MUST BE CALLED WITH THE

7 * SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */

8

9 /* Place the event list item of the TCB in the appropriate event list.

10 * This is placed in the list in priority order so the highest priority task

11 * is the first to be woken by the event.

12 *

13 * Note: Lists are sorted in ascending order by ListItem_t.xItemValue.

14 * Normally, the xItemValue of a TCB's ListItem_t members is:

15 * xItemValue = ( configMAX_PRIORITIES - uxPriority )

16 * Therefore, the event list is sorted in descending priority order.

17 *

18 * The queue that contains the event list is locked, preventing

19 * simultaneous access from interrupts. */

20 /* 将当前任务加入到事件列表, 列表是按升序存放的, 而一般情况下, 任务的

21 * xEventListItem的值是xItemValue=(configMAX_PRIORITIES-uxPriority),

22 * 所以事件列表是按优先级降序排列的 */

23 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );

24

25 /* 还需要放到延迟列表中, 用于最大延迟时间的唤醒 */

26 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );

27 }

vTaskPlaceOnEventList

4.2.18 加入到无序事件列表--vTaskPlaceOnUnorderedEventList

把当前任务放到无序的事件列表中,主要用于事件组。

接口:

void vTaskPlaceOnUnorderedEventList( List_t * pxEventList,const TickType_t xItemValue, const TickType_t xTicksToWait )

形参1:pxEventList,事件列表;

形参2:xItemValue,设置的值

形参3:xTicksToWait ,最长等待时间。

接口代码如下:

1 void vTaskPlaceOnUnorderedEventList( List_t * pxEventList,

2 const TickType_t xItemValue,

3 const TickType_t xTicksToWait )

4 {

5 configASSERT( pxEventList );

6

7 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by

8 * the event groups implementation. */

9 configASSERT( uxSchedulerSuspended != ( UBaseType_t ) 0U );

10

11 /* Store the item value in the event list item. It is safe to access the

12 * event list item here as interrupts won't access the event list item of a

13 * task that is not in the Blocked state. */

14 /* 中断只会访问处于Blocked态的事件列表项, 这里当前任务明显还未进入Blocked态 */

15 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );

16

17 /* Place the event list item of the TCB at the end of the appropriate event

18 * list. It is safe to access the event list here because it is part of an

19 * event group implementation - and interrupts don't access event groups

20 * directly (instead they access them indirectly by pending function calls to

21 * the task level). */

22 /* 主要是用于事件组的实现, 中断不会直接访问. 无序存放, 所以直接放在最后 */

23 listINSERT_END( pxEventList, &( pxCurrentTCB->xEventListItem ) );

24

25 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );

26 }

vTaskPlaceOnUnorderedEventList

4.2.19 移出事件列表--xTaskRemoveFromEventList

将当前任务从事件列表中移出,主要用于队列的实现。

接口:

BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )

形参1:pxEventList,事件列表;

返回值:pdTRUE:需要进行上下文切换;pdFALSE:不需要。

接口代码如下:

1 BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )

2 {

3 TCB_t * pxUnblockedTCB;

4 BaseType_t xReturn;

5

6 /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be

7 * called from a critical section within an ISR. */

8

9 /* The event list is sorted in priority order, so the first in the list can

10 * be removed as it is known to be the highest priority. Remove the TCB from

11 * the delayed list, and add it to the ready list.

12 *

13 * If an event is for a queue that is locked then this function will never

14 * get called - the lock count on the queue will get modified instead. This

15 * means exclusive access to the event list is guaranteed here.

16 *

17 * This function assumes that a check has already been made to ensure that

18 * pxEventList is not empty. */

19 /* MISRA Ref 11.5.3 [Void pointer assignment] */

20 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */

21 /* coverity[misra_c_2012_rule_11_5_violation] */

22 /* 按优先级降序存放的, 所以头部是优先级最高的任务 */

23 pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList );

24 configASSERT( pxUnblockedTCB );

25 listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) );

26

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

28 {

29 listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) );

30 prvAddTaskToReadyList( pxUnblockedTCB );

31

32 #if ( configUSE_TICKLESS_IDLE != 0 )

33 {

34 /* If a task is blocked on a kernel object then xNextTaskUnblockTime

35 * might be set to the blocked task's time out time. If the task is

36 * unblocked for a reason other than a timeout xNextTaskUnblockTime is

37 * normally left unchanged, because it is automatically reset to a new

38 * value when the tick count equals xNextTaskUnblockTime. However if

39 * tickless idling is used it might be more important to enter sleep mode

40 * at the earliest possible time - so reset xNextTaskUnblockTime here to

41 * ensure it is updated at the earliest possible time. */

42 /* 重置最近唤醒时间 */

43 prvResetNextTaskUnblockTime();

44 }

45 #endif

46 }

47 else

48 {

49 /* The delayed and ready lists cannot be accessed, so hold this task

50 * pending until the scheduler is resumed. */

51 /* 调度器暂停, 不能访问延迟和就绪列表, 需要放到pend列表里 */

52 listINSERT_END( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );

53 }

54

55 #if ( configNUMBER_OF_CORES == 1 )

56 {

57 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )

58 {

59 /* Return true if the task removed from the event list has a higher

60 * priority than the calling task. This allows the calling task to know if

61 * it should force a context switch now. */

62 /* 取出任务的优先级更高, 需要进行上下文切换 */

63 xReturn = pdTRUE;

64

65 /* Mark that a yield is pending in case the user is not using the

66 * "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */

67 xYieldPendings[ 0 ] = pdTRUE;

68 }

69 else

70 {

71 xReturn = pdFALSE;

72 }

73 }

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

75

76 return xReturn;

77 }

xTaskRemoveFromEventList

16~19都比较简单,这里就简单过一下,下一篇学习空闲任务究竟做了什么事情以及它调用的几个小接口。

下篇再见。


上一篇: 2024072100-idea配置tomcat

下一篇: 运算符、分支语句

本文标签

task    freeRTOS源码解析    freeRTOS   


声明

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