文章目录
一、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 增删过程来完成的。所以在读内核源码之前,一定要搞清楚这这些接口的实现,对照着上面的图来想,这样在读源码的时候就会减少很多困扰。