要使用内核链表,需要包含头文件<linux/list.h>,链表结构定义如下:
struct list_head {
struct list_head *next, *prev;
};
Linux内核中的链表是一个双向循环链表,结构中只包含两个指针next和prev,不包含其它任何数据成员,同常见定义链表稍有不同。在Linux内核中使用链表,是将链表内嵌在其它结构体中来使用,从这里也可以看出,Linux内核虽然使用c语言这种非面向对象语言,但也体现出了面向对象的思想(继承)。
例如:
struct todo_struct { struct list_head list; int priority; /* driver specific */ /* ... add other driver-specific fields */ };
1. 链表头
链表头通常需要单独维护,例如:
struct list_head todo_list;定义了一个链表头todo_list,在使用之前,需要使用宏INIT_LIST_HEAD对链表头做初始化:
INIT_LIST_HEAD(&todo_list);
LIST_HEAD(todo_list);实际展开后如下:
struct list_head todo_list = { &todo_list, &todo_list };所谓初始化就是让链表中的next、prev指针同时指向自己。
void list_add(struct list_head *new, struct list_head *head); void list_add_tail(struct list_head *new, struct list_head *head);当然这个头并不是绝对意义上的链表头,也可以是链表中的其它节点,表示在该节点之后或之前插入一个新节点。
void list_del(struct list_head *entry);
int list_empty(const struct list_head *head);
void list_splice(const struct list_head *list, struct list_head *head);
void todo_add_entry(struct todo_struct *new) { struct list_head *ptr; struct todo_struct *entry; list_for_each(ptr, &todo_list) { entry = list_entry(ptr, struct todo_struct, list); if (entry->priority < new->priority) { list_add_tail(&new->list, ptr); return; } } list_add_tail(&new->list, &todo_struct); }list_entry定义有三个参数,第一个参数是struct list_head类型的指针,第二个参数是包含这个struct list_head成员的结构体类型,例如前面的struct todo_struct,第三个参数是结构体中该struct list_head的名字。
8. list_for_each_entry、list_for_each_entry_safe
使用这两个宏的话,就不用在list_for_each中调用list_entry宏。