【转】内核链表的应用
0赞本文构建了一个双向循环的内核链表,然后对链表进行遍历并打印了数据,最后释放了链表节点。
方法1:
使用到的数据结构和链表操作函数如下:
struct list_head 内核提供的双向循环链表节点的结构体
LIST_HEAD(name) 该宏定义并初始化一个名为name的struct list_head类型节点
INIT_LIST_HEAD(name) 该宏初始化一个由name指向的 struct list_head类型节点,事先需要定义好一个struct list_head类型变量,
并将变量的指针赋给name,然后再使用该宏
list_for_each(pos, head) 该宏可以遍历以head为链表头的循环链表,pos是遍历到的每个节点,pos和head均为指针类型。
list_entry(ptr, type, number) 该宏可以得到type类型的结构体指针,number为包含在该type类型结构体中的struct list_head类型成员变量,
ptr为&number。返回值为指向type类型的指针。
list_for_each_safe(pos, n, head) 该宏类似于list_for_each宏,区别在于每次遍历,n指向了pos的下一个节点。该宏可用于释放链表节点之用。
程序代码如下:
1 #include <linux/slab.h>
2 #include <linux/sched.h>
3 #include <linux/module.h>
4 #include <linux/kernel.h>
5 #include <linux/init.h>
6 #include <linux/list.h>
7
8 struct fox {
9 int data;
10 struct list_head list;
11 };
12
13 int i;
14 struct list_head *temp;
15 struct fox *tmp;
16 LIST_HEAD(head);
17
18 static int __init test_init(void)
19 {
20 for (i = 0; i < 10; i++) {
21 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
22 tmp->data = i;
23 INIT_LIST_HEAD(&tmp->list);
24 list_add_tail(&tmp->list, &head);
25 }
26
27 list_for_each(temp, &head) {
28 tmp = list_entry(temp, struct fox, list);
29 printk("<0> %d\n", tmp->data);
30 }
31
32 return 0;
33 }
34
35 static void __exit test_exit(void)
36 {
37 struct list_head *next;
38
39 printk("<1> byebye\n");
40 list_for_each_safe(temp, next, &head) {
41 tmp = list_entry(temp, struct fox, list);
42 printk("<0> %d\n", tmp->data);
43 kfree(tmp);
44 }
45 }
46
47 module_init(test_init);
48 module_exit(test_exit);
49 MODULE_LICENSE("GPL");
需要注意的是,在释放链表时,不可以直接用list_del(pos)宏来删除节点,该宏仅仅是把struct list_head节点从其链表中卸下来,而且不释放。而我们需要删除的是fox结构体,所以只能使用本文中的这种方法,利用list_for_each_safe()宏,将需要释放的节点指针保存到pos中,同时将下一个节点指针保存在next中,这样就保证了释放节点时链表不会丢失。其实list_head节点是不用单独去释放的,该结构体一般会以结构体变量的形式保存在更大的结构体中,只要释放更大结构题即可。如本例所示的那样。
方法2:
也可以用list_for_each_entry()和list_for_each_entry_safe()宏来完成,代码如下:
1 #include <linux/slab.h>
2 #include <linux/sched.h>
3 #include <linux/module.h>
4 #include <linux/kernel.h>
5 #include <linux/init.h>
6 #include <linux/list.h>
7
8 struct fox {
9 int data;
10 struct list_head list;
11 };
12
13 int i;
14 struct fox *tmp;
15 LIST_HEAD(head);
16
17 static int __init test_init(void)
18 {
19 for (i = 0; i < 10; i++) {
20 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
21 tmp->data = i;
22 INIT_LIST_HEAD(&tmp->list);
23 list_add_tail(&tmp->list, &head);
24 }
25
26 list_for_each_entry(tmp, &head, list) {
27 printk("<0> %d\n", tmp->data);
28 }
29
30 return 0;
31 }
32
33 static void __exit test_exit(void)
34 {
35 struct fox *next;
36
37 printk("<1> byebye\n");
38 list_for_each_entry_safe(tmp, next, &head, list) {
39 printk("<0> %d\n", tmp->data);
40 kfree(tmp);
41 }
42 }
43
44 module_init(test_init);
45 module_exit(test_exit);
46 MODULE_LICENSE("GPL");
list_for_each_entry()是list_for_each()和list_entry()二者的结合体,在该程序中对二者进行了替换,使用起来更方便。
同样,list_for_each_entry_safe是list_for_each_safe()和list_entry()二者的结合体,在本程序中替换了二者。其余都不变。

