關於 LOAD segment with RWX permissions 警告, 這是 Binutils 2.39 引入的一個新的安全類型的警告, GCC在升級版本時會帶著新版本的 Binutils 一起發佈. 如果要消除這個警告, 要麼修改ld文件, 要麼屏蔽掉它. ...
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
接下來就是介面函數了,在理解了相關的巨集和數據結構後,再去看介面函數就會相對輕鬆一些。在下一篇開始解析介面函數,今天就到這裡。