Freertos使用的是改良的雙向鏈表。
#1 list item 增加了完整性檢測(configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 配置),
#2 增加了list item的owner(owner一般指的就是任務控制塊TCB);
#3 增加了list的item的Container容器(指定item所在的list);
根據TCB里面的兩個列表項進行分類:1.任務狀態列表,有就緒列表、延時列表、掛起列表等。2.事件信號量隊列Queue,這個隊列里面,有WaitToSend列表和WaitToRcv列表。
#4 xItemValue則是鏈表進行排序時的參考值,list在不同地方引用,一般需要按照xItemValue進行排序;
一般task中引用按照delay時間排序,queue中WaitToSend/Rcv列表按照優先級排序,timer中按照超時時間排序。
#5 Freertos代碼很精簡高效,這種改良的list在額外開銷和效率之間做了一個很好的平衡,
除此之外,還專門定義縮減的list item,用於表示鏈表結構中的首尾鏈接item,
xMINI_LIST_ITEM前面字節定義和xLIST_ITEM一致,可以直接轉型為xLIST_ITEM,以讀取鏈表的首尾元素。
xMINI_LIST_ITEM在別的地方沒有使用,可能僅僅是為了減少內存占用。
以上出自:http://www.tk4479.net/jorhai/article/details/65455328
一、List_t,作用類似表頭,管理一個列表
/* * Definition of the type of queue used by the scheduler. */ typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE UBaseType_t uxNumberOfItems; ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ } List_t;
說明:
1、listFIRST_LIST_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_INTEGRITY_CHECK_VALUE是頭和尾保護,防止越界(其實就是寫特定數據),需要把configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES配置為1;
2、uxNumberOfItems 本List_t中有多少個項;
3、pxIndex 指向列表其中一項的地址;【這一項是“listGET_OWNER_OF_NEXT_ENTRY獲取時”最后返回的item】。
4、xListEnd指向列表最后一項,類型為MiniListItem_t。
二、ListItem_t
/* * Definition of the only type of object that a list can contain. */ struct xLIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item.
There is therefore a two way link between the object containing the list item and the list item itself. */ void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */ listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ }; typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
說明:
1、listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE保護,需要把configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES配置為1;
2、xItemValue 本ListItem_t項的值,大多數用於排序,比如延時;
3、pxNext 指向下一項;
4、pxPrevious 指向前一項;
5、pvOwner 指向擁有者,一般是TCB;
6、pvContainer 指向所屬的列表;
三、MiniListItem_t
struct xMINI_LIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE TickType_t xItemValue; struct xLIST_ITEM * configLIST_VOLATILE pxNext; struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; }; typedef struct xMINI_LIST_ITEM MiniListItem_t;
說明:
1、只是少了pvOwner和pvContainer,一般用於列表的結尾,表示結束;
四、listGET_OWNER_OF_NEXT_ENTRY ()
#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; \ }
get下一個列表項的onwer
如果下一列表項是xListEnd,則再切換下一項。這里不明白設置這個xListEnd的用意。
四 plus、
/* * Access macro to retrieve the value of the list item at the head of a given * list. * * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE * \ingroup LinkedList */ #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) /* * Return the list item at the head of the list. * * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY * \ingroup LinkedList */ #define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
可以看出使用這個墊底的 xListEnd.pxNext 竟然可以獲取到整個 List 的 HEAD_ENTRY。
以下為list.c中的內容:
五、初始化List_t
list.h
/* * Must be called before a list is used! This initialises all the members * of the list structure and inserts the xListEnd item into the list as a * marker to the back of the list. * * @param pxList Pointer to the list being initialised. * * \page vListInitialise vListInitialise * \ingroup LinkedList */ void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
list.c void vListInitialise( List_t * const pxList ) { /* The list structure contains a list item which is used to mark the end of the list. To initialise the list the list end is inserted as the only list entry. */ pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ /* The list end value is the highest possible value in the list to ensure it remains at the end of the list. */ pxList->xListEnd.xItemValue = portMAX_DELAY; //(TickType_t)(0xFFFF_FFFF ul) /* The list end next and previous pointers point to itself so we know when the list is empty. */ pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 This is checked and valid. */ pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. */ pxList->uxNumberOfItems = ( UBaseType_t ) 0U; /* Write known values into the list if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); }
說明:
1、pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); 在list最后放一項,作為標記。
2、pxList->xListEnd.xItemValue = portMAX_DELAY; 這一項的值為32bit的最大值,保證排序的時候,仍排在最后。
3、xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); 注意一下這里。
六、初始化Item
void vListInitialiseItem( ListItem_t * const pxItem ) { /* Make sure the list item is not recorded as being on a list. */ pxItem->pvContainer = 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 ); }
七、插入
插入到末尾:
void vListInsertEnd( List_t * const pxList, ListItem_t * const 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().
不對list排序,而是把新的item作為 “listGET_OWNER_OF_NEXT_ENTRY獲取時” 最后才能獲取到的item。
*/ 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 )++; }
按升序插入:
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) { ListItem_t *pxIterator; const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* 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 the new list item into the list, sorted in xItemValue order. If the list already contains a list item with the same item value then the new list item should be placed after it. This ensures that TCB's which are stored in ready lists (all of which have the same xItemValue value) get a share of the CPU. However, if the xItemValue is the same as the back marker the iteration loop below will not end. Therefore the value is checked first, and the algorithm slightly modified if necessary. */ 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; /* Remember which list the item is in. This allows fast removal of the item later. */ pxNewListItem->pvContainer = ( void * ) pxList; ( pxList->uxNumberOfItems )++; }
八、移除
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 = ( List_t * ) pxItemToRemove->pvContainer; 利用Item的Container獲得了他的管理表頭!!【這回知道->優先級比()高了】 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->pvContainer = NULL; ( pxList->uxNumberOfItems )--; return pxList->uxNumberOfItems; }