linux内核链表判空,Linux内核数据结构之链表

1、前言

最近写代码需用到链表结构,正好公共库有关于链表的。第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域。后来看代码注释发现该代码来自linux内核,在linux源代码下include/Lish.h下。这个链表具备通用性,使用非常方便。只需要在结构定义一个链表结构就可以使用。

2、链表介绍

链表是非常基本的数据结构,根据链个数分为单链表、双链表,根据是否循环分为单向链表和循环链表。通常定义定义链表结构如下:

typedef structnode

{

ElemType data; //数据域struct node *next; //指针域

}node,*list;

链表中包含数据域和指针域。链表通常包含一个头结点,不存放数据,方便链表操作。单向循环链表结构如下图所示:

d9cda6961634667eb460ed2d4eecd6d8.png

双向循环链表结构如下图所示:

d95d2c8f64234c5cd48c779959f5b27c.png

这样带数据域的链表降低了链表的通用性,不容易扩展。linux内核定义的链表结构不带数据域,只需要两个指针完成链表的操作。将链表节点加入数据结构,具备非常高的扩展性,通用性。链表结构定义如下所示:

structlist_head {struct list_head *next, *prev;

};

链表结构如下所示:

14c3c18944242f2dd36bf1edeecaa08a.png

需要用链表结构时,只需要在结构体中定义一个链表类型的数据即可。例如定义一个app_info链表,

1 typedef structapplication_info2 {3 uint32_t app_id;4 uint32_t up_flow;5 uint32_t down_flow;6 struct 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结构的起始地址。可以参考: http://www.linuxidc.com/Linux/2016-12/137930.htm 。

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)插入节点

1 static inline void __list_add(struct list_head *new,2 struct list_head *prev,3 struct list_head *next)4 {5 next->prev = new;6 new->next =next;7 new->prev =prev;8 prev->next = new;9 }10

11 static inline void list_add(struct list_head *new, struct list_head *head)12 {13 __list_add(new, head, head->next);14 }15

16 static inline void list_add_tail(struct list_head *new, struct list_head *head)17 {18 __list_add(new, head->prev, head);19 }

插入节点分为从链表头部插入list_add和链表尾部插入list_add_tail,通过调用__list_add函数进行实现,head->next指向之一个节点,head->prev指向尾部节点。

(3)删除节点

1 static inline void __list_del(struct list_head * prev, struct list_head *next)2 {3 next->prev =prev;4 prev->next =next;5 }6

7 static inline void list_del(struct list_head *entry)8 {9 __list_del(entry->prev, entry->next);10 entry->next =LIST_POISON1;11 entry->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 */

6 static inline void list_move(struct list_head *list, struct list_head *head)7 {8 __list_del(list->prev, list->next);9 list_add(list, head);10 }11

12 /**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 */

17 static inline void list_move_tail(struct list_head *list,18 struct list_head *head)19 {20 __list_del(list->prev, list->next);21 list_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 */

6 static inline int list_is_last(const struct list_head *list,7 const struct list_head *head)8 {9 return list->next ==head;10 }11

12 /**13 * list_empty - tests whether a list is empty14 * @head: the list to test.15 */

16 static inline int list_empty(const struct list_head *head)17 {18 return 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) \

8 container_of(ptr, type, member)9

10 /**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) \

19 list_entry((ptr)->next, type, member)20

21 /**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) \

27 for (pos = (head)->next; prefetch(pos->next), pos !=(head); \28 pos = pos->next)

宏list_entity获取链表的结构,包括数据域。list_first_entry获取链表第一个节点,包括数据源。list_for_each宏对链表节点进行遍历。

4、测试例子

编写一个简单使用链表的程序,从而掌握链表的使用。

自定义个类似的list结构如下所示:mylist.h

1 # define POISON_POINTER_DELTA 0

2

3 #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)

4 #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)

5

6 //计算member在type中的位置

7 #define offsetof(type, member) (size_t)(&((type*)0)->member)

8 //根据member的地址获取type的起始地址

9 #define container_of(ptr, type, member) ({ \

10 const typeof(((type *)0)->member)*__mptr =(ptr); \11 (type *)((char *)__mptr -offsetof(type, member)); })12

13 //链表结构

14 structlist_head15 {16 struct list_head *prev;17 struct list_head *next;18 };19

20 static inline void init_list_head(struct list_head *list)21 {22 list->prev =list;23 list->next =list;24 }25

26 static inline void __list_add(struct list_head *new,27 struct list_head *prev, struct list_head *next)28 {29 prev->next = new;30 new->prev =prev;31 new->next =next;32 next->prev = new;33 }34

35 //从头部添加

36 static inline void list_add(struct list_head *new , struct list_head *head)37 {38 __list_add(new, head, head->next);39 }40 //从尾部添加

41 static inline void list_add_tail(struct list_head *new, struct list_head *head)42 {43 __list_add(new, head->prev, head);44 }45

46 static inline void __list_del(struct list_head *prev, struct list_head *next)47 {48 prev->next =next;49 next->prev =prev;50 }51

52 static inline void list_del(struct list_head *entry)53 {54 __list_del(entry->prev, entry->next);55 entry->next =LIST_POISON1;56 entry->prev =LIST_POISON2;57 }58

59 static inline void list_move(struct list_head *list, struct list_head *head)60 {61 __list_del(list->prev, list->next);62 list_add(list, head);63 }64

65 static inline void list_move_tail(struct list_head *list,66 struct list_head *head)67 {68 __list_del(list->prev, list->next);69 list_add_tail(list, head);70 }71 #define list_entry(ptr, type, member) \

72 container_of(ptr, type, member)73

74 #define list_first_entry(ptr, type, member) \

75 list_entry((ptr)->next, type, member)76

77 #define list_for_each(pos, head) \

78 for (pos = (head)->next; pos != (head); pos = pos->next)

mylist.c如下所示:

1 /**@brief 练习使用linux内核链表,功能包括:2 * 定义链表结构,创建链表、插入节点、删除节点、移动节点、遍历节点3 *4 *@auther Anker @date 2013-12-155 **/

6 #include

7 #include

8 #include

9 #include

10 #include "mylist.h"

11 //定义app_info链表结构

12 typedef structapplication_info13 {14 uint32_t app_id;15 uint32_t up_flow;16 uint32_t down_flow;17 struct list_head app_info_node;//链表节点

18 }app_info;19

20

21 app_info*get_app_info(uint32_t app_id, uint32_t up_flow, uint32_t down_flow)22 {23 app_info *app = (app_info*)malloc(sizeof(app_info));24 if (app ==NULL)25 {26 fprintf(stderr, "Failed to malloc memory, errno:%u, reason:%s\n",27 errno, strerror(errno));28 returnNULL;29 }30 app->app_id =app_id;31 app->up_flow =up_flow;32 app->down_flow =down_flow;33 returnapp;34 }35 static void for_each_app(const struct list_head *head)36 {37 struct list_head *pos;38 app_info *app;39 //遍历链表

40 list_for_each(pos, head)41 {42 app =list_entry(pos, app_info, app_info_node);43 printf("ap_id: %u\tup_flow: %u\tdown_flow: %u\n",44 app->app_id, app->up_flow, app->down_flow);45

46 }47 }48

49 void destroy_app_list(struct list_head *head)50 {51 struct list_head *pos = head->next;52 struct list_head *tmp =NULL;53 while (pos !=head)54 {55 tmp = pos->next;56 list_del(pos);57 pos =tmp;58 }59 }60

61

62 intmain()63 {64 //创建一个app_info

65 app_info * app_info_list = (app_info*)malloc(sizeof(app_info));66 app_info *app;67 if (app_info_list ==NULL)68 {69 fprintf(stderr, "Failed to malloc memory, errno:%u, reason:%s\n",70 errno, strerror(errno));71 return -1;72 }73 //初始化链表头部

74 struct list_head *head = &app_info_list->app_info_node;75 init_list_head(head);76 //插入三个app_info

77 app = get_app_info(1001, 100, 200);78 list_add_tail(&app->app_info_node, head);79 app = get_app_info(1002, 80, 100);80 list_add_tail(&app->app_info_node, head);81 app = get_app_info(1003, 90, 120);82 list_add_tail(&app->app_info_node, head);83 printf("After insert three app_info: \n");84 for_each_app(head);85 //将第一个节点移到末尾

86 printf("Move first node to tail:\n");87 list_move_tail(head->next, head);88 for_each_app(head);89 //删除最后一个节点

90 printf("Delete the last node:\n");91 list_del(head->prev);92 for_each_app(head);93 destroy_app_list(head);94 free(app_info_list);95 return 0;96 }

测试结果如下所示:

7bb64756ca0add1219d944eb3febfb69.png

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值