蓝娅萍 发表于 2025-6-8 13:01:37

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

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 }eTaskGetState4.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                      * notslip, 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这些,应该会选一个举例,其他的可能就一笔带过了。
  那么,下一篇再见。
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: freeRTOS源码解析4--tasks.c 3