freeRTOS源码解析2--链表管理
源码目录:\FreeRTOS\list.c、\FreeRTOS\list.h
代码比较简单就不举具体的例子了,直接分析源码。
数据结构:
1、链表项
struct xLIST_ITEM
{
configLIST_VOLATILE TickType_t xItemValue; /* 项值,链表中升序排序 */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 下一个链表项 */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /* 上一个链表项 */
void * pvOwner; /* 指向该项的持有者(通常为TCB)。 因此在包含链表项的链表和链表项本身之间存在双向链接。 */
struct xLIST * configLIST_VOLATILE pxContainer; /* 指向该链表项所在链表(如果有的话)。 */
};
typedef struct xLIST_ITEM ListItem_t;
struct xMINI_LIST_ITEM
{
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
2、链表
typedef struct xLIST
{
volatile UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex; /* 用于遍历链表。指向listGET_OWNER_OF_NEXT_ENTRY()返回的最后一项。 */
MiniListItem_t xListEnd; /* 包含最大可能项值的列表项,这意味着它总是在列表的末尾,因此可用作标记。 */
} List_t;
初始化链表
void vListInitialise( List_t * const pxList ):
1 void vListInitialise( List_t * const pxList ) 2 { 3 /* The list structure contains a list item which is used to mark the 4 * end of the list. To initialise the list the list end is inserted 5 * as the only list entry. */ 6 /* 链表结构包含一个用于标记尾部的链表项。为了初始化链表, 7 * 将xListEnd作为唯一的链表项插入。 */ 8 pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); 9 10 /* The list end value is the highest possible value in the list to 11 * ensure it remains at the end of the list. */ 12 /* xListEnd的项值应为链表中所有项的最大值,以确保它始终处于尾部。 */ 13 pxList->xListEnd.xItemValue = portMAX_DELAY; 14 15 /* The list end next and previous pointers point to itself so we know 16 * when the list is empty. */ 17 /* xListEnd的下一个和上一个均指向自己,那么就可知该链表为空。 */ 18 pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); 19 pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); 20 21 pxList->uxNumberOfItems = ( UBaseType_t ) 0U; 22 }
初始化链表项
void vListInitialiseItem( ListItem_t * const pxItem ):
1 void vListInitialiseItem( ListItem_t * const pxItem ) 2 { 3 /* Make sure the list item is not recorded as being on a list. */ 4 /* 确保链表项没有被记录为在链表中。 */ 5 pxItem->pxContainer = NULL; 6 }
将pxNewListItem链表项插入pxList链表尾部
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ):
1 void vListInsertEnd( List_t * const pxList, 2 ListItem_t * const pxNewListItem ) 3 { 4 ListItem_t * const pxIndex = pxList->pxIndex; 5 6 /* Insert a new list item into pxList, but rather than sort the list, 7 * makes the new list item the last item to be removed by a call to 8 * listGET_OWNER_OF_NEXT_ENTRY(). */ 9 /* 向pxList中插入一个新的链表项,但不是对链表进行排序, 10 * 而是通过调用listGET_OWNER_OF_NEXT_ENTRY()将新链表项作为最后一个要删除的项。 */ 11 pxNewListItem->pxNext = pxIndex; 12 pxNewListItem->pxPrevious = pxIndex->pxPrevious; 13 14 pxIndex->pxPrevious->pxNext = pxNewListItem; 15 pxIndex->pxPrevious = pxNewListItem; 16 17 /* Remember which list the item is in. */ 18 /* 记录链表项所在链表*/ 19 pxNewListItem->pxContainer = pxList; 20 21 ( pxList->uxNumberOfItems )++; 22 }
按pxNewListItem链表项的元素大小,从小到大插入到链表pxList适当位置
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ):
1 void vListInsert( List_t * const pxList, 2 ListItem_t * const pxNewListItem ) 3 { 4 ListItem_t * pxIterator; 5 const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; 6 7 /* Insert the new list item into the list, sorted in xItemValue order. 8 * 9 * If the list already contains a list item with the same item value then the 10 * new list item should be placed after it. This ensures that TCBs which are 11 * stored in ready lists (all of which have the same xItemValue value) get a 12 * share of the CPU. However, if the xItemValue is the same as the back marker 13 * the iteration loop below will not end. Therefore the value is checked 14 * first, and the algorithm slightly modified if necessary. */ 15 /* 将新的链表项插入到链表中,按xItemValue大小排序。 16 * 如果链表中已经包含了具有相同项值的链表项,那么新的链表项应该放在它的后面。 17 * 这确保存储在就绪链表中的TCB(它们都具有相同的xItemValue值)都能获得CPU的份额。 18 * 但是,如果xItemValue与List中的xListEnd的值相同,则下面的迭代循环将不会结束。 19 * 因此,首先检查该值,然后在必要时稍微修改算法。 */ 20 if( xValueOfInsertion == portMAX_DELAY ) 21 { 22 pxIterator = pxList->xListEnd.pxPrevious; 23 } 24 else 25 { 26 for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */ 27 { 28 /* There is nothing to do here, just iterating to the wanted 29 * insertion position. */ 30 /* 什么都不做,只遍历到所需的位置。 */ 31 } 32 } 33 34 pxNewListItem->pxNext = pxIterator->pxNext; 35 pxNewListItem->pxNext->pxPrevious = pxNewListItem; 36 pxNewListItem->pxPrevious = pxIterator; 37 pxIterator->pxNext = pxNewListItem; 38 39 /* Remember which list the item is in. This allows fast removal of the 40 * item later. */ 41 /* 记录链表项所在链表。这样能快速得将项移出链表。 */ 42 pxNewListItem->pxContainer = pxList; 43 44 ( pxList->uxNumberOfItems )++; 45 }
当插入的链表项的值等于portMAX_DELAY(0xFFFFFFFF)或者是该链表的所有项中的最大值,则其效果与vListInsertEnd相同。
将pxItemToRemove链表项移出链表
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ):
1 UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) 2 { 3 /* The list item knows which list it is in. Obtain the list from the list 4 * item. */ 5 /* 链表项知道它在哪个链表中。从链表项中获取链表。 */ 6 List_t * const pxList = pxItemToRemove->pxContainer; 7 8 pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; 9 pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; 10 11 /* Make sure the index is left pointing to a valid item. */ 12 /* 确保索引指向一个有效的项。 */ 13 if( pxList->pxIndex == pxItemToRemove ) 14 { 15 pxList->pxIndex = pxItemToRemove->pxPrevious; 16 } 17 else 18 { 19 mtCOVERAGE_TEST_MARKER(); 20 } 21 22 pxItemToRemove->pxContainer = NULL; 23 ( pxList->uxNumberOfItems )--; 24 25 return pxList->uxNumberOfItems; 26 }
移出很简单,就是普通的链表操作,就不画出示意图了。
freeRTOS的链表操作就解析完成了,下次开始解析任务切换、上下文切换、保存现场相关的代码。