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\n", 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