FreeRTOS進階列表和列表項示例分析
前言
FreeRTOS內(nèi)核調(diào)度大量使用了列表(list)和列表項(list item)數(shù)據(jù)結(jié)構(gòu)。我們?nèi)绻胍惶紽reeRTOS背后的運行機制,首先遇到的攔路虎就是列表和列表項。對于FreeRTOS內(nèi)核來說,列表就是它最基礎(chǔ)的部分。我們在這一章集中講解列表和列表項的結(jié)構(gòu)以及操作函數(shù),在下一章講解任務(wù)創(chuàng)建時,會用到本章的知識點。
列表被FreeRTOS調(diào)度器使用,用于跟蹤任務(wù),處于就緒、掛起、延時的任務(wù),都會被掛接到各自的列表中。用戶程序如果有需要,也可以使用列表。
FreeRTOS列表使用指針指向列表項。一個列表(list)下面可能有很多個列表項(list item),每個列表項都有一個指針指向列表。如圖1-1所示。
圖1-1:列表與列表項
列表項有兩種形式,全功能版的列表項xLIST_ITEM和迷你版的列表項xMINI_LIST_ITEM。我們來看一下它們具體的定義,先看全功能版。
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; /*指向列表中上一個列表項*/ void * pvOwner; /*指向一個任務(wù)TCB*/ void * configLIST_VOLATILE pvContainer; /*指向包含該列表項的列表 */ listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*用于檢測列表項數(shù)據(jù)是否完整*/ }; typedef struct xLIST_ITEM ListItem_t;
宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE用于檢查列表項數(shù)據(jù)是否完整,在projdefs.h中,如果將宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項數(shù)據(jù)完整性檢查,則宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE會被兩個已知的數(shù)值代替。
xItemValue是列表項值,通常是一個被跟蹤的任務(wù)優(yōu)先級或是一個調(diào)度事件的計數(shù)器值。如果任務(wù)因為等待從隊列取數(shù)據(jù)而進入阻塞狀態(tài),則任務(wù)的事件列表項的列表項值保存任務(wù)優(yōu)先級有關(guān)信息,狀態(tài)列表項的列表項值保存阻塞時間有關(guān)的信息。這個變量被configLIST_VOLATILE修飾,configLIST_VOLATILE被映射成C語言關(guān)鍵字volatile,表明這個變量是“易變的”,告訴編譯器不得對這個變量進行代碼優(yōu)化,因為列表項的成員可能會在中斷服務(wù)程序中被更新。關(guān)于volatile關(guān)鍵字,如果不是熟悉的話,可以參考我的博文《編寫優(yōu)質(zhì)嵌入式C程序》第3.2.4節(jié)。
pxNext和pxPrevious是列表項類型指針,用來指向列表中下一個和上一個列表項,通過這兩個指針,列表項之間可以形成類似雙向鏈表結(jié)構(gòu)。
指針pvOwner通常指向一個任務(wù)TCB。
指針pvContainer指向包含該列表項的列表。
迷你版的列表項xMINI_LIST_ITEM是全功能版列表項xLIST_ITEM的一個子集,定義如下所示:
struct xMINI_LIST_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; typedef struct xMINI_LIST_ITEM MiniListItem_t;
既然有了全功能版的列表項,為什么還要聲明迷你版的列表項呢?這是因為列表結(jié)構(gòu)體需要一個列表項成員,但又不需要列表項中的所有字段,所以才有了迷你版列表項。列表結(jié)構(gòu)體定義為:
typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE /*用于檢測列表項數(shù)據(jù)是否完整*/ configLIST_VOLATILE UBaseType_t uxNumberOfItems; ListItem_t * configLIST_VOLATILE pxIndex; /*用于遍歷列表*/ MiniListItem_t xListEnd; /*列表項*/ listSECOND_LIST_INTEGRITY_CHECK_VALUE /*用于檢測列表項數(shù)據(jù)是否完整*/ }List_t;
和列表項定義相同,宏listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE用于檢查列表項數(shù)據(jù)是否完整,在projdefs.h中,如果將宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項數(shù)據(jù)完整性檢查,則宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE會被兩個已知的數(shù)值代替。
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))。
下面我們看一下列表操作。FreeROTS提供了幾個API函數(shù),用于初始化列表和列表項以及列表項插入操作。
1.初始化列表
列表結(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 ); }
如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項數(shù)據(jù)完整性檢查,則宏listSET_LIST_INTEGRITY_CHECK_1_VALUE()和listSET_LIST_INTEGRITY_CHECK_2_VALUE被一個已知值代替,默認(rèn)為0x5a5a(16位架構(gòu))或者0x5a5a5a5a(32位架構(gòu))。
假設(shè)禁止列表數(shù)據(jù)完整性檢查,初始化后的列表如圖1-2所示,uxNumberOfItems被初始化為0,xListEnd.xItemValue初始化為0xffffffff,pxIndex、xListEnd.pxNext和xListEnd.pxPrevious初始化為指向列表項xListEnd。
圖1-2:初始化后的列表
2.初始化列表項
列表項的初始比較簡單,只要確保列表項不在任何列表中即可。
void vListInitialiseItem( ListItem_t * const pxItem ) { pxItem->pvContainer = NULL; /*設(shè)置為已知值,用于檢測列表項數(shù)據(jù)是否完整*/ listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem ); listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem ); }
如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項數(shù)據(jù)完整性檢查,則宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE會被兩個已知的數(shù)值代替,默認(rèn)為0x5a5a(16位架構(gòu))或者0x5a5a5a5a(32位架構(gòu))。
假設(shè)禁止列表項數(shù)據(jù)完整性檢查,初始化后的列表項如圖1-3所示。僅是將指針pvContainer設(shè)置為空指針,該指針用于指向包含該列表項的列表,這里設(shè)置為NULL表示這個列表項不屬于任何列表。
圖1-3:初始化后的列表項
3.將列表項插入到列表中,列表項所在的位置取決于列表項的列表項值(xItemValue)。
每個列表項對象都有一個列表項值(xItemValue),通常是一個被跟蹤的任務(wù)優(yōu)先級或是一個調(diào)度事件的計數(shù)器值。調(diào)用API函數(shù)vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem)可以將pxNewListItem指向的列表項插入到pxList指向的列表中,列表項在列表的位置由pxNewListItem->xItemValue決定,按照升序排列。
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) { ListItem_t *pxIterator; const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* 檢查列表和列表項數(shù)據(jù)的完整性,僅當(dāng)configASSERT()定義時有效。*/ 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 ) { /* 這里為空 */ } } pxNewListItem->pxNext =pxIterator->pxNext; pxNewListItem->pxNext->pxPrevious= pxNewListItem; pxNewListItem->pxPrevious =pxIterator; pxIterator->pxNext = pxNewListItem; pxNewListItem->pvContainer = ( void* ) pxList; ( pxList->uxNumberOfItems )++; }
根據(jù)xItemValue的值將新的列表項插入到列表。如果列表中存在與新列表項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),則表示到達了列表結(jié)束位置。
我們用圖示的方法來講解這個函數(shù),我們假設(shè)一個列表項值(xItemValue)為32的列表項插入到如圖1-2所示的初始化后的列表中,調(diào)用vListInsert()函數(shù)后,列表和列表項的關(guān)系如圖1-4所示。列表項xListItem_1的成員指針pxNext和pxPrevious都指向了xListEnd,而xListEnd的成員指針pxNext和pxPrevious都指向了列表項xListItem_1;列表項xListItem_1的成員指針pvContainer指向了列表xList_1;列表成員uxNumberOfItems為1。
圖1-4:將列表項插入到列表
在此基礎(chǔ)上,如果再將一個列表項值(xItemValue)為40的列表項插入到列表中,調(diào)用vListInsert()函數(shù)后,列表和列表項的關(guān)系如圖1-5所示。
圖1-5:將列表項插入到列表
4.將列表項插入到列表末端
第3節(jié)講的API插入函數(shù)是根據(jù)列表項中的列表項值(xItemValue)來決定插入位置的,本節(jié)所講的API函數(shù)vListInsertEnd()是簡單的將列表項插入到列表的末端。在下一章任務(wù)創(chuàng)建分析的文章中,將會遇到這個API函數(shù),到時再以圖標(biāo)的形式分析這個函數(shù),現(xiàn)在給出這個函數(shù)的源碼。
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 )++; }
以上就是FreeRTOS進階系列列表和列表項示例分析的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS進階列表和列表項的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
FreeRTOS實時操作系統(tǒng)結(jié)構(gòu)示例
這篇文章主要介紹了FreeRTOS實時操作系統(tǒng)結(jié)構(gòu)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04freertos實時操作系統(tǒng)臨界段保護開關(guān)中斷及進入退出
這篇文章主要介紹了freertos實時操作系統(tǒng)臨界段保護開關(guān)中斷及進入退出,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04FreeRTOS實時操作系統(tǒng)的任務(wù)概要講解
這篇文章主要為大家介紹了FreeRTOS實時操作系統(tǒng)的任務(wù)概要講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04FreeRTOS軟件定時器apollo中斷狀態(tài)判斷
這篇文章主要為大家介紹了FreeRTOS軟件定時器apollo中斷狀態(tài)的判斷,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04FreeRTOS實時操作系統(tǒng)的任務(wù)通知方法
這篇文章主要為大家介紹了FreeRTOS實時操作系統(tǒng)的任務(wù)通知方法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04FreeRTOS動態(tài)內(nèi)存分配管理heap_1示例
這篇文章主要為大家介紹了FreeRTOS動態(tài)內(nèi)存分配管理heap_1的示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-04-04