freertos list
- 基本類型
- 結構體
- ListItem_t (list.h)
- List_t (list.h)
- 宏函數
- 函數
- vListInitialise
- vListInitialiseItem
- vListInsertEnd
- vListInsert
- uxListRemove
基本類型
freertos為了兼容性,重新定義了基本類型,像BaseType_t,TickType_t等等,這些定義都在portable文件夾下對應編譯器文件夾下對應內核文件夾的portmacro.h
里。比如armcm3下的BaseType_t就是long類型,我一直以為long是64位,就很奇怪,不應該是32位嗎,問了ai查了資料后才明白了,了解到數據模型。重新定義基本類型可以屏蔽cpu內核和編譯器對數據類型位數的影響,為了讓常用數據類型與cpu位數匹配。看到這我也是第一次對這個問題比以前有更深入一點的研究,為了統一理解,引入了 數據模型 ,有ILP32,LP64,LLP64等等,I表示int,L表示long,P表示指針類型,比如ILP32就是int,long,指針都是32位的,主要是解決一些有位數差異的類型。
結構體
ListItem_t (list.h)
鏈表節點
struct xLIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUEconfigLIST_VOLATILE TickType_t xItemValue;struct xLIST_ITEM * configLIST_VOLATILE pxNext;struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;void * pvOwner;struct xLIST * configLIST_VOLATILE pxContainer;listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
typedef struct xLIST_ITEM ListItem_t;#if ( configUSE_MINI_LIST_ITEM == 1 )struct xMINI_LIST_ITEM{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUEconfigLIST_VOLATILE TickType_t xItemValue;struct xLIST_ITEM * configLIST_VOLATILE pxNext;struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;};typedef struct xMINI_LIST_ITEM MiniListItem_t;
#elsetypedef struct xLIST_ITEM MiniListItem_t;
#endif
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
見名知義,鏈表節點完整性檢查值,具體定義在本結構體定義的前面,如果configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES
配置為1的時候這兩個宏會被定義成TickType_t
的字段,如果配置為0就啥也沒有。- 關于
configLIST_VOLATILE
的說明在list.h開頭,鏈表結構體的成員變量是從中斷中被修改的,因此從理論上來說應該將它們聲明為 volatile。然而,這些成員變量僅在“功能上是原子性”的方式下被修改(即在臨界區或調度器掛起期間進行修改),并且它們要么是通過引用傳入函數的,要么是通過一個 volatile 變量進行索引訪問的。因此,在目前為止測試的所有使用場景中,可以省略 volatile 修飾符,從而帶來一定程度的性能提升,而不會對功能行為產生不良影響。目前為止IAR、ARM 和 GCC 編譯器在設置為最大優化級別時所生成的匯編指令已經被檢查過,可以不加,但是隨著編譯器的發展可能會被錯誤優化,遇到這種情況可以在FreeRTOSConfig.h添加#define configLIST_VOLATILE volatile
。 pxNext
指向下一個節點。pxPrevious
指向前一個結點。pvOwner
指向一些與節點相關的其他數據,可能指向任務控制塊等,pxContainer
指向當前鏈表項所屬的鏈表,可用于判斷該項是否已加入某個鏈表。xItemValue
節點值我猜測可能和任務分配時間有關。- 還提供了一種迷你鏈表節點,去除了
pvOwner
和pxContainer
兩個字段,只保留了鏈表結構部分。
List_t (list.h)
給調度器使用的鏈表。
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;
uxNumberOfItems
當前鏈表中的節點數量。pxIndex
用于遍歷鏈表的指針,相當于一個游標。xListEnd
是特殊的鏈表節點,從源碼注釋來看,xItemValue是最大可能值,它永遠位于鏈表末尾,作為結束標記(從這里的意思可以看出這里的鏈表可能是升序排序的,后面看調度器的代碼應該就清楚了)。
宏函數
比較簡單,根據名字就基本知道功能,簡單羅列一下。
- listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )
設置鏈表節點pxListItem的pxOwner為pxOwner - listGET_LIST_ITEM_OWNER( pxListItem )
返回pxListItem的pvOwner - listSET_LIST_ITEM_VALUE( pxListItem, xValue )
設置pxListItem的值xItemValue為xValue - listGET_LIST_ITEM_VALUE( pxListItem )
返回pxListItem的值xItemValue - listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )
返回pxList 的頭節點的值xItemValue - listGET_HEAD_ENTRY( pxList )
返回pxList 的頭節點,也是尾節點的下一個節點,可以看出是個雙向循環鏈表 - listGET_NEXT( pxListItem )
返回pxListItem的下一個節點 - listGET_END_MARKER( pxList )
返回pxList 的尾節點 - listLIST_IS_EMPTY( pxList )
返回鏈表是否為空 - listCURRENT_LIST_LENGTH( pxList )
返回鏈表長度 - listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )
返回下一個節點(跳過尾節點)的pvOwner給pxTCB - listREMOVE_ITEM( pxItemToRemove )
移除pxItemToRemove節點,把pxIndex移到pxItemToRemove 前一個節點 - listINSERT_END( pxList, pxNewListItem )
尾部插入pxNewListItem - listGET_OWNER_OF_HEAD_ENTRY( pxList )
返回頭節點的pvOwner - listIS_CONTAINED_WITHIN( pxList, pxListItem )
pxList是否包含pxListItem - listLIST_IS_INITIALISED( pxList )
pxList 是否初始化了
函數
這些函數的聲明都有PRIVILEGED_FUNCTION
宏,特權函數,類似的宏還有特權變量,定義在mpu_wrapper.h
#define PRIVILEGED_FUNCTION attribute( ( section( “privileged_functions” ) ) )
特權函數會分配到特殊的段,為MPU(內存保護單元)提供支持。
vListInitialise
void vListInitialise( List_t * const pxList )
{traceENTER_vListInitialise( pxList ); //調試用的好像,先不管他pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); //游標指向尾節點listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );//設置節點完整性檢查值為1pxList->xListEnd.xItemValue = portMAX_DELAY;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 ) );}#endifpxList->uxNumberOfItems = ( UBaseType_t ) 0U;listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );traceRETURN_vListInitialise();
}
初始化鏈表,初始化鏈表尾節點。
vListInitialiseItem
void vListInitialiseItem( ListItem_t * const pxItem )
{traceENTER_vListInitialiseItem( pxItem );/* Make sure the list item is not recorded as being on a list. */pxItem->pxContainer = NULL;/* Write known values into the list item if* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );traceRETURN_vListInitialiseItem();
}
沒啥好說的
vListInsertEnd
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{ListItem_t * const pxIndex = pxList->pxIndex;traceENTER_vListInsertEnd( pxList, pxNewListItem );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->pxContainer = pxList;( pxList->uxNumberOfItems ) = ( UBaseType_t ) ( pxList->uxNumberOfItems + 1U );traceRETURN_vListInsertEnd();
}
在pxIndex后面插入新的節點
vListInsert
void vListInsert( List_t * const pxList,ListItem_t * const pxNewListItem )
{ListItem_t * pxIterator;const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;traceENTER_vListInsert( pxList, pxNewListItem );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 ){/* 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;pxNewListItem->pxContainer = pxList;( pxList->uxNumberOfItems ) = ( UBaseType_t ) ( pxList->uxNumberOfItems + 1U );traceRETURN_vListInsert();
}
將一個新的節點按其 xItemValue 的大小順序插入到鏈表中,保持鏈表始終按升序排列。
uxListRemove
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{List_t * const pxList = pxItemToRemove->pxContainer;traceENTER_uxListRemove( pxItemToRemove );pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;/* Only used during decision coverage testing. */mtCOVERAGE_TEST_DELAY();if( pxList->pxIndex == pxItemToRemove ){pxList->pxIndex = pxItemToRemove->pxPrevious;}else{mtCOVERAGE_TEST_MARKER();}pxItemToRemove->pxContainer = NULL;( pxList->uxNumberOfItems ) = ( UBaseType_t ) ( pxList->uxNumberOfItems - 1U );traceRETURN_uxListRemove( pxList->uxNumberOfItems );return pxList->uxNumberOfItems;
}