【FreeRTOS】FreeRTOS 源码学习笔记 (2)列表项 +一些不容易理解的点(xItemValue、pxIndex、vListInsertEnd…)

1. 引言

本来第二节想直接写任务调度的,发现调度器里很多用到的list这个结构体。
freeRTOS中的list.c和list.h文件又挺短的(list.c 198行 list.h 412行),就是一个链表,
所以作为一个基础知识(软柿子),先补一波。
(本文FreeRTOS版本 v10.3.1)

2. 结构体

list.h里重要的结构体就3个。

  • 列表
  • 列表项
  • 迷你列表项

2.1 xLIST 列表

源码

/*
 * 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. */
	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;

挨个解释一下成员。

  • listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE是两个固定值,0x5a5a…如果需要进行完整性判断,可以用这个。
  • uxNumberOfItems 是这个列表中所拥有的列表项的数量
  • pxIndex,用来遍历列表。指向调用listGET_OWNER_OF_NEXT_ENTRY()返回的最后一个项。这个是不容易理解的点,放最后说
  • xListEnd 是一个迷你列表项,作为结尾。

2.2 xLIST_ITEM 列表项

/*
 * 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 descending 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. */
};
  • listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE依然是完整性判断
  • pxNext 和 pxPrevious是指向前一个和后一个的指针。
  • pvOwner 是指向的TCB
  • pxContainer是属于哪个列表
  • xItemValue 是用来排序的值,做有序插入的时候,要根据这个值做升序

2.3 xMINI_LIST_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;
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

xLIST_ITEM的迷你版。为了省一点点RAM。
目前我只在List_t结构体里看到了使用。

3. 接口

list的接口也非常简单,就是常用链表的几个操作。
在这里插入图片描述
再加一个宏定义 listGET_OWNER_OF_NEXT_ENTRY

3.1 初始化列表 void vListInitialise( List_t * const pxList )

列表的初始化,十分简单

  1. 把数量清零
  2. 把pxIndex指针指向自己的xListEnd
  3. 把xListEnd的前后指针pxNext和pxPrevious都指向自己,组成一个环形链表
  4. 把xListEnd的值设为最大值
    在这里插入图片描述

3.2 初始化列表项 void vListInitialiseItem( ListItem_t * const pxItem )

初始化列表项。
非常简单,只是赋值了pxContainer,列表项中的其他成员都不是在这里赋值的。

3.3 删除 UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )

删除一个列表项。
把当前项的前一项的next指到当前项的下一项,即可。
要删除的这个列表项只是从链表中删除,而不是释放空间的删除。

3.4 插入 void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )

把 pxNewListItem 这个列表项 插入到 pxList 这个列表里。
按照xItemValue升序的原则来排列。
通过一个循环来找到要插入的位置。
插入操作就是典型的链表操作。

插入前:
在这里插入图片描述
插入后
在这里插入图片描述

3.5 插入到最后 void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )

这个接口没有做排序,就是插入到列表的最后。也是做了一个典型链表操作,修改了指向指针。
这些都很好理解。
但是,插入最后,就是列表的最后吗?就是xListEnd的位置吗?
在这里插入图片描述
其实是插在pxIndex指向列表项的前面。
在这里插入图片描述
为什么这么做?
pxIndex指到哪里?
在这里插入图片描述

4. 难点

4.1 pxIndex指的是什么

初始化就是在end,搜索了代码,中间对pxIndex赋值的地方只有listGET_OWNER_OF_NEXT_ENTRY这个接口。
每调用一次listGET_OWNER_OF_NEXT_ENTRY,列表的pxIndex会指向下一个列表项。
而调用listGET_OWNER_OF_NEXT_ENTRY,主要是
在这里插入图片描述

4.2 xItemValue 存的是什么

列表项值。
都是通过listSET_LIST_ITEM_VALUE这个宏来赋值的。
搜了一下,主要赋值了两类值

  • 优先级(对于事件列表)
    在这里插入图片描述
  • 醒来时间(对于状态列表)
    在这里插入图片描述

4.3 vListInsertEnd()的插入位置

从名字上看,是说插入到list的尾部。
那是End?并不是,列表是一个双向环形链表,默认把pxIndex所指作为列表的开头。所以插入End,就是插入到目前开始的位置(pxIndex指的列表项)之前。

4.4 List的头尾在哪里?

结尾是在xListEnd吗?
这个是初始化时候的结尾,名字也是结尾。
但是vListInsertEnd又不是根据xListEnd来定的。是插在pxIndex的前面,那默认pxIndex是开头,
查了一些资料,头尾好像没怎么分,但是第二种的认可度比较高,因为vListInsertEnd是这么用的。

4.5 列表是不是个有序链表?还是个无序的?

个人感觉有些是需要有序的,就按照vListInsert来插入(升序),有些是无序的,就按照vListInsertEnd来插入。
也看到一篇文章总结(参考链接第4条)
在这里插入图片描述

5. 参考链接

6. 系列文章

发布了25 篇原创文章 · 获赞 7 · 访问量 5101

猜你喜欢

转载自blog.csdn.net/tao475824827/article/details/105495512