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;
}