首页 > 学院 > 操作系统 > 正文

内核链表的应用

2024-06-28 13:25:21
字体:
来源:转载
供稿:网友
内核链表的应用

本文构建了一个双向循环的内核链表,然后对链表进行遍历并打印了数据,最后释放了链表节点。

方法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()二者的结合体,在本程序中替换了二者。其余都不变。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表