1. linux内核链表
链表数据结构的定义:
struct list_head
{
struct list_head *next, *prev;
};
list_head结构包含两个指向list_head结构的指针prev和next,由此可见,内核的链表具备双链表功能,实际上,通常它都组织成双向环链表。
2. 链表操作
Linux内核中提供的链表操作主要有:
初始化链表头
INIT_LIST_HEAD(list_head*head)
插入节点
list_add(struct list_head *new, struct list_head *head) (链表头head之后插入节点)
list_add_tail(struct list_head *new, struct list_head *head) 它是从右向左在head->priv和head两个节点之间插入_new。
删除节点
list_del(struct list_head *entry)
提取数据结构
list_entry(ptr, type, member)
已知数据结构中的节点指针ptr,找出数据结构,type为整个节点结构的类型,member为list_head在整个节点结构中的成员名,返回一个指向节点类型的指针,例:list_entry(P, struct h,M)。
遍历 list_for_each(struc list_head *pos, struc list_head *head)
例:
structlist_head *entry;
structlist_head cs46xx_devs; //链表头
list_for_each(entry, &cs46xx_devs) //内核定义实际为or循环
{
card =list_entry(entry, struct cs_card, list);
if (card->dev_midi == minor)
break;
}
3. 示例代码
#include<linux/list.h> #include<linux/slab.h> 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() { 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 ", tmp_student->num, tmp_student->name); // 5-->1输出, 注意list_add 与 list_add_tail区别。。 } return 0; } void mylist_exit() { int i=0; for(i=0; i<5; i++) { list_del(&(pstudent[i].list)); } kfree(pstudent); } module_init(mylist_init); module_exit(mylist_exit);
内核编译makefile
ifneq ($(KERNELRELEASE),) obj-m :=list.o else KDIR := /lib/modules/3.5.0-17-generic/build all: make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ok *.o *.mod.o *.mod.c *.symvers endif