FreeRTOS Task Management (1) - list 实现
原文链接:https://www.cnblogs.com/yanpio/p/14838071.html
list
结构是FreeRTOS Task Management
等模块重要的数据结构,其源码在list.c
和list.h
中。
以下结合源码来分析list
的结构与功能的实现细节。
1 结构体定义
/* list结构由以下三个结构体组成 */
struct xLIST;
/* list结构模型是一个双向链表,ListItem_t 定义了每个节点的数据结构 */
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 见说明(1),下同*/
configLIST_VOLATILE TickType_t xItemValue; /* 每个节点的值。 一般用于降序排列链表节点。 */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 指向后一个节点 */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;/* 指向前一个节点 */
void * pvOwner; /* 指向owner,一般是一个task control block(TCB),后面在分析task时会详细说明 */
struct xLIST * configLIST_VOLATILE pxContainer; /* 指向该节点所在的链表 */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
typedef struct xLIST_ITEM ListItem_t;
/* 上述节点信息结构体的删减版。 用于定义list中的尾结点,作为list结尾标记 */
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
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结构 */
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE
volatile UBaseType_t uxNumberOfItems; /* 结点数量 */
ListItem_t * configLIST_VOLATILE pxIndex; /* 节点指针(类似于容器中的迭代器)*/
MiniListItem_t xListEnd; /* list尾结点 */
listSECOND_LIST_INTEGRITY_CHECK_VALUE
} List_t;
说明(1)— listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
宏的作用
/* 这一系列的宏的作用是,检查是否发生内存覆盖 */
#if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
/* 如果功能没有开启,则以下宏都定义为空,不实现功能 */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
#define listTEST_LIST_INTEGRITY( pxList )
#else
/* 定义变量 */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1;
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2;
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;
/* 将变量设置为固定值. */
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
#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 macros that will assert if one of the structure members does not
* contain its expected value. */
#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#endif
说明(2)— list
结构图示
2 宏定义
list.h
中将一些简单的函数功能定义成了宏。以下逐个进行分析。
/* 设置listItem的owner指针,一般是一个TCB对象 */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/* 获取listItem的owner指针,一般是一个TCB对象 */
#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )
/* 设置item value */
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
/* 获取item value, 一般是task的优先级,或者是task进入unblocked状态的时刻 */
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
/* 获取list的头结点 item value */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
/* 获取list的 head item */
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
/* 获取下一个item */
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
/* 获取end marker */
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
/* 判断list是否为空*/
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
/* 获取list长度 */
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
/* 包含两个功能,一是迭代到下一个item(如果是listEnd,则返回listEnd的下一个item)
* 二是返回下一个item的pvOwner。*/
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
{ \
List_t * const pxConstList = ( pxList ); \
/* Increment the index to the next item and return the item, ensuring */ \
/* we don't return the marker used at the end of the list. */ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
{ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
} \
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
}
/* 获取list的owner, 返回第一个item的pvOwner指针 */
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
/* 判断给定的item 是否在给定的list中 */
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
/* 获取给定item的container */
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
/* 判断list是否被初始化,因为在list初始化时,会将listEnd的item value初始化为portMAX_DELAY */
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
3 初始化
/*
* 初始化list,分别处理结构体的3个成员
* (1)pxIndex 指向 xListEnd
* (2)xListEnd的xItemValue设置为portMAX_DELAY,因为list中的item都是按照大小进行排序,这样可以保证xListEnd在最后
* xListEnd的 pxNext 和 pxPrevious 都指向自身
* (3)uxNumberOfItems 置为0
*/
void vListInitialise( List_t * const pxList )
{
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.xItemValue = portMAX_DELAY;
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
/* 写入校验数. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
/* 初始化item,主要就是将其pvContainer 指针置为NULL,表示不在任何一个list中*/
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 );
}
4 插入元素 - vListInsertEnd()
首先需要解释一下vListInsertEnd
中 End
的含义。顾名思义,End
就是最后的意思,但是代码中的指针一顿操作,实际完成的工作如下图所示:
从插入的结果来看,貌似并不能直观地表现End
的含义,源码中有一段注释如下:
/*
* Insert a list item into a list. The item will be inserted in a position such that it will be the last item within the list * returned by multiple calls to listGET_OWNER_OF_NEXT_ENTRY.
*/
翻译过来就是,插入的item
是listGET_OWNER_OF_NEXT_ENTRY
函数(宏)最后遍历到的位置,因为函数会从pxIndex
开始遍历。因此,End
的含义是遍历时最后访问到,而不是list
空间位置的最后。
/* 在list的最后插入一个item*/
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex;
/* 校验数值,用于判断是否发生memory overwite */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* 操作指针,完成上图中的操作 */
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
/* 操作指针,完成上图中的操作 */
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* Remember which list the item is in. */
pxNewListItem->pvContainer = ( void * ) pxList;
( pxList->uxNumberOfItems )++;
}
5 插入元素 - vListInsert()
与vListInsertEnd()
不同,vListInsert()
函数是按照xItemValue
,进行排序。
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
/* check overwritten in memory. */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* 如果插入的 Item Value 和已有 Item Value 相等,则插入到这个已有的 item 的后面。
* 如果插入的 Item Value 为 portMAX_DELAY,则插入到xListEnd的前一个,不能破坏了xListEnd的marker作用 */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
/* 根据xItemValue,迭代到合适的位置 */
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) { }
}
/* 一顿指针操作,将item插入其中 */
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* pvContainer赋值 */
pxNewListItem->pvContainer = ( void * ) pxList;
( pxList->uxNumberOfItems )++;
}
6 删除元素
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
/* 将要删除的item从双向链表中解开 */
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
/* 如果 pxIndex指向的item 已经被删除,则需要将pxIndex指向前一个item. */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxItemToRemove->pvContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}