FreeRTOS列表

内核中有很多双向列表,这些列表可以挂接很多列表项,每条列表都有一个确定的尾节点、列表当前指针、列表项个数

/* 列表结构体 */
typedef struct xLIST
{
	listFIRST_LIST_INTEGRITY_CHECK_VALUE 
	configLIST_VOLATILE UBaseType_t uxNumberOfItems;	/* 列表项个数 */
	ListItem_t *configLIST_VOLATILE pxIndex;		/* 当前列表项指针 */
	MiniListItem_t xListEnd;				/* 列表的尾节点 */
	listSECOND_LIST_INTEGRITY_CHECK_VALUE
}List_t;

列表尾节点中的有效信息包括:列表项的值、next指针、previous指针

/* 迷你列表项结构体 */
struct xMINI_LIST_ITEM
{
	listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
	configLIST_VOLATILE TickType_t xItemValue;		/* 列表项的值 */
	struct xLIST_ITEM *configLIST_VOLATILE pxNext;	        /* next指针指向后一个列表项 */
	struct xLIST_ITEM *configLIST_VOLATILE pxPrevious;	/* previous指针指向前一个列表项 */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

列表项的内容包括:列表项的值、next指针、previous指针、所属TCB指针、正在挂接的列表指针

/* 列表项结构体 */
struct xLIST_ITEM
{
	listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 
	configLIST_VOLATILE TickType_t xItemValue;		/* 列表项的值 */
	struct xLIST_ITEM *configLIST_VOLATILE pxNext;		/* next指针指向后一个列表项 */
	struct xLIST_ITEM *configLIST_VOLATILE pxPrevious;	/* previous指针指向前一个列表项 */
	void *pvOwner;					        /* 该指针指向所属TCB */
	void *configLIST_VOLATILE pvContainer;			/* 指向包含该列表项的列表 */
	listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
typedef struct xLIST_ITEM ListItem_t;

列表会挂接很多列表项,如图所示:

列表初始化时不包含任何列表项

/* 功能:初始化列表
   pxList:列表指针 */
void vListInitialise(List_t *const pxList)
{
	/* 列表初始化时只有尾节点,因此将当前指针指向尾节点 */
	pxList->pxIndex = (ListItem_t *)&(pxList->xListEnd);
	
	/* 尾节点的值初始化为0xffffffff */
	pxList->xListEnd.xItemValue = portMAX_DELAY;

	/* 列表初始化时只有尾节点,且列表是双向环形链表 */
	pxList->xListEnd.pxNext = (ListItem_t *)&(pxList->xListEnd);
	pxList->xListEnd.pxPrevious = (ListItem_t *)&(pxList->xListEnd);

	/* 列表项的个数初始化为0 */
	pxList->uxNumberOfItems = (UBaseType_t)0U;

	listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList);
	listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList);
}

初始化完成后,如图所示:

列表项初始化时不属于任何列表

/* 功能:初始化列表项
   pxItem:列表项指针 */
void vListInitialiseItem(ListItem_t *const pxItem)
{
	/* 将列表项所属列表指针初始化为不指向任何列表 */
	pxItem->pvContainer = NULL;

	listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem);
	listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem);
}

列表初始化后,如图所示:

列表项插入列表的方式有两种,一种是直接插入当前指针指向的位置,另一种是按照列表项值从小到大插入

/* 功能:将列表项插入列表
   pxList:列表指针
   pxNewListItem:列表项指针 */
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->pvContainer = (void *)pxList;

	/* 列表中列表项个数加一 */
	(pxList->uxNumberOfItems)++;
}

/* 功能:将列表项按列表值从小到大插入列表中
   pxList:列表指针
   pxNewListItem:列表项指针 */
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; pxIterator = pxIterator->pxNext)
		{

		}
	}

	/* 将列表项插入列表 */
	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext = pxNewListItem;

	/* 将列表项所属列表指针指向列表 */
	pxNewListItem->pvContainer = (void *)pxList;

	/* 列表中列表项个数加一 */
	(pxList->uxNumberOfItems)++;
}

从列表中移除列表项

/* 功能:将列表项从当前所在的列表中移除
   pxItemToRemove:列表项
   返回值:移除该列表项后所在列表中列表项的个数 */
UBaseType_t uxListRemove(ListItem_t *const pxItemToRemove)
{
	/* 列表项所在列表指针 */
	List_t *const pxList = (List_t *)pxItemToRemove->pvContainer;

	/* 将列表项从列表中移除 */
	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

	mtCOVERAGE_TEST_DELAY();

	/* 列表当前指针指向该列表项,则将列表当前指针改为指向前一个列表项 */
	if(pxList->pxIndex == pxItemToRemove)
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	/* 该列表项不属于任何列表 */
	pxItemToRemove->pvContainer = NULL;
	
	/* 列表中列表项个数减一 */
	(pxList->uxNumberOfItems)--;

	/* 返回列表项个数 */
	return pxList->uxNumberOfItems;
}

列表还提供了一些其他的接口

/* 设置列表项所属TCB */
#define listSET_LIST_ITEM_OWNER(pxListItem, pxOwner)	((pxListItem)->pvOwner = (void *)(pxOwner))

/* 获取列表项所属TCB */
#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)

/* 获取列表头部列表项的值 */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxList)		(((pxList)->xListEnd).pxNext->xItemValue)

/* 获取列表头部列表项 */
#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)	((BaseType_t)((pxList)->uxNumberOfItems == (UBaseType_t)0))

/* 获取列表中当前列表项的个数 */
#define listCURRENT_LIST_LENGTH(pxList)	((pxList)->uxNumberOfItems)

/* 将当前列表项指针指向下一个列表项,返回所属TCB */
#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 */
#define listGET_OWNER_OF_HEAD_ENTRY(pxList)  ((&((pxList)->xListEnd))->pxNext->pvOwner)

/* 判断列表项是否属于指定列表 */
#define listIS_CONTAINED_WITHIN(pxList, pxListItem) ((BaseType_t)((pxListItem)->pvContainer == (void *)(pxList)))

/* 获取列表项所在列表 */
#define listLIST_ITEM_CONTAINER(pxListItem) ((pxListItem)->pvContainer)

/* 判断列表是否已经初始化(尾节点列表项值为最大可能值0xffffffff) */
#define listLIST_IS_INITIALISED(pxList) ((pxList)->xListEnd.xItemValue == portMAX_DELAY)

猜你喜欢

转载自blog.csdn.net/lushoumin/article/details/87933934
今日推荐