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

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

list.c与list.h的源代码分析

这一篇之所以讲list的内容,是为了后面分析其他代码用的,list是FreeRTOS的一种链式数据结构,许多变量均采用这种数据结构,比如Ready任务表,pending任务表和delayed任务表等。这种数据结构在FreeRTOS中被广泛使用,因此这里先分析这种数据结构的组成与实现原理。

list.h

首先看list.h这个文件,这个文件一开头就有一个宏定义

#ifndef configLIST_VOLATILE
    #define configLIST_VOLATILE
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */

这里是判断configLIST_VOLATILE是否被定义,没有的话就定义为空,Demo默认是没定义的,所以后面出现这个宏的时候,是什么都不做的。这个宏如果被定义的话一般是被定义为

#define configLIST_VOLATILE     volatile

之后又是一大块的宏定义:

#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
    /* Define the macros to do nothing. */
    #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 macros that add new members into the list structures. */
    #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 macros that set the new structure members to known values. */
    #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 /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */

因为configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 在Demo里也是默认的设置为0,这样实际这一连串的宏都是空的,不起作用。为简单起见,这里用默认设置,先不管这些各种Check宏,以后熟悉后需要时再分析即可。

/*
 * 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. */

接下来就是有关xLIST_ITEM这个数据类型的定义了,这是一个结构体,注意最顶上的那一句话,这个数据类型是list数据结构里唯一存在的类型。开头与结尾的宏定在前面说过了是空的,无视掉,然后里面的configLIST_VOLATILE也是空的,也可以无视。通过旁边的英文写的注释也可以知道,第一个成员xItemValue是代表的是这个Item的值,一般这个Item在list里的位置,会由这个值来排序。以DelayedTaskList为例子,在这个list里,每一个Item代表一个被延迟的任务的控制块所对应的Item,其Item_Value则代表的就是delay的值了,以tick为单位。这个list为以这个Delay值作降序排列,越小的会越在后面。pxNext和pxPrevious都是Item的指针,看名字也知道分别代表指向同一list中下一个Item的指针和指向上一个Item的指针。pvOwner是反向指向这个Item所代表的目标,比如任务控制块(TCB)。最后的pvContainer则是指向这个Item所在的list。

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;

这个MiniItem其实就是一个精简的Item,去掉了pvOwner和pvContainer,一般用在list里的最后一个特殊的Item。

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;

再来就是list的结构体定义了,同样去除无效的宏之后,就只有三个成员,uxNumberOfItems,代表这个list的所有Item的数量(不包括list的最后一个特殊的Item);pxIndex是指向list这个列表里当前的Item,相当于数组里的下标;xListEnd是Mini_Item,这个是每个list都会有的一个特殊的Item,而且总是存在与list的末尾,并且这个endItem的下一个nextItem会指向list的首部第一个Item,这样就形成了一个环形list。

list.h文件下面的除了是函数申明之外就是一系列用宏来实现的功能函数,这些函数比较简单,用宏来实现也很容易,并且执行起来比函数要来得快。每一个在上方都有用英文写出注释,这里基本只用简单翻译一下就懂了。

#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )      ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
#define listGET_LIST_ITEM_OWNER( pxListItem )   ( ( pxListItem )->pvOwner )

这两个宏,一个是用来设置Item的所属Owner的,之前也说过,一般是指某个任务控制块TCB。另外一个看名字就知道是反过来获得Item所属的Owner指针的。

#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )   ( ( pxListItem )->xItemValue = ( xValue ) )
#define listGET_LIST_ITEM_VALUE( pxListItem )   ( ( pxListItem )->xItemValue )

这两个宏,一个是设置Item的xItemValue值的,一个是获取这个值的。

#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )  ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
#define listGET_HEAD_ENTRY( pxList )    ( ( ( pxList )->xListEnd ).pxNext )

这两个宏,下面的那个是获取list的首部Item,上面的则是获取这个首部Item所对应的Value值,实现方法很简单就是获取list的尾部那个特殊的Item的下一个,前面也说过尾部那个特殊的Item的下一个就是指向list的首部。

#define listGET_NEXT( pxListItem )  ( ( pxListItem )->pxNext )
#define listGET_END_MARKER( pxList )    ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
#define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )
#define listCURRENT_LIST_LENGTH( pxList )   ( ( pxList )->uxNumberOfItems )

这几个宏的功能看名字也知道,实现也非常简单,分别是获取Item的下一个指向,list的末尾特殊Item,通过list的uxNumberOfItems是否为0来判断list是否为空(注意,每个list都含有一个末尾特殊Item,这个是不包含在这个Number里的),以及获得这个Number值。

#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的下一个Item,并且把这个Item所指向的Owner赋值给参数pxTCB,也就是说这个宏的主要作用是获取list的下一个Item的所属TCB,同时还有做了一件事,就是给Index重赋值。看实现代码可知道,list成员Index的下一个指向就是list里的下一个Item了,当调用这个宏函数来获取下一个Item时,会先把Index重赋值为下一个指向,然后再判断这个新指向是否是list里的末尾特殊Item,如果是的话再重新赋值一遍到下一个指向,这时得到的会是list的首部Item。然后把这个Item对应的Owner赋值给参数pxTCB。

#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) )
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer )
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )

剩下的这四个宏,也是很简单的实现,看名字也能知道用途,简单说下,分别是 得到list的首部Item的所属(TCB),指定Item是否在指定list里,Item的所在list以及list是否被初始化(这个判断是看list的末尾特殊Item的value是否是portMAX_DELAY,这个在list初始化时会指定否则一般会是0)。

下面几行就是list.c里定义的几个实现函数的申明了,这在下一篇分析。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值