freeRTOS源码解析4--tasks.c 1
4、tasks.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 ) )
接下来就是接口函数了,在理解了相关的宏和数据结构后,再去看接口函数就会相对轻松一些。在下一篇开始解析接口函数,今天就到这里。