最近鸿蒙系统大火,趁着热度,学习了一下鸿蒙内核的kernel/los_list.h的源码,纯属个人爱好,学Linux总得看点内核汲取汲取营养,下面源码有兴趣尝试conainer_of的建议Linux系统下编译运行,windows把linux/kernel.h去掉即可,头文件linux/kernel.h和stddef.h不是必须的,只是两个分别存放了offsetof和container_of函数,与LOS_OFF_SET_OF(type, member) 和 LOS_DL_LIST_ENTRY(item, type, member)具有相同的功能,stdlib.h和stdio.h头文件是必须的,删除则编译不成功。
答案一定是: LOS_DL_LIST
(双向链表),它长这样.
/** *@ingroup los_list * Structure of a node in a doubly linked list. */ typedef struct LOS_DL_LIST {//双向链表,内核最重要结构体 struct LOS_DL_LIST *pstPrev; /**< Current node‘s pointer to the previous node *///前驱节点(左手) struct LOS_DL_LIST *pstNext; /**< Current node‘s pointer to the next node *///后继节点(右手) } LOS_DL_LIST;
这个结构体很简单,只有两个指针域的双向链表,简单到甚至连数据域都没有。可是没有数据域的链表不是形同虚设吗?那你将大错特错,几乎内核里的所有模块都能看的到该双向链表的身影。可以豪不夸张的说理解LOS_DL_LIST
及相关函数是读懂鸿蒙内核的关键。
双向链表是指含有往前和往后两个方向的链表,即每个结点中除存放下一个节点指针外,还增加一个指向其前一个节点的指针。其头指针head
是唯一确定的。 如图所示,该双向链表是镶嵌在其他结构体中使用的。
这是一种很巧妙的链表实现,在内核中用这种结构进行进程管理等,下面给出一个简单的实例,来说明该如何使用,相关API已在程序中给出(手打确实有点累),其中LOS_OFF_SET_OF(type, member)可以用stddef.h中的offsetof(type, member)来进行代替,LOS_DL_LIST_ENTRY(item, type, member)可以用linux/kernel.h中的container_of(item, type, member)来进行代替。程序很简单,新建4个Thread,加入队列,再遍历输出队列中的Thread,看看这种内嵌的双向链表是否真的起到作用(比较地址是否相同)
#include <stdio.h> /** *@defgroup los_list Doubly linked list *@ingroup kernel */ #ifndef _LOS_LIST_H #define _LOS_LIST_H #include <stdlib.h> #include <stddef.h> #include <linux/kernel.h> #ifdef __cplusplus #if __cplusplus extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ /** *@ingroup los_list * Structure of a node in a doubly linked list. */ typedef struct LOS_DL_LIST {//双向链表,内核最重要结构体 struct LOS_DL_LIST *pstPrev; /**< Current node‘s pointer to the previous node *///前驱节点(左手) struct LOS_DL_LIST *pstNext; /**< Current node‘s pointer to the next node *///后继节点(右手) } LOS_DL_LIST; #ifndef BOOL #define BOOL int8_t #endif #ifndef CHAR #define CHAR char #endif #ifndef NULL #define NULL ((void *)0) #endif /* #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );}) */ /** *宏定义,初始化双向链表 */ #define LOS_DL_LIST_HEAD(list) LOS_DL_LIST list = {&(list), &(list)} /** *计算type结构体成员member相对于结构体的地址偏移量 */ #define LOS_OFF_SET_OF(type, member) ((unsigned long)&((type *)0)->member) /** *获取包含LOS_DL_LIST item的结构体的地址 */ #define LOS_DL_LIST_ENTRY(item, type, member) \ ((type *)(void *)((char *)(item) - LOS_OFF_SET_OF(type, member))) /** *遍历双向链表LOS_DL_LIST */ #define LOS_DL_LIST_FOR_EACH(item, list) for (item = (list)->pstNext; (item) != (list); item = (item)->pstNext) /** *遍历双向链表,获取包含该节点结构体的地址,并保存下一个节点结构体的地址 */ #define LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, next, list, type, member) for (item = LOS_DL_LIST_ENTRY((list)->pstNext, type, member), next = LOS_DL_LIST_ENTRY((item)->member.pstNext, type, member); &(item)->member != list; item = next, next = LOS_DL_LIST_ENTRY((item)->member.pstNext, type, member) /** *遍历指定双向链表,获取包含该链表节点的结构体地址 */ #define LOS_DL_LIST_FOR_EACH_ENTRY(item, list, type, member) for (item = LOS_DL_LIST_ENTRY((list)->pstNext, type, member); &(item)->member != (list); item = LOS_DL_LIST_ENTRY((item)->member.pstNext, type, member))
#define LOS_List_PeekTailType(list, type, member) ({ \ type *__t; if ((list)->pstPrev == list) { __t = NULL; } else { __t = LOS_DL_LIST_ENTRY((list)->pstPrev, type, member); } __t; })
#define LOS_List_PeekHeadType(list, type, member) ({ \ type *__t; if ((list)->pstNext == list) { __t = NULL; } else { __t = LOS_DL_LIST_ENTRY((list)->pstNext, type, member); } __t; })
#define LOS_List_RemoveHeadType(list, type, member) ({ \ type *__t; if ((list)->pstNext == list) { __t = NULL; } else { __t = LOS_DL_LIST_ENTRY((list)->pstNext, type, member); LOS_ListDelete((list)->pstNext); } __t; })
#define LOS_ListNextType(list, item, type, member) ({ \ type *__t; if ((item)->pstNext == list) { __t = NULL; } else { __t = LOS_DL_LIST_ENTRY((item)->pstNext, type, member); } __t; }) /** *@ingroup los_list * *@par Description: * This API is used to initialize a doubly linked list. */ static inline void LOS_ListInit(LOS_DL_LIST *list) { list->pstNext = list; list->pstPrev = list; } /** *@ingoup los_list * *@par Decription: * This API is uesd to remove a node in a doubly linked list. */ static inline void LOS_ListDelete(LOS_DL_LIST *node) { node->pstNext->pstPrev = node->pstPrev; node->pstPrev->pstNext = node->pstNext; node->pstNext = NULL; node->pstPrev = NULL; }
/** *@ingroup los_list * *@par Description: * This API is uesd to insert a new node in a doubly linked list. */ 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; } /** *@ingroup los_list * *@par Description: * This API is used to insert a new node to the tail of a doubly linked list. */ static inline void LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node) { LOS_ListAdd(list->pstPrev, node); } /** *@ingroup los_list * *@par Description: * This API is used to insert a new node to the head of a doubly linked list. */ static inline void LOS_listHeadInsert(LOS_DL_LIST *list, LOS_DL_LIST *node) { LOS_ListAdd(list, node); } /** *@ingroup los_list * *@par Description: * This API is used to return whether a doubly linked list is empty. */ static inline BOOL LOS_ListEmpty(LOS_DL_LIST *list) { return (BOOL)(list->pstNext == list); }
#ifdef __cplusplus #if __cplusplus extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ #endif /* _LOS_LIST_H */
/** *@ingroup jckeep_thread_demo * Structure of a thread */ typedef struct Thread { char *thread_name; int thread_ID; LOS_DL_LIST thread_line; } Thread; int main() { LOS_DL_LIST_HEAD(list1); Thread a = {"chrome", 1}; Thread b = {"Edge", 2}; Thread c = {"bash", 3}; Thread d = {"visual studio code", 4}; LOS_ListTailInsert(&list1, &a.thread_line); LOS_ListTailInsert(&list1, &b.thread_line); LOS_ListTailInsert(&list1, &c.thread_line); LOS_ListTailInsert(&list1, &d.thread_line); printf("Thread_1‘s address is %p\nThread_2‘s address is %p\n" "Thread_3‘s address is %p\nThread_4‘s address is %p\n", &a, &b, &c, &d); Thread *A = LOS_List_PeekHeadType(&list1, Thread, thread_line); Thread *B = LOS_List_PeekTailType(&list1, Thread, thread_line); //Thread *A = LOS_DL_LIST_ENTRY(list1.pstNext ,Thread, thread_line); //Thread *B = LOS_DL_LIST_ENTRY(list1.pstNext->pstNext, Thread, thread_line); Thread *item; LOS_DL_LIST_FOR_EACH_ENTRY(item, &list1, Thread, thread_line) { printf("Thread address: %p\t\033[4mThread_name\033[0m: \033[1;31m%30s\033[0m\t" "Thread_ID: \033[1;32m%d\033[0m\tThread_line: %p\n", item, item->thread_name ,item->thread_ID, &item->thread_line); } return 0; }
运行结果:
可以看到Thread 1, 2, 3, 4对应前后的地址均相同。
原文:https://www.cnblogs.com/JCKeep/p/14753394.html