基本类型

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_VALUE
    configLIST_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_VALUE
        configLIST_VOLATILE TickType_t xItemValue;
        struct xLIST_ITEM * configLIST_VOLATILE pxNext;
        struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
    };
    typedef struct xMINI_LIST_ITEM MiniListItem_t;
#else
    typedef struct xLIST_ITEM      MiniListItem_t;
#endif
  • listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUElistSECOND_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节点值 我猜测可能和任务分配时间有关
  • 还提供了一种迷你链表节点,去除了pvOwnerpxContainer两个字段,只保留了链表结构部分。

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 ) );//设置节点完整性检查值为1
    pxList->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 ) );
    }
    #endif
    pxList->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;
}
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐