FreeRTOS之鏈表操作相關接口
- 1 FreeRTOS源碼下載地址
- 2 任務控制塊TCB
- 2.1 任務控制塊TCB
- 2.1.1 任務控制塊的關鍵成員
- 2.1.2 TCB 的核心作用
- 2.2 ListItem_t
- 2.3 List_t
- 3 函數接口
- 3.1 vListInitialise
- 3.2 vListInitialiseItem
1 FreeRTOS源碼下載地址
https://www.freertos.org/
2 任務控制塊TCB
2.1 任務控制塊TCB
2.1.1 任務控制塊的關鍵成員
-
volatile StackType_t * pxTopOfStack
,上下文切換的核心依賴 —— 保存 / 恢復任務運行狀態(如 CPU 寄存器值壓棧 / 出棧)。指向任務棧中 “最后一個被使用的位置”(棧頂),存儲任務當前的上下文(如寄存器值、返回地址等)。 -
UBaseType_t uxCoreAffinityMask
, 條件編譯:(configUSE_CORE_AFFINITY == 1 && configNUMBER_OF_CORES > 1)
在多核系統中,指定任務可運行的核心(核心親和性)。 -
ListItem_t xStateListItem
,將任務鏈接到 FreeRTOS 的 “狀態鏈表” 中(如就緒鏈表、阻塞鏈表、掛起鏈表)。 -
ListItem_t xEventListItem
,將任務鏈接到 “事件等待鏈表” 中(如信號量、消息隊列、事件組的等待鏈表)。當任務調用xSemaphoreTake()
、xQueueReceive()
等函數等待事件時,會通過xEventListItem
加入對應事件的等待鏈表,直到事件觸發(如信號量被釋放)才被移回就緒鏈表。 -
UBaseType_t uxPriority
,存儲任務的優先級(0 為最低優先級,最大值由configMAX_PRIORITIES定義)。 -
StackType_t * pxStack
,指向任務棧的 “起始地址”(棧的最低地址,與pxTopOfStack
配合標識棧的范圍)。- 與
pxTopOfStack
的關系:- pxStack:棧的起點(固定不變);
- pxTopOfStack:棧的當前頂部(隨任務運行動態變化,如函數調用時棧頂上移)。
- 與
-
volatile BaseType_t xTaskRunState
:標識任務的運行狀態 —— 若任務正在運行,存儲其所在的核心編號;若未運行,存儲狀態(如未運行、正在讓出 CPU)。 -
UBaseType_t uxTaskAttributes
:存儲任務的屬性,目前主要用于標識 “空閑任務”(FreeRTOS 為每個核心創建一個空閑任務,用于核心空閑時運行)。 -
char pcTaskName[ configMAX_TASK_NAME_LEN ]
,存儲任務的名稱(字符串),僅用于調試(如通過vTaskList()打印任務列表時顯示名稱)。由configMAX_TASK_NAME_LEN定義(默認 16 字節,含終止符\0)。 -
UBaseType_t uxCriticalNesting
,記錄任務的 “臨界區嵌套深度”(進入臨界區時加 1,退出時減 1,0 表示不在臨界區)。 -
UBaseType_t uxTCBNumber
:存儲 TCB 的創建序號(每次創建任務時遞增),用于調試時識別任務是否被刪除后重建(刪除后重建的任務序號不同)。 -
UBaseType_t uxTaskNumber
:供第三方跟蹤工具使用,用于任務的唯一標識和性能分析。 -
UBaseType_t uxBasePriority
:存儲任務的 “基礎優先級”(原始優先級),用于 “優先級繼承” 機制 —— 當任務持有互斥鎖時,若被高優先級任務等待,會臨時提升到等待任務的優先級(避免優先級反轉),釋放鎖后恢復為uxBasePriority。 -
UBaseType_t uxMutexesHeld
:記錄任務當前持有的互斥鎖數量,用于確保任務刪除時釋放所有持有的鎖(避免死鎖)。
/** Task control block. A task control block (TCB) is allocated for each task,* and stores task state information, including a pointer to the task's context* (the task's run time environment, including register values)*/
typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{volatile StackType_t * pxTopOfStack; /**< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */#if ( portUSING_MPU_WRAPPERS == 1 )xMPU_SETTINGS xMPUSettings; /**< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */#endif#if ( configUSE_CORE_AFFINITY == 1 ) && ( configNUMBER_OF_CORES > 1 )UBaseType_t uxCoreAffinityMask; /**< Used to link the task to certain cores. UBaseType_t must have greater than or equal to the number of bits as configNUMBER_OF_CORES. */#endifListItem_t xStateListItem; /**< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ListItem_t xEventListItem; /**< Used to reference a task from an event list. */UBaseType_t uxPriority; /**< The priority of the task. 0 is the lowest priority. */StackType_t * pxStack; /**< Points to the start of the stack. */#if ( configNUMBER_OF_CORES > 1 )volatile BaseType_t xTaskRunState; /**< Used to identify the core the task is running on, if the task is running. Otherwise, identifies the task's state - not running or yielding. */UBaseType_t uxTaskAttributes; /**< Task's attributes - currently used to identify the idle tasks. */#endifchar pcTaskName[ configMAX_TASK_NAME_LEN ]; /**< Descriptive name given to the task when created. Facilitates debugging only. */#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )BaseType_t xPreemptionDisable; /**< Used to prevent the task from being preempted. */#endif#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )StackType_t * pxEndOfStack; /**< Points to the highest valid address for the stack. */#endif#if ( portCRITICAL_NESTING_IN_TCB == 1 )UBaseType_t uxCriticalNesting; /**< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */#endif#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxTCBNumber; /**< 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. */UBaseType_t uxTaskNumber; /**< Stores a number specifically for use by third party trace code. */#endif#if ( configUSE_MUTEXES == 1 )UBaseType_t uxBasePriority; /**< The priority last assigned to the task - used by the priority inheritance mechanism. */UBaseType_t uxMutexesHeld;#endif#if ( configUSE_APPLICATION_TASK_TAG == 1 )TaskHookFunction_t pxTaskTag;#endif#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];#endif#if ( configGENERATE_RUN_TIME_STATS == 1 )configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /**< Stores the amount of time the task has spent in the Running state. */#endif#if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 )configTLS_BLOCK_TYPE xTLSBlock; /**< Memory block used as Thread Local Storage (TLS) Block for the task. */#endif#if ( configUSE_TASK_NOTIFICATIONS == 1 )volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];#endif/* See the comments in FreeRTOS.h with the definition of* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */#if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )uint8_t ucStaticallyAllocated; /**< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */#endif#if ( INCLUDE_xTaskAbortDelay == 1 )uint8_t ucDelayAborted;#endif#if ( configUSE_POSIX_ERRNO == 1 )int iTaskErrno;#endif
} tskTCB;
2.1.2 TCB 的核心作用
TCB 是 FreeRTOS 任務的 “數字身份證”,通過整合棧信息、優先級、狀態鏈表、同步機制等關鍵數據,實現了以下核心功能:
- 任務調度:操作系統通過uxPriority和xStateListItem選擇下一個運行的任務;
- 上下文切換:依賴pxTopOfStack保存 / 恢復任務的運行環境;
- 任務同步:通過xEventListItem和任務通知成員實現任務間的事件交互;
- 內存與安全管理:通過 MPU 配置、棧溢出檢測、臨界區控制確保任務安全運行;
- 可擴展性:條件編譯支持按需裁剪功能,適配從微控制器到多核處理器的各類場景。
2.2 ListItem_t
-
configLIST_VOLATILE TickType_t xItemValue;
,節點的排序依據,通常存儲任務的優先級、超時時間(如xTaskDelay()的延時值)等。- FreeRTOS 通過該值對鏈表進行升序排序
- 就緒任務鏈表按優先級(uxPriority)排序,高優先級任務排在前面;
- 延時任務鏈表按喚醒時間(當前時間 + 延時值)排序,最早喚醒的任務排在最前。
- FreeRTOS 通過該值對鏈表進行升序排序
- 雙向鏈表指針,分別指向前驅節點和后繼節點,形成雙向鏈表結構。
-
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
-
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
-
-
void * pvOwner;
,指向包含該鏈表節點的對象(通常是任務控制塊TCB)。通過鏈表節點快速定位到所屬任務。 -
struct xLIST * configLIST_VOLATILE pxContainer;
,指向當前節點所在的鏈表(xLIST結構體)。
/** Definition of the only type of object that a list can contain.*/
struct xLIST;
struct xLIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /**< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */configLIST_VOLATILE TickType_t xItemValue; /**< The value being listed. In most cases this is used to sort the list in ascending order. */struct xLIST_ITEM * configLIST_VOLATILE pxNext; /**< Pointer to the next ListItem_t in the list. */struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /**< Pointer to the previous ListItem_t in the list. */void * pvOwner; /**< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */struct xLIST * configLIST_VOLATILE pxContainer; /**< Pointer to the list in which this list item is placed (if any). */listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /**< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t;
2.3 List_t
這個結構體是 FreeRTOS 內核中用于管理鏈表的核心數據結構xLIST。鏈表在 FreeRTOS 中被廣泛用于任務調度、事件管理、資源分配等場景(如就緒任務鏈表、延時任務鏈表、信號量等待鏈表等)。
-
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
,記錄鏈表中節點數量。 -
ListItem_t * configLIST_VOLATILE pxIndex;
,用于迭代訪問鏈表節點(支持循環遍歷)。 -
MiniListItem_t xListEnd;
,特殊節點,始終位于鏈表尾部,作為遍歷終止標記。
/** Definition of the type of queue used by the scheduler.*/
typedef struct xLIST
{listFIRST_LIST_INTEGRITY_CHECK_VALUE /**< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */configLIST_VOLATILE UBaseType_t uxNumberOfItems;ListItem_t * configLIST_VOLATILE pxIndex; /**< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */MiniListItem_t xListEnd; /**< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */listSECOND_LIST_INTEGRITY_CHECK_VALUE /**< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
3 函數接口
3.1 vListInitialise
-
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
,將遍歷指針pxIndex指向哨兵節點xListEnd。空鏈表中沒有有效節點,pxIndex指向尾部標記,確保首次遍歷時能正確定位到第一個有效節點。 -
pxList->xListEnd.xItemValue = portMAX_DELAY;
,將哨兵節點的xItemValue設為最大值(通常是0xFFFFFFFF)。在插入節點時,按xItemValue
升序排列,哨兵節點的值最大,因此始終位于鏈表尾部,作為遍歷終止標記。 -
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
,讓哨兵節點的pxNext和pxPrevious都指向自身,形成自循環。 -
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
,讓哨兵節點的pxNext和pxPrevious都指向自身,形成自循環。 -
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
,將鏈表長度計數器置為 0,表示鏈表中沒有有效節點。
void vListInitialise( List_t * const pxList )
{traceENTER_vListInitialise( pxList );/* The list structure contains a list item which is used to mark the* end of the list. To initialise the list the list end is inserted* as the only list entry. */pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );/* The list end value is the highest possible value in the list to* ensure it remains at the end of the list. */pxList->xListEnd.xItemValue = portMAX_DELAY;/* The list end next and previous pointers point to itself so we know* when the list is empty. */pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/* Initialize the remaining fields of xListEnd when it is a proper ListItem_t */#if ( configUSE_MINI_LIST_ITEM == 0 ){pxList->xListEnd.pvOwner = NULL;pxList->xListEnd.pxContainer = NULL;listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );}#endifpxList->uxNumberOfItems = ( UBaseType_t ) 0U;/* Write known values into the list if* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );traceRETURN_vListInitialise();
}
3.2 vListInitialiseItem
void vListInitialiseItem( ListItem_t * const pxItem )
{traceENTER_vListInitialiseItem( pxItem );/* Make sure the list item is not recorded as being on a list. */pxItem->pxContainer = NULL;/* Write known values into the list item if* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );traceRETURN_vListInitialiseItem();
}