LiteOS解读_第二篇:通过指针的获取结构体入口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/snoopwolf/article/details/83021261

笔者以前一直是裸机写代码,还没有研究过其他的操作系统。以下技巧,获取其他操作系统中也有,但笔者感觉还是很精巧的,因此写下来,供大家分享。同时加快大家读代码的速度。

操作系统使用过程中最重要的就是终端使用和任务调度。

LiteOS在任务建立时,是建立了一个大的任务数组,每个任务按照索引分配一个单独的任务号,最终通过任务号完成对每个任务的查找或者指定。其中比较有意思的是,每个任务的首地址的查找,这个在本文最后写,我们先看任务创建:

代码如下:

LITE_OS_SEC_TEXT_INIT UINT32 osTaskInit(VOID)
{
    UINT32 uwSize;
    UINT32 uwIndex;
    LOS_DL_LIST *pstListObject;

    uwSize = (g_uwTskMaxNum + 1) * sizeof(LOS_TASK_CB);
    g_pstTaskCBArray = (LOS_TASK_CB *)LOS_MemAlloc(m_aucSysMem0, uwSize); //分配任务序列的空间
    .............................

    (VOID)memset(g_pstTaskCBArray, 0, uwSize);  //清空序列空间
    ................................
    for (uwIndex = 0; uwIndex <= LOSCFG_BASE_CORE_TSK_LIMIT; uwIndex++)
    {
        g_pstTaskCBArray[uwIndex].usTaskStatus = OS_TASK_STATUS_UNUSED;
        g_pstTaskCBArray[uwIndex].uwTaskID = uwIndex;   //设置任务编号
        LOS_ListTailInsert(&g_stLosFreeTask, &g_pstTaskCBArray[uwIndex].stPendList);
    }

    ..................................................

    return LOS_OK;
}

LiteOS中使用了大量的宏定义用来做地址计算,下面我们就看看这个宏定义:

#define LOS_DL_LIST_ENTRY(item, type, member) \
    ((type *)((char *)item - LOS_OFF_SET_OF(type, member))) \
先看注释:

 *@ingroup los_list
 *@brief Obtain the pointer to a structure that contains a doubly linked list.
注释说,属于los_list包,用来获取一个包含双向链表的结构指针。

该宏定义还包含了另外一个宏定义

#define LOS_OFF_SET_OF(type, member) ((long)&((type *)0)->member)
这个宏定义的实体是:

((long)&((type *)0)->member)

什么意思呢?

该实体通过(type *)0 把0地址强制转换成type类型,

&(type->member)又获取了type中member的地址,因为从0地址开始算的。那么member的地址也就是member到该type的偏移量了。最后强制类型转换为long类型。

因此该宏定义LOS_OFF_SET_OF(type, member)是获取了 type类型中member的再type中的便宜地址。

下面我们看

#define LOS_DL_LIST_ENTRY(item, type, member) \
    ((type *)((char *)item - LOS_OFF_SET_OF(type, member))) \

这个宏定义中,通过((char *)item - LOS_OFF_SET_OF(type, member))) 实现一个指针减去一个偏移量,指针位置前移。最后,又加了一个type*的类型转换。

我们最后看看这个宏定义怎么用的:

我们选osTaskScan函数中的调用

for (pstTaskCB = LOS_DL_LIST_ENTRY((pstListObject)->pstNext, LOS_TASK_CB, stTimerList);&pstTaskCB->stTimerList != (pstListObject);) 

在这句代码中

LOS_DL_LIST_ENTRY((pstListObject)->pstNext, LOS_TASK_CB, stTimerList)

的  item = (pstListObject)->pstNext

    type = LOS_TASK_CB;

   member = stTimerList

LOS_TASK_CB的定义如下

typedef struct tagTaskCB
{
    VOID                        *pStackPointer;             /**< Task stack pointer                 */
    UINT16                      usTaskStatus;
     ...........
    LOS_DL_LIST                 stPendList;
    LOS_DL_LIST                 stTimerList;
    ............................
} LOS_TASK_CB;

通过宏定义 LOS_OFF_SET_OF,我们可以得到stTimerList到pStackPointer的偏移量

如果LOS_DL_LIST_ENTRY((pstListObject)->pstNext, LOS_TASK_CB, stTimerList)中

(pstListObject)->pstNext指向 一个LOS_TASK_CB中的stTimerList,那我们是不是就得到了 LOS_TASK_CB的首地址?

我们看看osTaskScan函数中(pstListObject)->pstNext的由来

LITE_OS_SEC_TEXT VOID osTaskScan(VOID)
{
.......

    g_stTskSortLink.usCursor = (g_stTskSortLink.usCursor + 1) % OS_TSK_SORTLINK_LEN;
    pstListObject = g_stTskSortLink.pstSortLink + g_stTskSortLink.usCursor;
.....

}

通过代码分析,我们可以看到(pstListObject)->pstNext正是指向 一个LOS_TASK_CB中的stTimerList。

至于具体逻辑,大家可以自己看代码,或者等我后续分析。

读懂这个宏定义,能大大加快大家读代码的速度。

希望能对大家有帮助。

猜你喜欢

转载自blog.csdn.net/snoopwolf/article/details/83021261