【Huawei LiteOS内核解读】四、内核双向链表(源码)

    科技2022-07-11  103

    文章目录

    一、LiteOS中的双向链表 LOS_DL_LIST二、 数据结构三、 接口分析3.1 LOS_ListInit3.2 LOS_ListAdd3.3 LOS_ListTailInsert3.4 LOS_ListDelete3.5 LOS_ListEmpty 四、 总结

    一、LiteOS中的双向链表 LOS_DL_LIST

      在Huawei Liteos源码中,比较核心的东西就是双向链表,它贯穿了整个内核代码,在研究内核功能实现前,需要对该数据结构及其对应的接口有一个比较清晰的认知,接下来开始学习 Liteos 中的双向链表。   该数据结构的定义和接口全部都实现在《los_list.h》文件中,而且所有该数据结构的API都是用 LITE_OS_SEC_ALW_INLINE 内联进行定义,因为这些接口在内核中大量的被调用,使用内联可以极大的提高内核的效率。

    二、 数据结构

      双向链表的定义在 los_list.h 文件中,其中所有接口都是在H文件中通过内联函数来实现的。

    typedef struct LOS_DL_LIST { struct LOS_DL_LIST *pstPrev; /* 指向前一个节点 */ struct LOS_DL_LIST *pstNext; /* 指向后一个节点 */ } LOS_DL_LIST;

      从该数据结构中可以看出,该数据结构是双向链表的数据结构,链表中每个节点都有指向前一个和后一个节点的指针。双向链表的有点就是从任何一个节点开始,都可以通过遍历的方式找到该链表中任意一个节点。

    三、 接口分析

    3.1 LOS_ListInit

    LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list) { list->pstNext = list; /* 将本节点的地址赋值给本节点的pstNext */ list->pstPrev = list; /* 将本节点的地址赋值给本节点的pstPrev */ }

    说明:该接口是负责初始化链表的,并使得本节点中的两个指针均指向自己,初始化了双向链表的头。 上图为该数据结构的图形化示意,该双向链表的 HEAD 节点作为使用 LOS_ListInit 接口初始化的头结点。

    3.2 LOS_ListAdd

    LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node) { node->pstNext = list->pstNext; node->pstPrev = list; list->pstNext->pstPrev = node; list->pstNext = node; }

    说明: 该接口用于将一个新的 node 节点添加进list链表中 由该方法的实现可知:

    该链表是将 list 节点作为链表的开始该链表中 list->pstNext 指向的是该链表中最后一个插入的节点如图下所示: 如果采用 LOS_ListAdd 方式添加一个节点,那么 node 节点会添加到最上面,也就是说 HEAD->pstNext指向的节点,就是新添加的节点。

    3.3 LOS_ListTailInsert

    LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node) { LOS_ListAdd(list->pstPrev, node); }

    说明:将node节点插入到链表尾端,如下图所示:

    3.4 LOS_ListDelete

    LITE_OS_SEC_ALW_INLINE STATIC_INLINE VOID LOS_ListDelete(LOS_DL_LIST *pstNode) { pstNode->pstNext->pstPrev = pstNode->pstPrev; pstNode->pstPrev->pstNext = pstNode->pstNext; pstNode->pstNext = (LOS_DL_LIST *)NULL; pstNode->pstPrev = (LOS_DL_LIST *)NULL; }

    说明:将pstNode节点从链表中删除,如下图所示:

    3.5 LOS_ListEmpty

    LITE_OS_SEC_ALW_INLINE STATIC_INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *pstNode) { return (BOOL)(pstNode->pstNext == pstNode); }

    说明:该接口用来判断 pstNode 是否为空双向链表,从 LOS_ListInit 接口可知,如果 pstNode->pstNext == pstNode 则该链表为空链表。

    四、 总结

      为什么在看源码之前需要先读懂 LOS_DL_LIST 数据结构呢?是因为该数据结构贯穿了整个内核源码,我们知道,LiteOS 内核中有任务调度,内存管理、定时器、中断等,就拿任务调度来说,内核为了实现内核调度,设置了很多的双向链表结构,这样方便操作系统去遍历哪些任务在就绪,哪些任务被阻塞等等,这些功能的实现,都是通过 LiteOS 提供的 LOS_DL_LIST 增删过程来完成的。所以在读内核源码之前,一定要搞清楚这这些接口的实现,对照着上面的图来想,这样在读源码的时候就会减少很多困扰。

    Processed: 0.008, SQL: 8