列表和列表項是FreeRTOS的一個數(shù)據(jù)結(jié)構(gòu), FreeRTOS內(nèi)核調(diào)度大量使用了列表(list)和列表項(list item)數(shù)據(jù)結(jié)構(gòu)。
FreeRTOS列表使用指針指向列表項。一個列表(list)下面可能有很多個列表項(list item),每個列表項都有一個指針指向列表。

一、什么是列表和列表項
列表概念上和鏈表有點相似,用來追蹤FreeRTOS中的任務(wù)。與列表相關(guān)的東西都在list.c和list.h中。
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE UBaseType_t uxNumberOfItems;//用來記錄列表中列表項的數(shù)量
ListItem_t * configLIST_VOLATILE pxIndex; //pxIndex,用來記錄當(dāng)前列表項索引號,用于遍歷列表
MiniListItem_t xListEnd; //列表中最后一個列表項,用來表示列表結(jié)束
listSECOND_LIST_INTEGRITY_CHECK_VALUE
} List_t;
- uxNumberOfItems表示該列表中掛接的列表項數(shù)目,0表示列表為空。
- 列表項類型指針用于遍歷列表,列表初始化后,這個指針指向&xListEnd。通過宏listGET_OWNER_OF_NEXT_ENTRY()來獲取列表中的下一個列表項。
- 列表項xListEnd用于標(biāo)記列表結(jié)束。xListEnd.xItemValue被初始化為一個常數(shù),其值與硬件架構(gòu)相關(guān),為0xFFFF(16位架構(gòu))或者0xFFFFFFFF(32位架構(gòu))。
列表項
列表項就是存放在列表中的項目。
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*用于檢測列表項數(shù)據(jù)是否完整*/
configLIST_VOLATILE TickType_t xItemValue; //列表項值
struct xLIST_ITEM * configLIST_VOLATILE pxNext; //下一列表項
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; //上一個列表項,同pxNext配合可實現(xiàn)雙向鏈表功能
void * pvOwner; //記錄此鏈表項歸誰所有,指向一個任務(wù)TCB
void * configLIST_VOLATILE pvContainer; //記錄此列表項歸哪個列表,指向包含該列表項的列表
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*用于檢測列表項數(shù)據(jù)是否完整*/
};
typedef struct xLIST_ITEM ListItem_t;
-
xItemValue是列表項值,通常是一個被跟蹤的任務(wù)優(yōu)先級或是一個調(diào)度事件的計數(shù)器值。
如果任務(wù)因為等待從隊列取數(shù)據(jù)而進(jìn)入阻塞狀態(tài),則任務(wù)的事件列表項的列表項值保存任務(wù)優(yōu)先級有關(guān)信息,狀態(tài)列表項的列表項值保存阻塞時間有關(guān)的信息。
迷你列表項
既然有了全功能版的列表項,為什么還要聲明迷你版的列表項呢?
這是因為列表結(jié)構(gòu)體需要一個列表項成員,但又不需要列表項中的所有字段,所以才有了迷你版列表項。
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; //上一個列表項,同pxNext配合可實現(xiàn)雙向鏈表功能
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
二、列表和列表項初始化
新創(chuàng)建或定義的列表需要對其做初始化處理,列表的初始化可以通過vListInitialise()函數(shù)來完成。
列表結(jié)構(gòu)體中包含一個列表項成員,主要用于標(biāo)記列表結(jié)束。初始化列表就是把這個列表項插入到列表中。
void vListInitialise( List_t * const pxList )
{
/*列表索引指向列表項*/
pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );
/* 設(shè)置為最大可能值 */
pxList->xListEnd.xItemValue =portMAX_DELAY;
/* 列表項xListEnd的pxNext和pxPrevious指針指向了它自己 */
pxList->xListEnd.pxNext = (ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious= ( ListItem_t * ) &( pxList->xListEnd );
pxList->uxNumberOfItems = ( UBaseType_t) 0U;
/* 設(shè)置為已知值,用于檢測列表數(shù)據(jù)是否完整*/
listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList );
}
列表項的初始比較簡單,只要確保列表項不在任何列表中即可。
void vListInitialiseItem( ListItem_t * const pxItem )
{
pxItem->pvContainer = NULL;/不屬于任何list
//初始化用于完成性檢查的變量
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
其他內(nèi)容,在實際使用時進(jìn)行賦值。
三、列表項插入和刪除
列表項所在的位置取決于列表項的列表項值(xItemValue)
3.1 列表項插入
vListInsert(List_t *const pxList, ListItem_t *const pxNewListItem)
參數(shù):列表項要插入的列表和要插入的列表項
要插入的位置由列表項中成員變量xItemValue來決定。
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 );
/*將新的列表項插入到列表,根據(jù)xItemValue的值降序插入列表。*/
if( xValueOfInsertion == portMAX_DELAY ) // 插入末尾
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );\
pxIterator->pxNext->xItemValue <= xValueOfInsertion;\
pxIterator = pxIterator->pxNext )
{ }// empty
}
//插入中間位置時,插在Interator后面
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
//列表項在列表中了,列表項成員變量pvContainer記錄此列表項屬于哪個列表
pxNewListItem->pvContainer = ( void * ) pxList;
//表示又加了一個列表項
( pxList->uxNumberOfItems )++;
}
portMAX_DELAY:如果列表中存在與新列表項xItemValue值相同的列表項,則新插入的列表項位于它之后。如果列表項的xItemValue值等于portMAX_DELAY(列表結(jié)束標(biāo)記,我們在講列表數(shù)據(jù)結(jié)構(gòu)時,說到每個列表數(shù)據(jù)結(jié)構(gòu)體中都有一個列表項成員xListEnd,用于標(biāo)記列表結(jié)束。xListEnd.xItemValue被初始化為一個常數(shù),其值與硬件架構(gòu)相關(guān),為0xFFFF或者0xFFFFFFFF。這個常數(shù)在移植層定義,即宏portMAX_DELAY),則表示到達(dá)了列表結(jié)束位置。
3.2 將列表項插入到列表末端
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t* const pxIndex = pxList->pxIndex;
/*檢查列表和列表項數(shù)據(jù)的完整性,僅當(dāng)configASSERT()定義時有效。*/
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 )++;
}