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);   测试链表是否为空​