在Linux内核中使用了大量的链表结构来组织数据。这些链表大多采用了[include/linux/list.h]中实现的一套精彩的链表数据结构。
链表数据结构的定义:
struct list_head
{
struct list_head *next, *prev;
};
list_head结构包含两个指向list_head结构的指针prev和next,由此可见,内核的链表具备双链表功能,实际上,通常它都组织成双向循环链表
Linux内核中提供的链表操作主要有:
初始化链表头
INIT_LIST_HEAD(list_head *head)
插入节点
list_add(structlist_head *new, struct list_head *head)
list_add_tail(structlist_head *new, struct list_head *head)
删除节点
list_del(structlist_head *entry)
提取数据结构
list_entry(ptr, type, member) <=> #define list_entry(link, type, member) \
((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
已知数据结构中的节点指针ptr,找出数据结构,
遍历
list_for_each(struclist_head *pos, struclist_head *head);
<=>#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
注意在编程时 list_entry与list_for_each的第一个形式参数都必须为指针,因为这两个式子为宏定义展开后是指针的形式,
所以只能定义为指针结构,同样list_entry 返回值的值类型为指针类型。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>
struct student{
unsigned char name[12];
unsigned int num;
struct list_head list;
};
struct student *pstudent;
struct student *p_stud;
struct list_head head;
struct list_head *pos;
static int hello_init(void)
{
// extern int myprintk();
// myprintk();
int i;
INIT_LIST_HEAD(&head);
pstudent = kzalloc(sizeof(struct student) * 5, GFP_KERNEL);
for(i = 0; i < 5; i++)
{
sprintf(pstudent[i].name,"student%d",i + 1);
pstudent[i].num = i;
list_add_tail(&(pstudent[i].list),&head);
}
list_for_each(pos,&head)
{
p_stud = list_entry(pos,struct student,list);
printk("p_stud->name = %s, p_stud->num = %d\n",p_stud->name , p_stud->num);
}
printk("************************hello world ! ***************************");
return 0;
}
static void hello_exit(void)
{
int i;
for(i = 0; i < 5; i++)
{
list_del(&(pstudent[i].list));
printk("pstudint[%d].list is delete!\n",i);
}
printk(KERN_ALERT"*******************in hello Goodbye world************************\n");
}
module_init(hello_init);
module_exit(hello_exit);
~
链表数据结构的定义:
struct list_head
{
struct list_head *next, *prev;
};
list_head结构包含两个指向list_head结构的指针prev和next,由此可见,内核的链表具备双链表功能,实际上,通常它都组织成双向循环链表
Linux内核中提供的链表操作主要有:
初始化链表头
INIT_LIST_HEAD(list_head *head)
插入节点
list_add(structlist_head *new, struct list_head *head)
list_add_tail(structlist_head *new, struct list_head *head)
删除节点
list_del(structlist_head *entry)
提取数据结构
list_entry(ptr, type, member) <=> #define list_entry(link, type, member) \
((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
已知数据结构中的节点指针ptr,找出数据结构,
遍历
list_for_each(struclist_head *pos, struclist_head *head);
<=>#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
注意在编程时 list_entry与list_for_each的第一个形式参数都必须为指针,因为这两个式子为宏定义展开后是指针的形式,
所以只能定义为指针结构,同样list_entry 返回值的值类型为指针类型。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>
struct student{
unsigned char name[12];
unsigned int num;
struct list_head list;
};
struct student *pstudent;
struct student *p_stud;
struct list_head head;
struct list_head *pos;
static int hello_init(void)
{
// extern int myprintk();
// myprintk();
int i;
INIT_LIST_HEAD(&head);
pstudent = kzalloc(sizeof(struct student) * 5, GFP_KERNEL);
for(i = 0; i < 5; i++)
{
sprintf(pstudent[i].name,"student%d",i + 1);
pstudent[i].num = i;
list_add_tail(&(pstudent[i].list),&head);
}
list_for_each(pos,&head)
{
p_stud = list_entry(pos,struct student,list);
printk("p_stud->name = %s, p_stud->num = %d\n",p_stud->name , p_stud->num);
}
printk("************************hello world ! ***************************");
return 0;
}
static void hello_exit(void)
{
int i;
for(i = 0; i < 5; i++)
{
list_del(&(pstudent[i].list));
printk("pstudint[%d].list is delete!\n",i);
}
printk(KERN_ALERT"*******************in hello Goodbye world************************\n");
}
module_init(hello_init);
module_exit(hello_exit);
~