FreeRTOS List簡易分析
阿新 • • 發佈:2020-12-10
FreeRTOS從簡單的List入手
- 前言:開啟List.c檔案來看,200多行,並不是很多,詳細看內容,其實就是一個雙向連結串列的增和刪
1.結構體List_t
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;
- 能力有限只能挑幾個來講C
變數名 | 作用 |
---|---|
listFIRST_LIST_INTEGRITY_CHECK_VALUE | 檢查資料是否完整 |
uxNumberOfItems | 掛接在這個連結串列的連結串列項數目 |
xListEnd | 指向連結串列的尾部 |
2.結構體xLIST_ITEM
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. */ };
變數名 | 作用 |
---|---|
xItemValue | 列表項值,用於按降序對列表進行排序 |
pxNext | 指向下一個列表項 |
pxPrevious | 指向前一個列表項 |
pvOwner | 指向任務塊TCB |
pvContainer | 指向屬於的連結串列 |
正如我開頭所說,結構體ListItem就是連結串列結點,結構體List就是連結串列,ListItem鏈到List上。
3.連結串列的操作函式
3.1連結串列的初始化
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; /* 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 The mini list structure is used as the list end to save RAM. 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. This is checked and valid. */ 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 ); }
->連結串列的初始化流程
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd )
指向尾結點pxList->xListEnd.xItemValue = portMAX_DELAY
在32位架構下portMAX_DELAY
為0xFFFFFFFFpxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd )
next指向尾結點pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd )
previous指向尾結點pxList->uxNumberOfItems = ( UBaseType_t ) 0U
設定當前掛載結點為0
3.2連結串列項的初始化
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 );
}
->連結串列項的初始化流程
只需要pxItem->pvContainer = NULL
,把這個連結串列項指向的連結串列置空即可 ,表示連結串列項不屬於任何連結串列
3.3向連結串列增加連結串列項:
3.3.1. 尾插
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(). */
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 )++;
}
->尾插流程
ListItem_t * const pxIndex = pxList->pxIndex
獲取最後一個結點pxNewListItem->pxNext = pxIndex
將新結點的next指向最後一個結點pxNewListItem->pxPrevious = pxIndex->pxPrevious
將新結點的previous指向最後結點的前一項pxIndex->pxPrevious->pxNext = pxNewListItem
將最後結點的next指向新結點pxIndex->pxPrevious = pxNewListItem
將最後結點的previous指向新結點pxNewListItem->pvContainer = ( void * ) pxList
新結點屬於pxList下的結點( pxList->uxNumberOfItems )++
pxList結點的總數目加1
3.3.2.升序插入
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
{
/* *** NOTE ***********************************************************
If you find your application is crashing here then likely causes are
listed below. In addition see http://www.freertos.org/FAQHelp.html for
more tips, and ensure configASSERT() is defined!
http://www.freertos.org/a00110.html#configASSERT
1) Stack overflow -
see http://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
http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
of configMAX_SYSCALL_INTERRUPT_PRIORITY on
http://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?).
**********************************************************************/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
{
/* 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 )++;
}
->升序插入流程
-
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
獲取插入的結點值 -
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
遍歷到小於 xValueOfInsertion 的值
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
做的就是把新結點插入到遍歷後pxIterator
的Next
-
pxNewListItem->pvContainer = ( void * ) pxList
該結點屬於List -
List的結點數目加1
3.4 刪除連結串列項
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;
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;
}
->刪除流程
-
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
找到該連結串列項的所在連結串列 -
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
A_Item -> B_Item -> C_Item,假設B為要刪除的Item,結果為A_Item - > CItem
-
if( pxList->pxIndex == pxItemToRemove ) { pxList->pxIndex = pxItemToRemove->pxPrevious; }
如果該Item為最後,A_Item -> Last_Item, 那麼A就會成為Lash_Item
-
pxItemToRemove->pvContainer = NULL; ( pxList->uxNumberOfItems )--;
該Item不屬於任何List,並把原List的Item數目減1