FreeRTOS源码中的list.c与list.h文件

0 阅读2分钟

1.该文件究竟在做什么?

FreeRTOS 里几乎所有“任务排队”都依赖这套链表机制。
它实现的是一种双向循环链表,并且内置尾哨兵节点(统一边界处理)。

2.必须抓住的三个结构角色是什么?

任务节点ListItem_t,带排序键 xItemValue、前后指针、owner、container

struct xLIST_ITEM
{        
    configLIST_VOLATILE TickType_t xItemValue;   
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;     
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; 
    void * pvOwner;                                    
    struct xLIST * configLIST_VOLATILE pxContainer;            
};
typedef struct xLIST_ITEM ListItem_t;  

尾哨兵轻量节点MiniListItem_t

    {
        configLIST_VOLATILE TickType_t xItemValue;
        struct xLIST_ITEM * configLIST_VOLATILE pxNext;
        struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
    };
    typedef struct xMINI_LIST_ITEM MiniListItem_t;

链表控制块List_t,持有节点数量、遍历游标 pxIndex 和尾哨兵 xListEnd。

typedef struct xLIST
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE      /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    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.list.c的核心函数

void vListInitialise( List_t * const pxList )
    初始化链表,把尾哨兵的前后都指向自己,并把其值设为最大值。  
    意义:空链表立刻可用,且遍历终止条件统一。
void vListInitialiseItem( ListItem_t * const pxItem )
    把节点标记为“不在任何链表里”(pxContainer = NULL)。  
    意义:避免重复挂链和脏状态。
void vListInsertEnd( List_t * const pxList,
                     ListItem_t * const pxNewListItem )
    按当前游标位置尾插,不排序。  
    意义:为同优先级任务轮转提供公平性基础。
void vListInsert( List_t * const pxList,
                  ListItem_t * const pxNewListItem )
    按 xItemValue 升序插入。  
    意义:延时队列等“按时间排序”的场景直接使用。  
    特别点:对最大值做了特殊分支,避免和哨兵比较时出现死循环风险。
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
    从所属链表中摘除节点,修正游标,数量减一。  
    意义:任务状态迁移(就绪/阻塞/唤醒)的基础动作。

4. 这个实现里最漂亮的设计点

尾哨兵模式:不需要判断头尾空指针,链表边界统一成“遇到哨兵即结束”。

侵入式节点:节点嵌在任务控制块中,不额外分配链表节点内存,减少碎片和分配开销。

双向绑定:节点有 owner,任务对象里有节点。调度器能在“任务对象”和“链表节点”之间 O(1) 来回切换。

5. 它如何服务调度器

就绪队列:通常用 vListInsertEnd + 轮转游标,保证同优先级时间片公平。

延时队列:通常用 vListInsert,按唤醒 tick 自动有序。

事件等待:任务可通过另一条节点链挂到事件列表,事件到达后再转回就绪。