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这些,应该会选一个举例,其他的可能就一笔带过了。
那么,下一篇再见。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。