下面将对给出的所有宏定义进行详细解释。这些宏是 FreeRTOS 内核中用于操作双向链表的常用工具,通常定义在 list.h 文件中。它们用于管理任务控制块(TCB)的列表,如就绪列表、阻塞列表等。


1. listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )

#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) \
    ((pxListItem)->pvOwner = (void*)(pxOwner))
  • 作用:设置列表项的“拥有者”。在 FreeRTOS 中,每个列表项通常属于一个任务,拥有者就是指向任务 TCB 的指针。
  • 参数
    • pxListItem:指向 ListItem_t 结构体的指针。
    • pxOwner:要设置的拥有者指针,通常是 TCB_t*
  • 展开:将 pxOwner 强制转换为 void* 并赋值给列表项的 pvOwner 成员。
  • 用途:用于将列表项与具体的任务关联起来,当从列表中取出项时,可以通过 pvOwner 获得对应的任务控制块。

2. listGET_LIST_ITEM_OWNER( pxListItem )

#define listGET_LIST_ITEM_OWNER( pxListItem ) \
    ( ( pxListItem )->pvOwner )
  • 作用:获取列表项所拥有的对象(通常是 TCB)。
  • 参数pxListItem 指向列表项的指针。
  • 展开:直接返回 pvOwner 成员的值。
  • 用途:在遍历列表时,通过此项获得对应的任务 TCB。

3. listSET_LIST_ITEM_VALUE( pxListItem, xValue )

#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) \
    ( ( pxListItem )->xItemValue = ( xValue ) )
  • 作用:设置列表项的排序辅助值(通常用于优先级或超时时间)。
  • 参数
    • pxListItem:指向列表项的指针。
    • xValue:要设置的 TickType_t 类型的值。
  • 用途:列表项在链表中按 xItemValue 升序排列,这个值决定了节点在列表中的位置。例如,在就绪列表中,值可以是任务优先级;在阻塞列表中,值可以是任务的唤醒时间。

4. listGET_LIST_ITEM_VALUE( pxListItem )

#define listGET_LIST_ITEM_VALUE( pxListItem ) \
    ( ( pxListItem )->xItemValue )
  • 作用:获取列表项的排序辅助值。
  • 参数pxListItem 指向列表项的指针。
  • 展开:返回 xItemValue
  • 用途:读取某个列表项的排序值,比如获取任务的优先级或阻塞超时时间。

5. listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )

#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) \
    ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
  • 作用:获取链表头部(第一个实际节点)的排序辅助值。
  • 参数pxList 指向链表根节点 List_t 的指针。
  • 展开
    • (pxList)->xListEnd:获取链表的哨兵节点(xListEnd)。
    • .pxNext:哨兵节点的 pxNext 指向链表的第一个实际节点。
    • ->xItemValue:获取该节点的排序值。
  • 用途:常用于获取就绪列表中的最高优先级任务的优先级值(因为就绪列表按优先级升序排列,头部是优先级最高的任务)。

6. listGET_HEAD_ENTRY( pxList )

#define listGET_HEAD_ENTRY( pxList ) \
    ( ( ( pxList )->xListEnd ).pxNext )
  • 作用:获取链表的第一个实际节点(头节点)。
  • 参数pxList 指向链表根节点的指针。
  • 展开:返回 (pxList)->xListEnd.pxNext,即哨兵节点指向的第一个实际节点。
  • 用途:在需要遍历列表时获取起始节点。

7. listGET_NEXT( pxListItem )

#define listGET_NEXT( pxListItem ) \
    ( ( pxListItem )->pxNext )
  • 作用:获取给定节点的下一个节点。
  • 参数pxListItem 指向当前列表项的指针。
  • 展开:返回 pxNext 成员。
  • 用途:用于遍历链表时移动到下一节点。

8. listGET_END_MARKER( pxList )

#define listGET_END_MARKER( pxList ) \
    ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
  • 作用:获取链表的哨兵节点(结束标记节点)。
  • 参数pxList 指向链表根节点的指针。
  • 用途:通常用于判断是否遍历到链表末尾(pxCurrent == listGET_END_MARKER(pxList))。哨兵节点不包含实际数据,仅用于标识链表的结尾。

9. listLIST_IS_EMPTY( pxList )

#define listLIST_IS_EMPTY( pxList ) \
    ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( BaseType_t ) 0 ) )
  • 作用:判断链表是否为空。
  • 参数pxList 指向链表根节点的指针。
  • 展开:比较 uxNumberOfItems(节点计数器)是否等于 0,结果强制转换为 BaseType_t(通常为 int)。
  • 用途:快速判断某个就绪列表或阻塞列表是否为空。

10. listCURRENT_LIST_LENGTH( pxList )

#define listCURRENT_LIST_LENGTH( pxList ) \
    ( ( pxList )->uxNumberOfItems )
  • 作用:获取链表当前的节点数量。
  • 参数pxList 指向链表根节点的指针。
  • 展开:返回 uxNumberOfItems 成员。
  • 用途:获取某个列表中的任务数量,例如就绪列表中优先级为 x 的任务个数。

11. listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
{ \
    List_t * const pxConstList = ( pxList ); \
    ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
    if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
    { \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
    } \
    ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
}
  • 作用:获取下一个列表项所拥有的对象(即 TCB),并自动推进列表索引,实现循环遍历(round-robin)。
  • 参数
    • pxTCB:输出参数,用于接收 TCB 指针。
    • pxList:指向链表根节点的指针。
  • 详细分解
    1. List_t * const pxConstList = ( pxList );
      将传入的链表指针保存到一个局部常量指针中,防止宏展开时多次解引用带来的副作用
    2. ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
      将列表的当前索引指针向前移动一个节点。pxIndex 是一个遍历指针,初始时通常指向哨兵节点 xListEnd,第一次调用后会指向第一个实际节点。
    3. if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )
      判断移动后的 pxIndex 是否指向了哨兵节点(xListEnd)。如果是,说明已经遍历到链表末尾(即绕了一圈)。
    4. ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
      在哨兵节点的情况下,再次将 pxIndex 向前移动一个节点。因为哨兵节点的 pxNext 指向链表的第一个实际节点,所以这一步使得 pxIndex 重新指向第一个实际节点,实现了循环回绕。
    5. ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;
      从当前 pxIndex 指向的列表项中取出 pvOwner(即 TCB 指针),赋值给 pxTCB
  • 用途:这是 FreeRTOS 中实现 轮询调度(Round-Robin) 的核心宏。当多个相同优先级的任务处于就绪状态时,调度器会依次选择它们来运行。每次调用此宏,都会从列表中取出下一个任务的 TCB,并自动循环。宏中的 if 语句正是为了在到达列表末尾时跳回开头,实现循环遍历。

总结

这些宏共同构成了 FreeRTOS 中高效、简洁的链表操作接口。它们被广泛用于任务调度、延时管理、事件处理等核心模块中。通过内联宏的方式,既保证了代码的紧凑性,又避免了函数调用的开销,符合嵌入式实时系统对性能和资源的要求。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐