当前位置:   article > 正文

Linux 内核双向链表_linux 双向链表

linux 双向链表

0x01:链表

链表是Linux内核中非常重要的数据结构,在日常内核驱动开发过程中,往往需要遍历内核的某个链表,内核提供了一套完整的双链表机制,使开发者可以在内核私有数据结构中轻松构建双向链表,一起学习双向链表的构建和遍历方法,具体链表的知识可以参考文末链接;

0x02:数据结构及关键函数

  • 链表可以用list_head来描述

    struct list_head {
    struct list_head *next, *prev;
    };
    
    • 1
    • 2
    • 3

    list_head结构体不包含链表节点的数据区,而是通常嵌入其他数据结构,如page 数据结构中就嵌入了lru链表节点,通常的做法是将page结构体挂入LRU链表。

    struct page {
    ...
    struct list_head lru;
    ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 链表头初始化

    • 静态初始化,name为链表头名
    #define LIST_HEAD_INIT(name) { &(name), &(name) }
    
    #define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)
    
    • 1
    • 2
    • 3
    • 4
    • 动态初始化
     * INIT_LIST_HEAD - Initialize a list_head structure
     * @list: list_head structure to be initialized.
     *
     * Initializes the list_head to point to itself.  If it is a list header,
     * the result is an empty list.
     */
    static inline void INIT_LIST_HEAD(struct list_head *list)
    {
    	WRITE_ONCE(list->next, list);
    	WRITE_ONCE(list->prev, list);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 添加节点到链表

    • list_add
      把新节点添加到链表头。
    /**
     * list_add - add a new entry
     * @new: new entry to be added
     * @head: list head to add it after
     *
     * Insert a new entry after the specified head.
     * This is good for implementing stacks.
     */
    static inline void list_add(struct list_head *new, struct list_head *head)
    {
    	__list_add(new, head, head->next);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • list_add_tail
      把新节点添加到表尾。
    /**
     * list_add_tail - add a new entry
     * @new: new entry to be added
     * @head: list head to add it before
     *
     * Insert a new entry before the specified head.
     * This is useful for implementing queues.
     */
    static inline void list_add_tail(struct list_head *new, struct list_head *head)
    {
    	__list_add(new, head->prev, head);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 从链表中删除某个节点

    • list_del
    /**
     * list_del - deletes entry from list.
     * @entry: the element to delete from the list.
     * Note: list_empty() on entry does not return true after this, the entry is
     * in an undefined state.
     */
    static inline void list_del(struct list_head *entry)
    {
    	__list_del_entry(entry);
    	entry->next = LIST_POISON1;
    	entry->prev = LIST_POISON2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 替换链表中的某个节点

    • list_replace
    	/**
     * list_replace - replace old entry by new one
     * @old : the element to be replaced
     * @new : the new element to insert
     *
     * If @old was empty, it will be overwritten.
     */
    static inline void list_replace(struct list_head *old,
    				struct list_head *new)
    {
    	new->next = old->next;
    	new->next->prev = new;
    	new->prev = old->prev;
    	new->prev->next = new;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 合并链表

    • list_splice(struct list_head *list,struct list_head *head)
      合并两个链表,它将 list 指向的链表的每个节点插入到指定链表的 head 元素后面(不会修改 list 链表本身)。
    • list_splice_init(struct list_head *list,struct list_head *head)
      与list_splice函数一致,但是会重新init list,相当与删除原链表。
  • 链表遍历

    • list_entry
    /**
     * list_entry - get the struct for this entry
     * @ptr:	the &struct list_head pointer.
     * @type:	the type of the struct this is embedded in.
     * @member:	the name of the list_head within the struct.
     */
    #define list_entry(ptr, type, member) \
    	container_of(ptr, type, member)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • list_for_each_safe
      获取结构体指针需要使用list_entry(),可以参考示例。
    /**
     * list_for_each_safe - iterate over a list safe against removal of list entry
     * @pos:	the &struct list_head to use as a loop cursor.
     * @n:		another &struct list_head to use as temporary storage
     * @head:	the head for your list.
     */
    #define list_for_each_safe(pos, n, head) \
    	for (pos = (head)->next, n = pos->next; \
    	     !list_is_head(pos, (head)); \
    	     pos = n, n = pos->next)
    
    // 参考使用示例
    getframe_deferred(struct aoedev *d, u32 tag)
    {
          struct list_head *head, *pos, *nx;
          struct frame *f;
    
          head = &d->rexmitq;
          list_for_each_safe(pos, nx, head) {
                  f = list_entry(pos, struct frame, head);
                  if (f->tag == tag) {
                          list_del(pos);
                          return f;
                  }
          }
          return NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • list_for_each_entry
    /**
     * list_for_each_entry	-	iterate over list of given type
     * @pos:	the type * to use as a loop cursor.
     * @head:	the head for your list.
     * @member:	the name of the list_head within the struct.
     */
    #define list_for_each_entry(pos, head, member)				\
    	for (pos = list_first_entry(head, typeof(*pos), member);	\
    	     !list_entry_is_head(pos, head, member);			\
    	     pos = list_next_entry(pos, member))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

0x03:双向链表使用示例

  • 示例代码
//list.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

/* header of list */
#include <linux/list.h>

/* private structure */
struct node {
    const char *name;
    struct list_head list;
};

/* Initialize a group node structure */
static struct node node0 = { .name = "BiscuitOS_node0", };
static struct node node1 = { .name = "BiscuitOS_node1", };
static struct node node2 = { .name = "BiscuitOS_node2", };
static struct node node3 = { .name = "BiscuitOS_node3", };
static struct node node4 = { .name = "BiscuitOS_node4", };
static struct node node5 = { .name = "BiscuitOS_node5", };
static struct node node6 = { .name = "BiscuitOS_node6", };

/* Declaration and implement a bindirect-list */
LIST_HEAD(BiscuitOS_list);

static __init int list_entry_init(void)
{
  struct node *np;

  /* add a new entry on special entry */
  list_add_tail(&node0.list, &BiscuitOS_list);
  list_add_tail(&node1.list, &BiscuitOS_list);
  list_add_tail(&node2.list, &BiscuitOS_list);

  printk("BiscuitOS_list:\n");
  /* Traverser all node on bindirect-list */
  list_for_each_entry(np, &BiscuitOS_list, list)
    printk("%s\n", np->name);

  /* get the struct for this entry */
  np = list_entry(BiscuitOS_list.next, struct node, list);
  printk("The entry struct node: %s\n", np->name);

  /* get the first element from a list */
  np = list_first_entry(&BiscuitOS_list, struct node, list);
  printk("The first entry struct node: %s\n", np->name);

  return -1;
}


static void __exit list_entry_exit(void)
{
  printk("Bye bye list_entry\n");
}

module_init(list_entry_init);
module_exit(list_entry_exit); 
MODULE_LICENSE("GPL");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

Makefile:

obj-m += list.o

KBUILD_CFLAGS+= -g

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 测试效果
[ 2113.170373] BiscuitOS_list:
[ 2113.170374] BiscuitOS_node0
[ 2113.170374] BiscuitOS_node1
[ 2113.170375] BiscuitOS_node2
[ 2113.170376] The entry struct node: BiscuitOS_node0
[ 2113.170376] The first entry struct node: BiscuitOS_node0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/185437
推荐阅读
相关标签
  

闽ICP备14008679号