• FreeRTOS源码分析——列表与列表项


    列表

    列表是 FreeRTOS 中的一个数据结构,概念上和双向链表有点类似,列表被用来跟踪 FreeRTOS中的任务。

    #结构体list_t

    声明:
    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;
    
    参数:
    listFIRST_LIST_INTEGRITY_CHECK_VALUE 完整性检查(不使用)
    uxNumberOfItems 列表中列表项的数量
    pxIndex 当前列表的索引
    xListEnd 列表中最后一个列表项,用来表示列表的结束
    listSECOND_LIST_INTEGRITY_CHECK_VALUE 完整性检查(不使用)


    列表项

    #结构体ListItem_t

    声明:
    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;										
    	void * configLIST_VOLATILE pvContainer;				
    	listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE			
    };
    typedef struct xLIST_ITEM ListItem_t;					
    
    参数:
    xItemValue 列表项值
    pxNext 指向下一个列表项的指针
    pxPrevious 指向上一个列表项的指针
    pvOwner 记录此链表项归谁拥有,通常是任务控制块
    pvContainer 用来记录此列表项归哪个列表

    注意:列表项的大部分参数要根据实际使用情况来初始化

    pvOwner和pvContainer的区别?

    任务控制块 TCB_t 中有两个变量 xStateListItem 和 xEventListItem,这两个变量的类型就是 ListItem_t,也就是说这两个成员变量都是列表项。以 xStateListItem 为例,当创建一个任务以后 xStateListItem 的 pvOwner 变量就指向这个任务的任务控制块,表示 xSateListItem属于此任务。当任务就绪态以后 xStateListItem 的变量 pvContainer 就指向就绪列表,表明此列表项在就绪列表中。


    #结构体MiniListItem_t

    声明:
    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;
    
    为什么需要Mini列表项呢?

    有些情况下我们不需要列表项这么全的功能,可能只需要其中的某几个成员变量,如果此时用列表项的话会造成内存浪费!



    相关的函数源码

    #列表项插入函数vListInsert()

    插入的位置由列表项中成员变量xItemValue 来决定。 列表项的插入根据 xItemValue 的值按照升序的方式排列!

    声明:
    void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
    
    参数:
    pxList 列表项要插入的列表
    pxNewListItem 要插入的列表项
    源码:带中文注释
    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. */
    	/* 如果列表项的值等于portMAX_DELAY,即列表项为最大值,则插入末尾 */
    	if( xValueOfInsertion == portMAX_DELAY )
    	{
    		pxIterator = pxList->xListEnd.pxPrevious;
    	}
    	else
    	{
    		/* 找到插入的位置(按xItemValue升序排列) */
    		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 )++;
    }
    

    注意:如果调试时程序崩溃在找插入点的for循环附近,可能的问题是:

    1. 栈溢出
    2. 中断优先级分配不正确
    3. 从临界区内或在调度程序挂起时调用API函数,或者从中断调用不以“FromISR”结尾的API函数
    4. 在初始化队列或信号量之前或在调度程序启动之前使用队列或信号量(是否在调用vTaskStartScheduler()之前触发中断?)
  • 相关阅读:
    bzoj 3744: Gty的妹子序列 主席树+分块
    bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
    bzoj 3041: 水叮当的舞步 迭代加深搜索 && NOIP RP++
    约瑟夫问题例题小结
    bzoj 3594: [Scoi2014]方伯伯的玉米田 dp树状数组优化
    人生第一场CTF的解题报告(部分)
    ZOJ 3811 Untrusted Patrol【并查集】
    POJ 2112: Optimal Milking【二分,网络流】
    Codeforces Round #277 (Div. 2 Only)
    POJ 2195 Going Home【最小费用流 二分图最优匹配】
  • 原文地址:https://www.cnblogs.com/Irvingcode/p/14653534.html
Copyright © 2020-2023  润新知