文章目录
- 前言
- 1、 list.h
- 1.1、未实现的宏
- 1.2、 列表项
- 1.3、mini列表项
- 1.4、列表
- 1.5、 已经实现的宏函数
- 1.5.1、 set列表项拥有者
- 1.5.2、 get列表项拥有者
- 1.5.3、 set列表项value
- 1.5.4、 检索(retrieve)列表项value
- 1.5.5、 检索(retrieve)列表头部列表项value
- 1.5.5、 get列表头部列表项
- 1.5.6、 get当前列表项的下一个列表项
- 1.5.7、 get列表尾部列表项地址
- 1.5.8、 判断列表是否为空
- 1.5.9、 列表长度数值
- 1.5.10、 获取列表下一项所有者
- 1.5.11、 从列表中删除一个项目
- 1.5.12、 移除列表项
- 1.5.13、 列表尾插
- 1.5.14、 获取列表第一条条目所有者
- 1.5.15、 检查列表项是否在列表中
- 1.5.16、 获取列表项的pxContainer
- 1.5.17、 查看列表是否被初始化
- 2、 list.c
前言
freeRTOS链表结构体和链表操作。源文件和头文件分别为list.c和list.h,list.c中主要为链表的创建,增删等操作,list.h为链表等相关的结构体,宏函数。
1、 list.h
1.1、未实现的宏
/* Define the macros to do nothing. */
#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 )
这些宏并没有实现,可以提供给用户进行自定义实现功能。
1.2、 列表项
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE //由1.1可以看到此成员没有实现
configLIST_VOLATILE TickType_t xItemValue; //被列出的值。在大多数情况下,用于按升序对列表进行排序。
struct xLIST_ITEM * configLIST_VOLATILE pxNext; //指向列表的下一个列表项的指针
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; //指向列表的上一个列表项的指针
void * pvOwner; //指向了包含该链表项的对象(通常是TCB),因此,FreeRTOS的链表与所有者互联,即所有者与链表项相互关联。
struct xLIST * configLIST_VOLATILE pxContainer; //指向放置此列表项的列表的指针(如果有的话)。
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE //由1.1可以看到此成员没有实现
};
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
1.3、mini列表项
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;
mini列表项大体上跟列表项差不多,但是结构体成员少了pvOwner,pxContainer。
1.4、列表
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE //由1.1可以看到此成员没有实现
volatile UBaseType_t uxNumberOfItems; //列表项的数量
ListItem_t * configLIST_VOLATILE pxIndex; //用来遍历列表,指向调用listGET_OWNER_OF_NEXT_ENTRY()返回的最后一项。
MiniListItem_t xListEnd; //包含最大可能项值的列表项,这意味着它总是在列表的末尾,因此用作标记。
listSECOND_LIST_INTEGRITY_CHECK_VALUE //由1.1可以看到此成员没有实现
} List_t;
mini列表项在列表的结构体中出现了,它的作用看注释或许不太明白?没关系接着往下看。
1.5、 已经实现的宏函数
1.5.1、 set列表项拥有者
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
1.5.2、 get列表项拥有者
#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )
1.5.3、 set列表项value
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
1.5.4、 检索(retrieve)列表项value
访问宏以检索列表项的值。这个值可以表示任何东西——例如任务的优先级,或者任务应该被解除阻塞的时间。
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
1.5.5、 检索(retrieve)列表头部列表项value
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
1.5.5、 get列表头部列表项
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
1.5.6、 get当前列表项的下一个列表项
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
1.5.7、 get列表尾部列表项地址
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
1.5.8、 判断列表是否为空
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
1.5.9、 列表长度数值
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
1.5.10、 获取列表下一项所有者
#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 ) ) \
//mini列表项没有列表项所有者的成员
{ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
} \
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
}
1.5.11、 从列表中删除一个项目
#define listREMOVE_ITEM( pxItemToRemove ) \
{ \
/* The list item knows which list it is in. Obtain the list from the list \
* item. */ \
List_t * const pxList = ( pxItemToRemove )->pxContainer; \
\
( pxItemToRemove )->pxNext->pxPrevious = ( pxItemToRemove )->pxPrevious; \
( pxItemToRemove )->pxPrevious->pxNext = ( pxItemToRemove )->pxNext; \
/* Make sure the index is left pointing to a valid item. */ \
if( pxList->pxIndex == ( pxItemToRemove ) ) \
{ \
pxList->pxIndex = ( pxItemToRemove )->pxPrevious; \
} \
\
( pxItemToRemove )->pxContainer = NULL; \
( pxList->uxNumberOfItems )--; \
}
1.5.12、 移除列表项
不返回值的uxListRemove()的版本。作为轻微的通过内联优化xTaskIncrementTick()。从列表中删除一个项目。列表项有一个指向它所在列表的指针,因此只需要将列表项传递到函数中。@param uxlistmove要删除的项。项目将从它的pxcontainer参数所指向的列表中删除自己。在列表项结束后,列表中剩余的项数被移除。
#define listREMOVE_ITEM( pxItemToRemove ) \
{ \
/* The list item knows which list it is in. Obtain the list from the list \
* item. */ \
List_t * const pxList = ( pxItemToRemove )->pxContainer; \
\
( pxItemToRemove )->pxNext->pxPrevious = ( pxItemToRemove )->pxPrevious; \
( pxItemToRemove )->pxPrevious->pxNext = ( pxItemToRemove )->pxNext; \
/* Make sure the index is left pointing to a valid item. */ \
if( pxList->pxIndex == ( pxItemToRemove ) ) \
{ \
pxList->pxIndex = ( pxItemToRemove )->pxPrevious; \
} \
\
( pxItemToRemove )->pxContainer = NULL; \
( pxList->uxNumberOfItems )--; \
}
1.5.13、 列表尾插
#define listINSERT_END( pxList, pxNewListItem ) \
{ \
ListItem_t * const pxIndex = ( pxList )->pxIndex; \
\
/* Only effective when configASSERT() is also defined, these tests may catch \
* the list data structures being overwritten in memory. They will not catch \
* data errors caused by incorrect configuration or use of FreeRTOS. */ \
listTEST_LIST_INTEGRITY( ( pxList ) ); \
listTEST_LIST_ITEM_INTEGRITY( ( pxNewListItem ) ); \
\
/* Insert a new list item into ( pxList ), but rather than sort the list, \
* makes the new list item the last item to be removed by a call to \
* listGET_OWNER_OF_NEXT_ENTRY(). */ \
( pxNewListItem )->pxNext = pxIndex; \
( pxNewListItem )->pxPrevious = pxIndex->pxPrevious; \
\
pxIndex->pxPrevious->pxNext = ( pxNewListItem ); \
pxIndex->pxPrevious = ( pxNewListItem ); \
\
/* Remember which list the item is in. */ \
( pxNewListItem )->pxContainer = ( pxList ); \
\
( ( pxList )->uxNumberOfItems )++; \
}
1.5.14、 获取列表第一条条目所有者
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
1.5.15、 检查列表项是否在列表中
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
1.5.16、 获取列表项的pxContainer
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
1.5.17、 查看列表是否被初始化
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
2、 list.c
2.1、vListInitialise
void vListInitialise( List_t * const pxList )
{
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); //用来遍历列表的指针指向mini列表,即为列表项尾部
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );
pxList->xListEnd.xItemValue = portMAX_DELAY;//mini列表项列表结束值为最大值
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
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;//最小值
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
2.2、vListInitialiseItem
void vListInitialiseItem( ListItem_t * const pxItem )
{
pxItem->pxContainer = NULL;//确保列表项没有被记录在列表中。
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
2.3、vListInsertEnd
void vListInsertEnd( List_t * const pxList,
ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex;//此时pxIndex指向的是mini列表项,即尾项
listTEST_LIST_INTEGRITY( pxList );//未实现
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );//未实现
/* Insert a new list item into pxList, but rather than sort the list,
* makes the new list item the last item to be removed by a call to
* listGET_OWNER_OF_NEXT_ENTRY(). */
pxNewListItem->pxNext = pxIndex;//让新插入的列表项的下一个指针域指向mini列表项,即指向尾项
pxNewListItem->pxPrevious = pxIndex->pxPrevious;//让新插入的列表项上一个指针域指向mini列表项的上一个指针域
//这两步实现新插入列表项的“左右手手拉手”
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
pxIndex->pxPrevious->pxNext = pxNewListItem;//让插入前的mini列表项下一项指针域指向新插入的列表项
pxIndex->pxPrevious = pxNewListItem;//让mini列表项上一个指针域指向新插入列表项
/* Remember which list the item is in. */
pxNewListItem->pxContainer = pxList;//将列表保存在列表项的pxContainer内
( pxList->uxNumberOfItems )++;
}
2.4、vListInsert
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
{
/* *** NOTE ***********************************************************
* If you find your application is crashing here then likely causes are
* listed below. In addition see https://www.FreeRTOS.org/FAQHelp.html for
* more tips, and ensure configASSERT() is defined!
* https://www.FreeRTOS.org/a00110.html#configASSERT
*
* 1) Stack overflow -
* see https://www.FreeRTOS.org/Stacks-and-stack-overflow-checking.html
* 2) Incorrect interrupt priority assignment, especially on Cortex-M
* parts where numerically high priority values denote low actual
* interrupt priorities, which can seem counter intuitive. See
* https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html and the definition
* of configMAX_SYSCALL_INTERRUPT_PRIORITY on
* https://www.FreeRTOS.org/a00110.html
* 3) Calling an API function from within a critical section or when
* the scheduler is suspended, or calling an API function that does
* not end in "FromISR" from an interrupt.
* 4) Using a queue or semaphore before it has been initialised or
* before the scheduler has been started (are interrupts firing
* before vTaskStartScheduler() has been called?).
* 5) If the FreeRTOS port supports interrupt nesting then ensure that
* the priority of the tick interrupt is at or below
* configMAX_SYSCALL_INTERRUPT_PRIORITY.
**********************************************************************/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */
{
/* There is nothing to do here, just iterating to the wanted
* insertion position. */
}
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* Remember which list the item is in. This allows fast removal of the
* item later. */
pxNewListItem->pxContainer = pxList;
( pxList->uxNumberOfItems )++;
}
2.5、uxListRemove
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in. Obtain the list from the list
* item. */
List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
/* Make sure the index is left pointing to a valid item. */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxItemToRemove->pxContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}