本文構建了一個雙向循環的內核鏈表,然后對鏈表進行遍歷并打印了數據,最后釋放了鏈表節點。
方法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()二者的結合體,在本程序中替換了二者。其余都不變。
新聞熱點
疑難解答