linux内核数据结构之链表1、前言最近写代码需用到链表结构,正好公共库有关于链表的。
第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域。
后来看代码注释发现该代码来自linux内核,在linux 源代码下include/Lish.h下。
这个链表具备通用性,使用非常方便。
只需要在结构定义一个链表结构就可以使用。
2、链表介绍链表是非常基本的数据结构,根据链个数分为单链表、双链表,根据是否循环分为单向链表和循环链表。
通常定义定义链表结构如下:typedef struct node{ElemType data; //数据域struct node *next; //指针域}node, *list;链表中包含数据域和指针域。
链表通常包含一个头结点,不存放数据,方便链表操作。
单向循环链表结构如下图所示:双向循环链表结构如下图所示:这样带数据域的链表降低了链表的通用性,不容易扩展。
linux内核定义的链表结构不带数据域,只需要两个指针完成链表的操作。
将链表节点加入数据结构,具备非常高的扩展性,通用性。
链表结构定义如下所示:struct list_head {struct list_head *next, *prev;};链表结构如下所示:需要用链表结构时,只需要在结构体中定义一个链表类型的数据即可。
例如定义一个app_info链表,1 typedef struct application_info3uint32_t app_id;4uint32_t up_flow;5uint32_t down_flow;6struct list_head app_info_head; //链表节点7 }app_info;定义一个app_info链表,app_info app_info_list;通过app_info_head进行链表操作。
根据C语言指针操作,通过container_of和offsetof,可以根据app_info_head的地址找出app_info的起始地址,即一个完整ap_info结构的起始地址。
可以参考:/Anker/p/3472271.html。
3、linux内核链表实现内核实现的是双向循环链表,提供了链表操作的基本功能。
(1)初始化链表头结点#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) \struct list_head name = LIST_HEAD_INIT(name)static inline void INIT_LIST_HEAD(struct list_head *list){list->next = list;list->prev = list;}LIST_HEAD宏创建一个链表头结点,并用LIST_HEAD_INIT宏对头结点进行赋值,使得头结点的前驱和后继指向自己。
INIT_LIST_HEAD函数对链表进行初始化,使得前驱和后继指针指针指向头结点。
(2)插入节点1static inline void __list_add(struct list_head *new,2struct list_head *prev,3struct list_head *next)4 {5next->prev = new;6new->next = next;7new->prev = prev;8prev->next = new;9 }1011static inline void list_add(struct list_head *new, struct list_head *head)12 {13__list_add(new, head, head->next);14 }1516static inline void list_add_tail(struct list_head *new, struct list_head *head)17 {18__list_add(new, head->prev, head);插入节点分为从链表头部插入list_add和链表尾部插入list_add_tail,通过调用__list_add函数进行实现,head->next指向之一个节点,head->prev指向尾部节点。
(3)删除节点1static inline void __list_del(struct list_head * prev, struct list_head * next)2 {3next->prev = prev;4prev->next = next;5 }67static inline void list_del(struct list_head *entry)8 {9__list_del(entry->prev, entry->next);10entry->next = LIST_POISON1;11entry->prev = LIST_POISON2;12 }从链表中删除一个节点,需要改变该节点前驱节点的后继结点和后继结点的前驱节点。
最后设置该节点的前驱节点和后继结点指向LIST_POSITION1和LIST_POSITION2两个特殊值,这样设置是为了保证不在链表中的节点项不可访问,对LIST_POSITION1和LIST_POSITION2的访问都将引起页故障/** These are non-NULL pointers that will result in page faults* under normal circumstances, used to verify that nobody uses* non-initialized list entries.*/#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)(4)移动节点1/**2* list_move - delete from one list and add as another's head3* @list: the entry to move4* @head: the head that will precede our entry5*/6static inline void list_move(struct list_head *list, struct list_head *head)7 {8__list_del(list->prev, list->next);9list_add(list, head);10 }1112/**13* list_move_tail - delete from one list and add as another's tail14* @list: the entry to move15* @head: the head that will follow our entry16*/17static inline void list_move_tail(struct list_head *list,18struct list_head *head)20__list_del(list->prev, list->next);21list_add_tail(list, head);22 }move将一个节点移动到头部或者尾部。
(5)判断链表1/**2* list_is_last - tests whether @list is the last entry in list @head3* @list: the entry to test4* @head: the head of the list5*/6static inline int list_is_last(const struct list_head *list,7const struct list_head *head)8 {9return list->next == head;10 }1112/**13* list_empty - tests whether a list is empty14* @head: the list to test.15*/16static inline int list_empty(const struct list_head *head)17 {18return head->next == head;19 }list_is_last函数判断节点是否为末尾节点,list_empty判断链表是否为空。
(6)遍历链表1/**2* list_entry - get the struct for this entry3* @ptr: the &struct list_head pointer.4* @type: the type of the struct this is embedded in.5* @member: the name of the list_struct within the struct.6*/7#define list_entry(ptr, type, member) \8container_of(ptr, type, member)910/**11* list_first_entry - get the first element from a list12* @ptr: the list head to take the element from.13* @type: the type of the struct this is embedded in.14* @member: the name of the list_struct within the struct.15*16* Note, that list is expected to be not empty.17*/18#define list_first_entry(ptr, type, member) \19list_entry((ptr)->next, type, member)22* list_for_each - iterate over a list23* @pos: the &struct list_head to use as a loop cursor.24* @head: the head for your list.25*/26#define list_for_each(pos, head) \27for (pos = (head)->next; prefetch(pos->next), pos != (head); \28pos = pos->next)宏list_entity获取链表的结构,包括数据域。