FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 六

7 篇文章 1 订阅
7 篇文章 4 订阅

list.c 代码分析

在list.c里一共有5个函数的定义,分别是vListInitialise,用来初始化列表list;vListInitialiseItem,用来初始化一个列表中的项目Item;uxListRemove,用来移除一个list里的指定Item;vListInsert,用来往list里插入一个Item,按照其xItemValue值来排序进入插入;vListInsertEnd,则是用来往list里插入一个Item到当前索引的前一个(因list里的链接是循环链接,在索引达到listEnd后会从新回到list的首部,因此插入到当前索引的前一个的结果是所插入的Item会是最后一个索引到的值)。

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

vListInitialise作用就是初始化一个list,其参数pxList就是要初始化的list的指针。 这个函数首先将list的当前Index赋值为list的末尾指针xListEnd,这个末尾指针是每个list都有的,是list结构体的成员之一。然后给xListEnd的ItemValue值赋值为最大portMAX_DELAY,在检查一个list是否被初始化时,就是通过查看其xListEnd的Value值是否为portMAX_DELAY。再之后,因为list初始化时,应该是没有任何Item的,除了xListEnd这个特殊的Item,所以这里会令xListEnd的前一个指向与后一个指向都指向自己本身。之后就是令list的Item数量uxNumberOfItems为0,下面两行宏无效,可以无视。

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

vListInitialiseItem就很简单了,就是让这个指定的pxItem的成员pvContainer ,也就是所在的list为一个空值,也就是不存在某个list中,就这一个简单的语句来初始化一个Item。

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

vListInsertEnd是在list的当前索引的前面进行插入一个Item,要做的事也很简单,首先把要插入的新Item的前一个指向赋值为Index的前一个,然后新Item的后一个当然就是指向Index了。插入之后Index要赋值新的前指向为新Item,而Index在未插入前的前一个指向Item此时所对应的后一个指向Next也要赋值为所插入的新Item。完成这些之后,就是对新Item的容器值赋值为这个list指针,然后就是list的项目数目NumberOfItems加1。

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;

    if( xValueOfInsertion == portMAX_DELAY )
    {
        pxIterator = pxList->xListEnd.pxPrevious;
    }
    else
    {
        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 )++;
}

vListInsert是按照所插入的Item的value值来进行升序排序后插入的,因此在插入之前要先按照升序来查找到最后一个value值小于或等于新Item的value的索引(因为在list里可能会有相同value值的Item存在),在这个位置之后进行插入,就像上面vListInsertEnd那样,只不过这次是在索引之后插入而不是在索引之前插入。在查找之前,先判断NewItem的value值是否为portMAX_DELAY这个默认最大值,如果是的就直接插入在ListEnd这个特殊末尾Item的前面,否则会一直循环下去,因为不会有比portMAX_DELAY还要大的value值存在。在利用for循环进行查询索引后,所得到的pxIterator就是NewItem要插在后面的位置,与上面vListInsertEnd里要做的工作一致,只不过这次是在pxIterator的后面插入,而不是在pxIndex的前面插入。

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

uxListRemove就是把指定Item移除出其所在的list的,移除所要做的工作,首先就是让这个List链条在移除其中一个环节后再接起来,也就是把所要移除的Item的前一个指向Item的next赋值为所要移除Item的后一个Item,同样的,所要移除Item的后一个指向也要反过来重新指向所要移除Item的前一个Item,这样这个链接就完整了,并剔除了所要移除的Item。之后就是判断list的当前索引Index是否刚好就在所要移除的Item这个位置,如果是的就把Index重新赋值为要移除Item的前一个Item,这样就能使在查找list下一个Item时,能正确的得到Index的下一个指向Item。然后就是把要移除的Item的容器重赋值为Null,相当于是重新初始化,让其可以直接在下一次被使用。然后就是让list的Item数量减一,然后返回这个数量值,所以这个移除函数是有返回值的,返回值就是移除这个Item后剩下的Item数量。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值