zl程序教程

您现在的位置是:首页 >  其他

当前栏目

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

2023-04-18 12:31:50 时间

4、task.c解析

task.c中包含任务创建、任务调度、delay等等接口,很多需要仿真才能弄清楚里面的机制,文章里只能尽可能详细地描述每一个流程。

4.1 宏和数据结构

源码中有涉及的几个宏和数据结构需要先说明一下,其中几个宏是之前讲链表时遗漏的,在这里再补充一下。

4.1.1 链表中遗漏的宏

 1 // 设置链表项的持有者
 2 #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )    ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
 3 // 获取链表项的持有者
 4 #define listGET_LIST_ITEM_OWNER( pxListItem )             ( ( pxListItem )->pvOwner )
 5 // 设置链表项的值
 6 #define listSET_LIST_ITEM_VALUE( pxListItem, xValue )     ( ( pxListItem )->xItemValue = ( xValue ) )
 7 // 获取链表项的值
 8 #define listGET_LIST_ITEM_VALUE( pxListItem )             ( ( pxListItem )->xItemValue )
 9 // 获取链表的第一项的值
10 #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )        ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
11 // 获取链表的第一项
12 #define listGET_HEAD_ENTRY( pxList )                      ( ( ( pxList )->xListEnd ).pxNext )
13 // 获取链表项的下一项
14 #define listGET_NEXT( pxListItem )                        ( ( pxListItem )->pxNext )
15 // 获取链表用于标记尾部的项
16 #define listGET_END_MARKER( pxList )                      ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
17 // 该链表是否为空
18 #define listLIST_IS_EMPTY( pxList )                       ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
19 // 该链表的总项数
20 #define listCURRENT_LIST_LENGTH( pxList )                 ( ( pxList )->uxNumberOfItems )
21 // 获取链表的第一项的持有者
22 #define listGET_OWNER_OF_HEAD_ENTRY( pxList )            ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
23 // 该链表是否持有此项
24 #define listIS_CONTAINED_WITHIN( pxList, pxListItem )    ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
25 // 获取持有该链表项的链表
26 #define listLIST_ITEM_CONTAINER( pxListItem )            ( ( pxListItem )->pxContainer )
27 // 该链表是否已初始化
28 #define listLIST_IS_INITIALISED( pxList )                ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )

4.1.2 TCB结构体

下面的结构体经过简化以后的样子,去除的那些成员变量在需要使用的时候再去理解就可以,这里先把最基础和常用的几个放出来。

 

 

 1 typedef struct tskTaskControlBlock
 2 {
 3     /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
 4     /* 指向放在任务栈上的最后一项的位置。这必须是TCB结构的第一个成员。 */
 5     volatile StackType_t * pxTopOfStack;
 6 
 7     /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
 8     /* 任务的状态链表项,表示该任务的状态(就绪、阻塞、挂起)。 */
 9     ListItem_t xStateListItem;
10     /*< Used to reference a task from an event list. */
11     /* 任务的事件链表项。 */
12     ListItem_t xEventListItem;
13     /*< The priority of the task.  0 is the lowest priority. */
14     /* 任务的优先级,0的优先级最低。 */
15     UBaseType_t uxPriority;
16     /*< Points to the start of the stack. */
17     /* 指向栈的起始位置。 */
18     StackType_t * pxStack;
19     /*< Descriptive name given to the task when created.  Facilitates debugging only. */
20     /* 描述任务的名字。 */
21     char pcTaskName[ configMAX_TASK_NAME_LEN ];
22 
23     #if ( configUSE_TRACE_FACILITY == 1 )
24         /*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
25         /* 存储每次创建TCB时递增的数字。它允许调试器确定何时删除任务,然后重新创建。 */
26         UBaseType_t uxTCBNumber;
27         /*< Stores a number specifically for use by third party trace code. */
28         /* 存储专门供第三方跟踪代码使用的数字。 */
29         UBaseType_t uxTaskNumber;
30     #endif
31 
32     #if ( configUSE_MUTEXES == 1 )
33         /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
34         /* 上次分配给任务的优先级-由优先级继承机制使用。 */
35         UBaseType_t uxBasePriority;
36         UBaseType_t uxMutexesHeld;
37     #endif
38 
39     #if ( configGENERATE_RUN_TIME_STATS == 1 )
40         /*< Stores the amount of time the task has spent in the Running state. */
41         /* 存储任务处于“运行”状态的时间。 */
42         uint32_t ulRunTimeCounter;
43     #endif
44 
45     #if ( configUSE_TASK_NOTIFICATIONS == 1 )
46         volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
47         volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
48     #endif
49 
50     #if ( INCLUDE_xTaskAbortDelay == 1 )
51         uint8_t ucDelayAborted;
52     #endif
53 } tskTCB;
54 
55 typedef tskTCB TCB_t;

4.1.3 全局变量

 1 /* 表示当前运行的任务 */
 2 PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
 3 /*< Prioritised ready tasks. */
 4 /* 就绪任务链表,每个优先级都有一个链表。 */
 5 PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];
 6 /*< Delayed tasks. */
 7 /* 延时任务链表。 */
 8 PRIVILEGED_DATA static List_t xDelayedTaskList1;
 9 /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
10 /* 延时的任务(使用两个列表-一个用于当前tick计数溢出时的延时。 */
11 PRIVILEGED_DATA static List_t xDelayedTaskList2;
12 /*< Points to the delayed task list currently being used. */
13 /* 指向当前使用的延时链表。 */
14 PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;
15 /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
16 /* 指向tick计数溢出时的延时任务。 */
17 PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList;
18 /*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready list when the scheduler is resumed. */
19 /* 调度器挂起时进入就绪的任务。当调度器恢复时,它们将被移动到就绪链表中。 */
20 PRIVILEGED_DATA static List_t xPendingReadyList;
21 /*< Tasks that have been deleted - but their memory not yet freed. */
22 /* 被删除的任务,但任务持有的内存还未释放。 */
23 PRIVILEGED_DATA static List_t xTasksWaitingTermination;
24 /* 等待清理内存的任务数量。 */
25 PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U;
26 /*< Tasks that are currently suspended. */
27 /* 当前被暂停的任务。 */
28 PRIVILEGED_DATA static List_t xSuspendedTaskList;
29 /* 当前的任务数量。 */
30 PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
31 /* tick计数。 */
32 PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
33 /* 当前就绪任务中最高的优先级。 */
34 PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
35 /* 指示调度器是否在运行。 */
36 PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
37 /* 调度器挂起时,tick的计数值。 */
38 PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U;
39 /* 指示是否需要进行上下文切换。 */
40 PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
41 /* 用于计时的参数。 */
42 PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
43 /* 用于第三方调式代码用的,记录任务的数量。 */
44 PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
45 /* Initialised to portMAX_DELAY before the scheduler starts. */
46 /* 调度器启动时初始化为portMAX_DELAY,用于指示延时任务中最近结束延时的时间。 */
47 PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U;
48 /*< Holds the handle of the idle task. */
49 /* idle任务的句柄。 */
50 PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL;
51 /* 最高任务优先级。 */
52 const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U;
53 /* 指示调度器是否被挂起。 */
54 PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;
55 /*< Holds the value of a timer/counter the last time a task was switched in. */
56 /* 保存上次切换任务时计时器/计数器的值。 */
57 PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL;
58 /*< Holds the total amount of execution time as defined by the run time counter clock. */
59 /* 保存运行时间总量。 */
60 PRIVILEGED_DATA static volatile uint32_t ulTotalRunTime = 0UL;

4.1.4 task.c中的宏

 1 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
 2 /* uxTopReadyPriority holds the priority of the highest priority ready
 3  * state task. */
 4 /* uxTopReadyPriority持有就绪任务链表中的最高优先级。 */
 5 // 记录就绪任务链表中的最高优先级。
 6     #define taskRECORD_READY_PRIORITY( uxPriority ) 
 7     {                                               
 8         if( ( uxPriority ) > uxTopReadyPriority )   
 9         {                                           
10             uxTopReadyPriority = ( uxPriority );    
11         }                                           
12     } /* taskRECORD_READY_PRIORITY */
13 
14 // 选择就绪任务链表中最高优先级的任务。
15 #define taskSELECT_HIGHEST_PRIORITY_TASK()                                    
16     {                                                                         
17         UBaseType_t uxTopPriority = uxTopReadyPriority;                       
18                                                                               
19         /* Find the highest priority queue that contains ready tasks. */      
20         /* 从记录的最高优先级的链表开始查看链表是否为空。 */                                         
21         while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) 
22         {                                                                     
23             configASSERT( uxTopPriority );                                    
24             --uxTopPriority;                                                  
25         }                                                                     
26                                                                               
27         /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of 
28          * the  same priority get an equal share of the processor time. */                    
29         /* 将找到的链表中的头链表项的持有者赋给就绪任务链表中。 */                                      
30         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); 
31         /* 记录最高优先级。 */                                                        
32         uxTopReadyPriority = uxTopPriority;                                                   
33     } /* taskSELECT_HIGHEST_PRIORITY_TASK */
34 
35 #else
36 
37     // #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities )      ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
38     // #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities )      ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
39     // 这种记录最高优先级的办法就是在相应位置1或清0。
40     #define taskRECORD_READY_PRIORITY( uxPriority )    portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
41 
42 /*-----------------------------------------------------------*/
43     // #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )    uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )
44     // __clz指令的意思就是所有1中处于最高位的1的前面0的个数。
45     // 那么宏portGET_HIGHEST_PRIORITY就是算出最高位1的位置,也就是最高优先级的值。
46     #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                  
47     {                                                                                           
48         UBaseType_t uxTopPriority;                                                              
49                                                                                                 
50         /* 找到最高优先级。 */                         
51         portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );                          
52         configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); 
53         /* 将找到的链表中的头链表项的持有者赋给就绪任务链表中。 */                                                        
54         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );   
55     } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
56 
57 /*-----------------------------------------------------------*/
58 
59     // 如果uxPriority优先级的就绪链表为空,则将该位清0。
60     #define taskRESET_READY_PRIORITY( uxPriority )                                                     
61     {                                                                                                  
62         if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) 
63         {                                                                                              
64             portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );                        
65         }                                                                                              
66     }
67 
68 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
69 
70 // 交换pxDelayedTaskList和pxOverflowDelayedTaskList指向的链表,并记录溢出的次数和重置最近延时时间。
71 #define taskSWITCH_DELAYED_LISTS()                                                
72     {                                                                             
73         List_t * pxTemp;                                                          
74                                                                                   
75         /* The delayed tasks list should be empty when the lists are switched. */ 
76         configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );               
77                                                                                   
78         pxTemp = pxDelayedTaskList;                                               
79         pxDelayedTaskList = pxOverflowDelayedTaskList;                            
80         pxOverflowDelayedTaskList = pxTemp;                                       
81         xNumOfOverflows++;                                                        
82         prvResetNextTaskUnblockTime();                                            
83     }
84 
85 // 将pxTCB放入就绪链表。先查看是否比记录的最高优先级还高,是的话更新记录的最高优先级,然后插入到相应链表的尾部。
86 #define prvAddTaskToReadyList( pxTCB )                                                                 
87         taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );                                             
88         listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); 
89 
90 #define prvGetTCBFromHandle( pxHandle )    ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) )
View Code

 

接下来就是接口函数了,在理解了相关的宏和数据结构后,再去看接口函数就会相对轻松一些。在下一篇开始解析接口函数,今天就到这里。