赞
踩
链表是Linux内核中非常重要的数据结构,在日常内核驱动开发过程中,往往需要遍历内核的某个链表,内核提供了一套完整的双链表机制,使开发者可以在内核私有数据结构中轻松构建双向链表,一起学习双向链表的构建和遍历方法,具体链表的知识可以参考文末链接;
链表可以用list_head
来描述
struct list_head {
struct list_head *next, *prev;
};
list_head结构体不包含链表节点的数据区,而是通常嵌入其他数据结构,如page 数据结构中就嵌入了lru链表节点,通常的做法是将page结构体挂入LRU链表。
struct page {
...
struct list_head lru;
...
}
链表头初始化
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
* 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);
}
添加节点到链表
/**
* 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);
}
/**
* 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);
}
从链表中删除某个节点
/**
* 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;
}
替换链表中的某个节点
/**
* 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;
}
合并链表
list_splice(struct list_head *list,struct list_head *head)
list_splice_init(struct list_head *list,struct list_head *head)
链表遍历
/**
* 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)
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; }
/**
* 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))
//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");
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
[ 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。