操作系统内核经常要维护内核数据结构的链表。有时,Linux内核数据结构中同时存在着多个链表的实现代码。为了减少重复代码的数量,内核开发者已经建立了一套标准的循环、双向链表的实现。如果你需要操作链表,那么建议你使用这一内核机制。
当使用这些链表接口时,应该始终牢记这么链表函数不进行任何锁定。如果你的驱动程序有可能试图对同一个链表执行并发操作的话,则有责任实现一个锁方案。否则,崩溃的链表结构体、数据丢失、内核混乱等问题是很难诊断的。
为了使用这个链表机制,驱动程序必须包含头文件<linux/list.h>,该文件定义了一个简单的list_head结构体。
struct list_head {
struct list_head *next, *prev;
用于实际代码的链表几乎都是由某种结构类型组成,没个结构描述链表中的一项,为了在代码中使用Linux链表机制,只需要在构成链表的结构里面嵌入一个list_head,如果驱动程序维护一个链表,则可声明如下:}
struct toto_struct{
struct list_head *list;
int priority;
/*........*/
};
在使用之前,必须用INIT_LIST_HEAD宏来初始化链表头。可如下声明并初始化一个实际的链表头:
struct list_head todo_list;
另外,也可在编译时初始化链表INIT_LIST_HEAD(&todo_list);
LIST_HEAD(todo_list);
头文件 <linux/list.h>中声明了下列操作链表的函数:list_add(struct list_head *new, struct list_head *head);
在链表头后面添加新项——通常在链表的头部。
list_add_tail(struct list_head *new, struct list_head *head)
在给定链表头的前面添加了一个新的项,即在链表的末尾处添加。
list_head结构体有利于实现具有类似结构的链表,但调用程序通常对组成链表的大结构更感兴趣。因此,可利用list_entry宏将一个list_head结构指针映射会指向包含它的大结构的指针。
list_entry(struct list_head *ptr,type_of_struct, field_name);
其中,ptr是指向正被使用的list_head结构体,type_of_struct是包含ptr的结构类型,field_name是结构体中链表字段的名字。