1、编写一个内核模块,在模块中完成内核链表的创建、插入、删除、遍历等操作。
背景知识
1、内核链表实例分析
内核链表最大的特点是它的通用性,不必因为结构体中数据域的不同而单独为操作链表设计一套方法。
Linux内核在linux/lish.h文件中定义了内核通用链表list_head类型基本结构:
struct list_head
{struct list_head *next,*prev;}
内核链表的常用用途是将某一个数据结构本身串成链表,或将某些链表与一个数据结构联系起来,下面通过实例来说明将某一个数据结构本身串成链表的过程。
1)加入list_head结构成员
假设有一个example_struct结构需要连接成链表,因而其结构里面加上list_head成员,就组成了结构链表,如:
struct example_struct{
struct list_head list;
int priority;
.../*其他成员*/
}
在example_struct 结构中的list成员,用来将example_struct结构串成链表。可理解为list_head“背负”的负载是example_struct结构。
2)创建list_head结构
使用前必须申请链表头并用INIT_LIST_HEAD宏初始化链表头,可使用两种方法:
struct list_head example_list;
INIT_LIST_HEAD(&example_list);
或者
LIST_HEAD(example_list);
其中,这两个宏include/linux/list.h中定义如下:
#define LIST_HEAD(name) struct list_head name=LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do{(ptr)->next=(ptr);(ptr)->pre=(ptr);}while(0)
宏定义INIT_LIST_HEAD初始化了链表,即向前、向后的指针都指向链表头。这样,就已经初始化了一个example_list的链表头,以后就可以向链表中增加链表元素了。
3)链表与用户结构连接
list_entry宏将example_list链表与example_struct结构类型连接起来。
下面这个代码行就是从example_list链表中得到的结点对应的example_struct结构指针,其中ptr是example_list链表中的指针,如ptr=example_list->next。
struct example_struct *node=list_entry(ptr,struct example_struct,list);
在上面代码行中的宏定义list_entry将一个list_head结构指针映射回一个指向结构example_struct的指针,即得到list_head的宿主结构。其宏定义在include/linux/list.h中
#define list_entry(ptr,type,member) container_of(ptr,type,member)
list_entry的功能是得到链表中结点的结构,它的参数含义为:
ptr是链表中的一个struct list_head结构元素指针。type是用户定义的结构类型,其中,包含struct list_head结构成员。member用户定义结构中的struct list_head结构成员名字。
4)遍历链表
下面使用list_entry宏遍历链表得到链表指针,再从链表指针映射回对应结构example_struct的指针,然后,对其成员priority进行操作,函数example_add_entry的功能是给链表加入新的结构成员。
mylist.c
Makefile
安装模块后insmod mylist.ko
.........................
模块初始化函数mylist_init被调用,在模块加载函数中,创建了一个内核链表,该链表的数据域是姓名和学号,指针域为list_head;接着使用list_add插入节点,使用list_for_each遍历整个链表,使用list_entry找出数据结构指针。由于list_add插入节点使用的是头插法,也就是说每次都在头节点处插入,因此先插入的节点反而在遍历时后打印出来。
内核链表是我们进行内核学习必须掌握的数据结构之一,它可以说是内核中使用得最为广泛的数据结构。除了能够正确使用内核链表,对于内核链表中各种操作方法的理解也是我们需要做到的。通过使用source insight查看内核源码在include/linux/list.h下分析内核链表的初始化、插入、删除、搬移、合并和遍历等操作的具体实现方法。如果你真正理解了内核链表,那么不仅对你学习内核有帮助,将它一直到你的应用程序中使用,也会使你的程序变得更加健壮。
另外一个函数: