1、在Linux内核中经常能够看到 struct list_head 这样的一个结构体,这个就是内核中的一个链表,内核链表
struct list_head {
struct list_head *next, *prev;
};
这个结构体中只有两个指向链表结构体的指针,分为前向指针和后向指针,因为可以用来构建一个双向链表,但是这个链表的用法与我们普通的链表的用法不一样,
我们的一般的链表结构体中都会包含两部分:一个是指针(前向指针和后向指针)部分,还有就是有效数据部分。将我们链表需要存放的数据放在结构体中的有效数据
区中,通过两个节点分别指向上一个节点和下一个节点。这是一般的链表的使用方法。
(1)但是内核链表的结构体中只有两个指针,并没有有效数据区,所以内核链表的用法和我们的普通链表的用法是不一样的,我们使用内核链表的方法就是:
自己建立一个结构体去包含这个内核链表,将整个结构体作为一个链表的节点,然后使用内置的链表的前向指针指向下一个结构体中内置的链表,使用内置的链表的
后向指针指向上一个结构体中内置的链表。
例如:
struct A{
struct list_head list;
.........
};
struct A a;
struct A b;
struct A c;
a.list.next = b.list;
b.list.prev = a.list, b.list.next = c.list;
c.list.prev = b.list;
2、内核链表相关的函数和宏定义
(1)内核链表的初始化
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
由上面可以知道,初始化就是将list_head中的两个指针都指向自己本身。初始化一个内核链表的方法:
(1.1) 定义一个内核链表并进行初始化可以直接调用宏: LIST_HEAD(list); 展开之后: struct list_head list = { &(list), &(list) }
(1.2) 也可以定义和初始化分开, struct list_head list; INIT_LIST_HEAD(&list);
(2)内核链表的常用函数
(2.1) list_add(struct list_head *new, struct list_head *head); 将节点插入到链表头部
list_add_tail(struct list_head *new, struct list_head *head); 将节点插入到链表尾部
(2.2) list_del(struct list_head *entry); 删除一个节点,并将他的指针清除0
list_del_init(struct list_head *entry); 删除一个节点,并将他的指针再次指向自己本身
(2.3) list_replace(struct list_head *old, struct list_head *new); 替换链表中的某个节点, old需要被替换的节点, new新的节点
list_replace_init(struct list_head *old, struct list_head *new); 和上面的区别在于,把替换之后的老的节点进行初始化
(2.4) int list_is_last(const struct list_head *list, const struct list_head *head); 测试一个节点是否为链表头节点,list是要测试的节点,head是一个链表头
int list_empty(const struct list_head *head); 测试链表是否为空