freeRTOS List_t列表

Freertos使用的是改良的双向链表。

#1 list item 增加了完整性检测(configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 配置),

#2 增加了list item的owner(owner一般指的就是任务控制块TCB);

#3 增加了list的item的Container容器(指定item所在的list);

  根据TCB里面的两个列表项进行分类:1.任务状态列表,有就绪列表、延时列表、挂起列表等。2.事件信号量队列Queue,这个队列里面,有WaitToSend列表和WaitToRcv列表。

#4 xItemValue则是链表进行排序时的参考值,list在不同地方引用,一般需要按照xItemValue进行排序;

  一般task中引用按照delay时间排序,queue中WaitToSend/Rcv列表按照优先级排序,timer中按照超时时间排序。

#5 Freertos代码很精简高效,这种改良的list在额外开销和效率之间做了一个很好的平衡,

除此之外,还专门定义缩减的list item,用于表示链表结构中的首尾链接item

xMINI_LIST_ITEM前面字节定义和xLIST_ITEM一致,可以直接转型为xLIST_ITEM,以读取链表的首尾元素。

xMINI_LIST_ITEM在别的地方没有使用,可能仅仅是为了减少内存占用。

 

以上出自:http://www.tk4479.net/jorhai/article/details/65455328

 

 

一、List_t,作用类似表头,管理一个列表

/*
 * Definition of the type of queue used by the scheduler.
 */
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;

说明:

1、listFIRST_LIST_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_INTEGRITY_CHECK_VALUE是头和尾保护,防止越界(其实就是写特定数据),需要把configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES配置为1;

2、uxNumberOfItems 本List_t中有多少个项;

3、pxIndex 指向列表其中一项的地址;【这一项是“listGET_OWNER_OF_NEXT_ENTRY获取时”最后返回的item】。

4、xListEnd指向列表最后一项,类型为MiniListItem_t。

 

 二、ListItem_t

/*
 * Definition of the only type of object that a list can contain.
 */
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. */ }; typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */

说明:

1、listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE保护,需要把configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES配置为1;

2、xItemValue 本ListItem_t项的值,大多数用于排序,比如延时;

3、pxNext 指向下一项;

4、pxPrevious 指向前一项;

5、pvOwner 指向拥有者,一般是TCB;

6、pvContainer 指向所属的列表;

 

三、MiniListItem_t

struct xMINI_LIST_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;
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

 说明:

1、只是少了pvOwner和pvContainer,一般用于列表的结尾,表示结束;

 

四、listGET_OWNER_OF_NEXT_ENTRY ()

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                        \
{                                                                                            \
List_t * const pxConstList = ( pxList );                                                    \
    /* Increment the index to the next item and return the item, ensuring */                \
    /* we don't return the marker used at the end of the list.  */                            \
    ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                            \
    if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )    \
    {                                                                                        \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                        \
    }                                                                                        \
    ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                            \
}

 get下一个列表项的onwer

如果下一列表项是xListEnd,则再切换下一项。这里不明白设置这个xListEnd的用意。

 

四 plus、

/*
 * Access macro to retrieve the value of the list item at the head of a given
 * list.
 *
 * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
 * \ingroup LinkedList
 */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )    ( ( ( pxList )->xListEnd ).pxNext->xItemValue )

/*
 * Return the list item at the head of the list.
 *
 * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
 * \ingroup LinkedList
 */
#define listGET_HEAD_ENTRY( pxList )    ( ( ( pxList )->xListEnd ).pxNext )

 可以看出使用这个垫底的 xListEnd.pxNext 竟然可以获取到整个 List 的 HEAD_ENTRY。

 

 

以下为list.c中的内容:

五、初始化List_t

list.h
/*
* Must be called before a list is used! This initialises all the members * of the list structure and inserts the xListEnd item into the list as a * marker to the back of the list. * * @param pxList Pointer to the list being initialised. * * \page vListInitialise vListInitialise * \ingroup LinkedList */ void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
list.c
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; //(TickType_t)(0xFFFF_FFFF ul) /* 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 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. */ 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 ); }

 说明:

1、pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );  在list最后放一项,作为标记。

2、pxList->xListEnd.xItemValue = portMAX_DELAY;  这一项的值为32bit的最大值,保证排序的时候,仍排在最后。

3、xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );  注意一下这里。

 

六、初始化Item

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

 

 

七、插入

插入到末尾:

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(). 
不对list排序,而是把新的item作为 “listGET_OWNER_OF_NEXT_ENTRY获取时” 最后才能获取到的item。
*/ 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 )++; }

 

 

按升序插入:

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
    {
        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; /* Remember which list the item is in. This allows fast removal of the item later. */ pxNewListItem->pvContainer = ( void * ) pxList; ( pxList->uxNumberOfItems )++; }

 

 

八、移除

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; 利用Item的Container获得了他的管理表头!!【这回知道->优先级比()高了】

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

 

posted @ 2017-11-14 17:19  为民除害  阅读(1844)  评论(0编辑  收藏  举报