Linux设备驱动工程师之路——内核链表的使用
K-Style
转载请注明来自于衡阳师范学院08电2 K-Style http://blog.csdn.net/ayangke,QQ:843308498 邮箱:[email protected]
一、重要知识点
1.内核链表和普通链表的区别
内核链表是一个双向链表,但是与普通的双向链表又有所区别。内核链表中的链表元素不与特定类型相关,具有通用性。
我们先来看一幅图
kernel list展示的是内核链表的结构,normallist展示的是普通链表的结构。head是链表头,p1,p2,p3是链表节点。从图中可以看出普通链表的p1的next指针是指向的结构体p2的地址,p2的pre指针指向p1结构体的地址。而内核链表的p1的next指向的是p2结构体中包含pre和next部分的地址,的p2的pre指向的是p1结构体中包含pre和next部分的地址。依此类推,这就是区别。内核结构元素不与特定类型结构相关,任何结构体都可通过内核的添加成为链表中的节点。
2.内核链表的具体操作
链表数据结构的定义
structlist_head
{
struct list_head *next, *prev;
}
初始化链表头
INIT_LIST_HEAD(list_head *head)
插入节点
list_add(struct list_head *new, struct list_head *head)
list_add_tail(struct list_head *new, sturct list_head *head)
第一个函数在head后面插入一个节点
第二个函数在链表尾部插入一个节点
删除节点:
list_del(struct list_head *entry)
提取数据结构:
list_entry(ptr,type, member)
ptr为已知节点指针ptr,type为节点结构体类型,member为节点指针的type结构体中的名字。返回type结构体的指针。
遍历:
list_for_each(struct list_head *ops, struct list_head *head)
从head开始遍历每个节点,节点指针保存在ops里面。
二、实例
#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("ListModule"); 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; int mylist_init() { inti = 0; INIT_LIST_HEAD(&student_list); pstudent= kmalloc(sizeof(struct student)*5,GFP_KERNEL); memset(pstudent,0,sizeof(structstudent)*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); } return0; } void mylist_exit() { inti ; for(i=0;i<5;i++) { list_del(&(pstudent[i].list)); } kfree(pstudent); } module_init(mylist_init); module_exit(mylist_exit);