自己是個初學者,一直在學習國嵌的教程,本來是在本子上做的筆記,今天學習到內核鏈表了,老師留了個小問題,自己做了一下,算是寫下自己的心得吧.
大牛們一定不要見笑...
源程序如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");
MODULE_DESCRIPTION("List Module");
MODULE_ALIAS("List module");
struct student {
char name[100];
int num;
struct list_head list;
};
struct student *pstudent;
struct student *tmp_student;
struct list_head student_list;
struct list_head *pos, *node; //add node
int mylist_init() {
int i=0;
INIT_LIST_HEAD(&student_list);
pstudent = kmalloc(sizeof(struct student)*5, GFP_KERNEL);
memset(pstudent, 0, sizeof(struct student)*5);
for (i=0; i<5; i++) {
sprintf(pstudent[i].name, "Student%d", i+1);
pstudent[i].num = i+1;
list_add(&(pstudent[i].list), &student_list);
}
list_for_each(pos, &student_list) {
tmp_student = list_entry(pos, struct student, list);
printk("<0>student %d name: %s\n", tmp_student->num, tmp_student->name);
}
return 0;
}
void mylist_exit() {
int i;
/*實驗: 將for換成list_for_each來遍歷刪除節點,觀察要發生的現象,並考慮解決辦法 */
for (i=0; i<5; i++) {
list_del(&(pstudent[i].list));
kfree(pstudent);
}
module_init(mylist_init);
module_exit(mylist_exit);
makefile文件內容如下//順便複習模塊的基本知識,linux的東西真多呀,看來嵌入式之路漫漫呀...
ifneq ($(KERNELRELEASE),)
obj-m := mylist.o
else
KDIR := /lib/modules/2.6.18-53.el5/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
按老師的留的思考題:
如果是換成list_for_each遍歷刪除節點,我開始是如下修改的
void mylist_exit()
{
list_for_each(pos,&student_list); //這裏寫的真是亂改,反正出現的情況就是死機,
list_del(&student_list); //這裏的格式都不對,list_for_list原型是for,後來語句是{}的,這裏
kfree(pstudent); // 都沒有做,另外還要用list_entry提到數據後才能遍歷操作...
}
總之,一直是死機,後來也修改了一些格式,還是死機,問了羣裏的朋友,說是要用到list_for_list_safe才能安全刪除
於是就G了一下,發現:
函數原型分析
#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)
由定義可知,list_del(pos)(將pos的前後指針指向undefined state)panic,list_del_init(pos)(將pos前後指針指向自身)導致死循環.--當刪除時,鏈表指針變爲特殊類型,所以死機.
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
由定義可知,safe函數首先將pos的後指針緩存到n,處理一個流程後再賦回pos,避免了這種情況的發生。
因此只遍歷鏈表不刪除節點時可以使用前者,若有刪除節點的操作,則要使用後者。
由safe的說明可知,是專門爲刪除節點時準備的:iterate over a list safe against removal of list entry。
其他帶safe的處理也基本源於這個原因。
下面進行了更改
修改程序爲:
先定義一個和pos同樣類型的node指針用以保存pos的後的指針
然後修改 exit_mylist函數,修改後如下:
void mylist_exit()
{
//int i ;
/* 實驗:將for換成list_for_each來遍歷刪除結點,觀察要發生的現象,並考慮解決辦法 */
//for(i=0;i<5;i++)
list_for_each_safe(pos,node,&student_list)
{
//list_del(&(pstudent[i].list));
tmp_student = list_entry(pos,struct student,list);//提取數據,我開始這個也不知道,哎...
list_del(&(tmp_student->list));
printk("<0>student %d name: %s is being deleted.\n",tmp_student->num,tmp_student->name);
}
kfree(pstudent);
}
這樣,就不會死機了...