没志青年
发布于 2025-09-16 / 20 阅读
0

FreeRTOS 源码 - 列表 list

列表是 FreeRTOS 系统各种功能实现的的基础,本质上是一个双向循环链表

类型定义

列表类型:

    typedef struct xLIST
    {
        listFIRST_LIST_INTEGRITY_CHECK_VALUE
        volatile UBaseType_t uxNumberOfItems;       // 子项数量
        ListItem_t *configLIST_VOLATILE pxIndex;    // 当前项

        MiniListItem_t xListEnd;
        listSECOND_LIST_INTEGRITY_CHECK_VALUE
    } List_t;

列表项类型:

 struct xLIST_ITEM
    {
        listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
            configLIST_VOLATILE TickType_t xItemValue;     // 值,用于排序
        struct xLIST_ITEM *configLIST_VOLATILE pxNext;     // 下一个项
        struct xLIST_ITEM *configLIST_VOLATILE pxPrevious; // 上一个项
        void *pvOwner;                                     // 拥有该节点的TCB
        struct xLIST *configLIST_VOLATILE pxContainer;     // 属于哪个列表
        listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
    };
    typedef struct xLIST_ITEM ListItem_t;

完整性检查

开头和结束的宏定义是为了做完整性检查,

#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;

展开后是:

   typedef struct xLIST
    {
        TickType_t xListIntegrityValue1;
        volatile UBaseType_t uxNumberOfItems;
        ListItem_t *configLIST_VOLATILE pxIndex;
        MiniListItem_t xListEnd;
        TickType_t xListIntegrityValue2;
    } List_t;

就是给结构体前后设置一个固定值,如果读到的不是这个值,说明结构体被破坏了。

#define listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList) (pxList)->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList) (pxList)->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE

宏函数

// 设置列表项所属的对象,通常为任务
#define listSET_LIST_ITEM_OWNER(pxListItem, pxOwner) ((pxListItem)->pvOwner = (void *)(pxOwner))
// 获取列表项所属的对象,通常为任务
#define listGET_LIST_ITEM_OWNER(pxListItem) ((pxListItem)->pvOwner)
// 设置列表项的值
#define listSET_LIST_ITEM_VALUE(pxListItem, xValue) ((pxListItem)->xItemValue = (xValue))
// 获取列表项的值
#define listGET_LIST_ITEM_VALUE(pxListItem) ((pxListItem)->xItemValue)

/*
 * Access macro to retrieve the value of the list item at the head of a given
 * list.
 *
 * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
 * \ingroup LinkedList
 */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxList) (((pxList)->xListEnd).pxNext->xItemValue)

/*
 * Return the list item at the head of the list.
 *
 * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
 * \ingroup LinkedList
 */
#define listGET_HEAD_ENTRY(pxList) (((pxList)->xListEnd).pxNext)

// 获取下一个列表项
#define listGET_NEXT(pxListItem) ((pxListItem)->pxNext)
// 获取列表的终止节点
#define listGET_END_MARKER(pxList) ((ListItem_t const *)(&((pxList)->xListEnd)))
// 判断列表是否为空
#define listLIST_IS_EMPTY(pxList) (((pxList)->uxNumberOfItems == (UBaseType_t)0) ? pdTRUE : pdFALSE)
// 获取列表的列表项数量
#define listCURRENT_LIST_LENGTH(pxList) ((pxList)->uxNumberOfItems)

初始化列表

最后一项是伪节点(哨兵节点),是为了让链表实现循环,与具体业务无关。

void vListInitialise(List_t *const pxList)
{
    // 最后项就是当前项
    pxList->pxIndex = (ListItem_t *)&(pxList->xListEnd);

    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(&(pxList->xListEnd));

    //列表项的 xItemValue 用于排序,因此最后一项的值要最大
    pxList->xListEnd.xItemValue = portMAX_DELAY;

    // 最后一项的特性:上一个和下一个都指向自己
    pxList->xListEnd.pxNext = (ListItem_t *)&(pxList->xListEnd);
    pxList->xListEnd.pxPrevious = (ListItem_t *)&(pxList->xListEnd);

// 如果不使用精简版链表还得初始化下面的
#if (configUSE_MINI_LIST_ITEM == 0)
    {
        pxList->xListEnd.pvOwner = NULL;
        pxList->xListEnd.pxContainer = NULL;
        listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(&(pxList->xListEnd));
    }
#endif

    // 总数为0
    pxList->uxNumberOfItems = (UBaseType_t)0U;

    // 完整性检查
    listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList);
    listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList);
}

插入到列表中

void vListInsert(List_t *const pxList, ListItem_t *const pxNewListItem)
{
    ListItem_t *pxIterator;
    const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;

    // 完整性检查
    listTEST_LIST_INTEGRITY(pxList);
    listTEST_LIST_ITEM_INTEGRITY(pxNewListItem);

    if (xValueOfInsertion == portMAX_DELAY)  // 值最大,插入到末尾
    {                                             
        pxIterator = pxList->xListEnd.pxPrevious; // 伪节点的前一项才是真正的节点
    }
    else   // 根据值找到位置
    {
        for (pxIterator = (ListItem_t *)&(pxList->xListEnd);
             pxIterator->pxNext->xItemValue <= xValueOfInsertion; // 终止节点的next为第一个节点
             pxIterator = pxIterator->pxNext)
        {
        }
    }

    pxNewListItem->pxNext = pxIterator->pxNext;
    pxNewListItem->pxNext->pxPrevious = pxNewListItem;
    pxNewListItem->pxPrevious = pxIterator;
    pxIterator->pxNext = pxNewListItem;

    // 设置父对象
    pxNewListItem->pxContainer = pxList;
    // 所属列表子项数量+1
    (pxList->uxNumberOfItems)++;
}

插入到列表尾部

和插入函数相比,少了条件判断。

void vListInsertEnd(List_t *const pxList, ListItem_t *const pxNewListItem)
{
    ListItem_t *const pxIndex = pxList->pxIndex;

    // 完整性检查
    listTEST_LIST_INTEGRITY(pxList);
    listTEST_LIST_ITEM_INTEGRITY(pxNewListItem);

    pxNewListItem->pxNext = pxIndex; // 指向链表终止节点
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;

    mtCOVERAGE_TEST_DELAY();

    pxIndex->pxPrevious->pxNext = pxNewListItem;
    pxIndex->pxPrevious = pxNewListItem;

    // 设置父对象
    pxNewListItem->pxContainer = pxList;
    // 数量+1
    (pxList->uxNumberOfItems)++;
}

从列表中删除

需要修改:

  • 前一项的后一项

  • 后一项的前一项

UBaseType_t uxListRemove(ListItem_t *const pxItemToRemove)
{
    // 获取它的父对象
    List_t *const pxList = pxItemToRemove->pxContainer;

    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
    pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

    // 修改当前的列表项
    if (pxList->pxIndex == pxItemToRemove)
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious;
    }

    //
    pxItemToRemove->pxContainer = NULL;
    // 所属列表子项数量-1
    (pxList->uxNumberOfItems)--;
    // 返回列表子项总数
    return pxList->uxNumberOfItems;
}