码迷,mamicode.com
首页 > 其他好文 > 详细

FreeRTOS Task Management (1) - list 实现

时间:2021-06-02 20:15:54      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:删除   访问   value   遍历   uri   容器   load   fir   turn   

FreeRTOS Task Management (1) - list 实现

list结构是FreeRTOS Task Management 等模块重要的数据结构,其源码在list.clist.h中。

以下结合源码来分析list的结构与功能的实现细节。

1 结构体定义

/* list结构由以下三个结构体组成 */

struct xLIST;

/* list结构模型是一个双向链表,ListItem_t 定义了每个节点的数据结构 */
struct xLIST_ITEM
{
    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 见说明(1),下同*/          
        
    configLIST_VOLATILE TickType_t xItemValue;  /* 每个节点的值。 一般用于降序排列链表节点。 */          
    struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 指向后一个节点 */         
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;/* 指向前一个节点 */    
    void * pvOwner; /* 指向owner,一般是一个task control block(TCB),后面在分析task时会详细说明 */
    struct xLIST * configLIST_VOLATILE pxContainer; /* 指向该节点所在的链表 */ 
    
    listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE             
};
typedef struct xLIST_ITEM ListItem_t;                      

/* 上述节点信息结构体的删减版。 用于定义list中的尾结点,作为list结尾标记 */
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;

/* list结构 */
typedef struct xLIST
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE  
        
    volatile UBaseType_t uxNumberOfItems; /* 结点数量 */
    ListItem_t * configLIST_VOLATILE pxIndex; /* 节点指针(类似于容器中的迭代器)*/   
    MiniListItem_t xListEnd;  /* list尾结点 */
    
    listSECOND_LIST_INTEGRITY_CHECK_VALUE         
        
} List_t;

说明(1)— listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE宏的作用

/* 这一系列的宏的作用是,检查是否发生内存覆盖 */
#if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
    /* 如果功能没有开启,则以下宏都定义为空,不实现功能 */
    #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
    #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
    #define listFIRST_LIST_INTEGRITY_CHECK_VALUE
    #define listSECOND_LIST_INTEGRITY_CHECK_VALUE
    #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
    #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
    #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
    #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
    #define listTEST_LIST_ITEM_INTEGRITY( pxItem )
    #define listTEST_LIST_INTEGRITY( pxList )
#else 
   /* 定义变量 */
    #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE     TickType_t xListItemIntegrityValue1;
    #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE    TickType_t xListItemIntegrityValue2;
    #define listFIRST_LIST_INTEGRITY_CHECK_VALUE          TickType_t xListIntegrityValue1;
    #define listSECOND_LIST_INTEGRITY_CHECK_VALUE         TickType_t xListIntegrityValue2;

/* 将变量设置为固定值. */
    #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )     ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
    #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )    ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
    #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )              ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
    #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )              ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE

/* Define macros that will assert if one of the structure members does not
 * contain its expected value. */
    #define listTEST_LIST_ITEM_INTEGRITY( pxItem )                      configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
    #define listTEST_LIST_INTEGRITY( pxList )                           configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#endif 

说明(2)— list 结构图示

技术图片

2 宏定义

list.h中将一些简单的函数功能定义成了宏。以下逐个进行分析。

/* 设置listItem的owner指针,一般是一个TCB对象 */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )    ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )

/* 获取listItem的owner指针,一般是一个TCB对象 */
#define listGET_LIST_ITEM_OWNER( pxListItem )             ( ( pxListItem )->pvOwner )

/* 设置item value */
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )     ( ( pxListItem )->xItemValue = ( xValue ) )

/* 获取item value, 一般是task的优先级,或者是task进入unblocked状态的时刻 */
#define listGET_LIST_ITEM_VALUE( pxListItem )             ( ( pxListItem )->xItemValue )

/* 获取list的头结点 item value */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )        ( ( ( pxList )->xListEnd ).pxNext->xItemValue )

/* 获取list的 head item */
#define listGET_HEAD_ENTRY( pxList )                      ( ( ( pxList )->xListEnd ).pxNext )

/* 获取下一个item  */
#define listGET_NEXT( pxListItem )                        ( ( pxListItem )->pxNext )

/* 获取end marker  */
#define listGET_END_MARKER( pxList )                      ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )

/* 判断list是否为空*/
#define listLIST_IS_EMPTY( pxList )             ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )

/* 获取list长度 */
#define listCURRENT_LIST_LENGTH( pxList )                 ( ( pxList )->uxNumberOfItems )

/* 包含两个功能,一是迭代到下一个item(如果是listEnd,则返回listEnd的下一个item)
 *  二是返回下一个item的pvOwner。*/
#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;                                             }

/* 获取list的owner, 返回第一个item的pvOwner指针 */
#define listGET_OWNER_OF_HEAD_ENTRY( pxList )            ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )

/* 判断给定的item 是否在给定的list中 */
#define listIS_CONTAINED_WITHIN( pxList, pxListItem )    ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )

/* 获取给定item的container */
#define listLIST_ITEM_CONTAINER( pxListItem )            ( ( pxListItem )->pxContainer )

/* 判断list是否被初始化,因为在list初始化时,会将listEnd的item value初始化为portMAX_DELAY */
#define listLIST_IS_INITIALISED( pxList )                ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )

3 初始化

/* 
 * 初始化list,分别处理结构体的3个成员 
 * (1)pxIndex 指向 xListEnd
 * (2)xListEnd的xItemValue设置为portMAX_DELAY,因为list中的item都是按照大小进行排序,这样可以保证xListEnd在最后
 *     xListEnd的 pxNext 和 pxPrevious 都指向自身
 * (3)uxNumberOfItems 置为0
 */
void vListInitialise( List_t * const pxList )
{
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );	
    
	pxList->xListEnd.xItemValue = portMAX_DELAY;
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
    
	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;

	/* 写入校验数. */
	listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
	listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}

/* 初始化item,主要就是将其pvContainer 指针置为NULL,表示不在任何一个list中*/
void vListInitialiseItem( ListItem_t * const pxItem )
{
	pxItem->pvContainer = NULL;

	/* 写入校验数 */
	listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
	listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}

4 插入元素 - vListInsertEnd()

首先需要解释一下vListInsertEndEnd的含义。顾名思义,End就是最后的意思,但是代码中的指针一顿操作,实际完成的工作如下图所示:

技术图片

从插入的结果来看,貌似并不能直观地表现End的含义,源码中有一段注释如下:

/*
* Insert a list item into a list.  The item will be inserted in a position such that it will be the last item within the list  * returned by multiple calls to listGET_OWNER_OF_NEXT_ENTRY.
*/

翻译过来就是,插入的itemlistGET_OWNER_OF_NEXT_ENTRY函数(宏)最后遍历到的位置,因为函数会从pxIndex开始遍历。因此,End的含义是遍历时最后访问到,而不是list空间位置的最后。

/* 在list的最后插入一个item*/
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t * const pxIndex = pxList->pxIndex;

	/* 校验数值,用于判断是否发生memory overwite */
	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->pvContainer = ( void * ) pxList;

	( pxList->uxNumberOfItems )++;
}

5 插入元素 - vListInsert()

vListInsertEnd()不同,vListInsert()函数是按照xItemValue,进行排序。

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

	/* check overwritten in memory. */
	listTEST_LIST_INTEGRITY( pxList );
	listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );

	/* 如果插入的 Item Value 和已有 Item Value 相等,则插入到这个已有的 item 的后面。
	* 如果插入的 Item Value 为 portMAX_DELAY,则插入到xListEnd的前一个,不能破坏了xListEnd的marker作用 */
	if( xValueOfInsertion == portMAX_DELAY )
	{
		pxIterator = pxList->xListEnd.pxPrevious;
	}
	else
	{
		/* 根据xItemValue,迭代到合适的位置 */
		for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; 					pxIterator = pxIterator->pxNext ) { }
	}

    /* 一顿指针操作,将item插入其中 */
	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext = pxNewListItem;

	/* pvContainer赋值 */
	pxNewListItem->pvContainer = ( void * ) pxList;

	( pxList->uxNumberOfItems )++;
}

6 删除元素

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
	List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

    /* 将要删除的item从双向链表中解开 */
	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

	/* Only used during decision coverage testing. */
	mtCOVERAGE_TEST_DELAY();

	/* 如果 pxIndex指向的item 已经被删除,则需要将pxIndex指向前一个item. */
	if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	pxItemToRemove->pvContainer = NULL;
	( pxList->uxNumberOfItems )--;

	return pxList->uxNumberOfItems;
}

FreeRTOS Task Management (1) - list 实现

标签:删除   访问   value   遍历   uri   容器   load   fir   turn   

原文地址:https://www.cnblogs.com/yanpio/p/14838071.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!