内核链表list_head

内核链表

普通链表与内核链表的区别

普通链表:把数据结构放入链表

struct list_element {
	void *data;
	struct list_element *next;
	struct list_element *prev;
}

内核链表:把链表放入数据结构

struct fox {
	unsigned long tail_length;
	unsigned long weight;
	struct list_head list;
}

list_head

简介

内核中已经实现了链表的结构体,直接拿来用即可。

struct list_head {
	struct list_head *next,*prev;
}

使用例程:

struct fox {
	unsigned long tail_length;
	unsigned long weight;
	struct list_head list_node;
}

如何找到父结构呢

因为一个给定的结构,在编译的时候,其大小和内部成员的便宜地址就被确定下来了,所以,通过计算偏移量即可获得父结构体的地址。

链表头

链表头:

创建一个链表后,需要一个头节点来索引这个链表,这个头节点一般不存储数据(链表的遍历方法中,是没有获取head的这个结构体的,不会取出head,所以也无法取出这个数据,所以一般不在这个head的节点这存储数据。),只用来索引其他的数据。

示意图:

创建链表头有两个方法,两个方法是一样的:

  • LIST_HEAD();
    
  • struct list_head head;
    LIST_HEAD_INIT(head);
    

他们的宏定义如下:

INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list->prev = list;
}


#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
	struct list_head name = LIST_HEAD_INIT(name)

📌提示
#define LIST_HEAD_INIT(name) { &(name), &(name) }​这个的作用是将list_head的next、prev都指向自己。

例如:

struct fox red_fox {
	.tail_length = 40,
	.weight = 6,
	.list = LIST_HEAD_INIT(red_fox.list),
}

//宏展开后就变成了

struct fox red_fox {
	.tail_length = 40,
	.weight = 6,
	.list = {&red_fox.list,red_fox.list},
}

list_head相关的操作方法

list_add

给链表增加一个节点

static inline void list_add(struct list_head *new, \
				struct list_head *head);

list_del

删除一个节点

void list_del(struct list_head *entry);

📌提示
这个函数只将entry元素从链表中移除,但并不释放这个元素所占用的内存空间。通常还需要用其他函数(例如:kfree(const void *objp)​​)删除这个结构体。

list_del删除原理

源码:

static inline void list_del(struct list_head *entry)
{
	__list_del_entry(entry);//从链表中中移除
	entry->next = LIST_POISON1;
	entry->prev = LIST_POISON2;
	//将删除的entry的list_head指向内核内存之外的地方,只要使用就会报错。
}

在使用了list_del后,被删除的entry指向的地址在内核内存地址之外,所以要么释放掉内存,要么使用list_del_init。

list_del_init

list_del​和list_del_init​的区别就是被删除的entry会被重新指向自己就相当于自己成为了链表头

list_del​和list_del_init​的区别图示:

list_empty

检查链表是否为空,为空则返回1(真),不为空则返回0(假)。

static inline int list_empty(const struct list_head *head)

list_for_each_entry

遍历所有的节点

list_for_each_entry(struct list_head *pos, \
	struct list_head *head, \
	<member.list_head's name>)
  • pos​:list_head结构体,需要新建一个,以作为遍历的成员。
  • head​:链表头
  • <member.list_head's name>​:这是链表数据结构体(包含list_head的结构体)中的list_head成员的名字。

📌提示
如果链表头的list_head的父结构体也有数据,那这个数据是无法遍历出来的,具体看完整例程,这里可以看到

list_entry

通过list_head成员获取父结构体(通过链表节点获取数据)

struct <struct_type> *list_entry(struct list_head *pos, \
	struct <struct_type>, \
	<member.list_head's name>)

示例:

//前面省略,详细代码可以查看完整例程
struct fox *fp;
printk("get letter_head data\n");
fp = list_entry(&fox_let_head.list_node,struct fox,list_node);
printk("fox id: %s\n",fp->fox_name);
printk("get letter_head data done\n");
printk("\n");

//结果
/*
[   92.619530] get letter_head data
[   92.619540] fox id: let_head
[   92.619550] get letter_head data done
[   92.619562]

*/

list_splice

将两个链表拼接起来

static inline void list_splice(const struct list_head *list,
				struct list_head *head)
  • *list​是要被放到后面的链表,这个链表的链表头会被丢弃
  • *head​这个链表是主链表,最后拼接的链表的链表头就是这个

例子:

//前面省略,详细代码可以查看完整例程
	//遍历letter链表
	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");
	//遍历number链表
	printk("all num_fox:\n");
	list_for_each_entry(fp,&fox_num_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");
	//链表拼接
	printk("splice number_fox_list to letter_fox_list \n");
	list_splice_init(&fox_num_head.list_node,&fox_let_head.list_node);
	printk("splice number_fox_list to letter_fox_list done\n");
	printk("\n");
	//检查拼接结果,letter_fox链表的状态
	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");
	//检查number_fox链表的状态
	printk("all num_fox:\n");
	list_for_each_entry(fp,&fox_num_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	retun 0;
}

//结果
/*
[   36.954121] all letter_fox:
[   36.954131] fox id: b
[   36.954141] fox id: c
[   36.954152] fox id: a
[   36.954160]
[   36.954168] all num_fox:
[   36.954176] fox id: 3
[   36.954184] fox id: 2
[   36.954192] fox id: 1
[   36.954199]
[   36.954208] splice number_fox_list to letter_fox_list
[   36.954218] splice number_fox_list to letter_fox_list done
[   36.954228]
[   36.954238] all letter_fox:
[   36.954249] fox id: 3
[   36.954257] fox id: 2
[   36.954267] fox id: 1
[   36.954276] fox id: b
[   36.954287] fox id: c
[   36.954295] fox id: a
[   36.954305]
[   36.954315] all num_fox:
[   36.954325] fox id: 3
[   36.954334] fox id: 2
[   36.954344] fox id: 1
[   36.954353] fox id: b
[   36.954364] fox id: c
[   36.954373] fox id: a
[   36.954380] fox id: let_head
[   36.954389] fox id: 3
[   36.954400] fox id: 2
[   36.954410] fox id: 1
[   36.954420] fox id: b
[   36.954430] fox id: c
[   36.954439] fox id: a
[   36.954449] fox id: let_head
[   36.954459] fox id: 3
[   36.954468] fox id: 2
[   36.954479] fox id: 1
[   36.954488] fox id: b
[   36.954499] fox id: c
[   36.954508] fox id: a
[   36.954518] fox id: let_head
......无限循环
*/

为什么会产生无线循环?

拼接后链表的示意图:

根据list_for_each_entry​原理可知,当遍历num_list时,无法返回num_head,所以会一直循环遍历。解决这个问题,看list_splice_init

list_splice_init

将两个链表拼接起来,并且初始化*list​的链表头。

功能和list_splice一样,增加了初始化*list​链表头的功能。

static inline void list_splice_init(const struct list_head *list,
				struct list_head *head)

对比list_splice例程的示意图:

list_for_each_entry_safe

如果想在使用list_for_each_entry​遍历的时候删除该项时,会因为把next的指针也删除掉而找不到下一个节点。所以,linux内核提供list_for_each_entry_safe​,这个函数的作用是,把当前遍历项的next或者prev指针保存在一个临时的变量当中,当要删除该项的时候,就不会出现找不到下一个(或者上一个)的情况。

list_for_each_entry_safe(){
	list_del();
}

为什么不删除遍历当前项的上一项呢?

如果删除遍历的上一项,当删除第一项的时候,会将链表头也删除,到遍历到最后一项的时候,因为回不到链表头了,就会报错。

📌提示
这个函数仍然需要加锁!这个函数只能保证在函数内部进行删除不会出问题,如果在其他地方有并发删除,这仍然会出问题。

完整例程

#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/list.h>

#define LET "letter"
#define NUM "number"

struct fox {
	char *fox_name;
	char *groups;
	struct list_head list_node;
};

struct fox fox_let_head = {
	.fox_name = "let_head",
	.groups = LET,
	.list_node = LIST_HEAD_INIT(fox_let_head.list_node),
};

struct fox fox_num_head = {
	.fox_name = "num_head",
	.groups = LET,
	.list_node = LIST_HEAD_INIT(fox_num_head.list_node),
};

int wgtest_init(void)
{
	struct fox *fp;

	struct fox fox_a = {
		.fox_name = "a",
		.groups = LET,
	};

	struct fox fox_b = {
        .fox_name = "b",
        .groups = LET,
    };

	struct fox fox_c = {
        .fox_name = "c",
        .groups = LET,
    };

	struct fox fox_1 = {
		.fox_name = "1",
		.groups = NUM,
	};

	struct fox fox_2 = {
        .fox_name = "2",
        .groups = NUM,
    };

	struct fox fox_3 = {
        .fox_name = "3",
        .groups = NUM,
    };

	printk("if let_list is empty:\n");
	if (list_empty(&fox_let_head.list_node)) {
		printk("yes\n");
	} else {
		printk("no\n");
	}
	printk("\n");

	printk("if num_list is empty:\n");
	if (list_empty(&fox_num_head.list_node)) {
		printk("yes\n");
	} else {
		printk("no\n");
	}
	printk("\n");

	//初始化
	printk("add letter_fox to letter_fox_list\n");
	list_add(&fox_a.list_node,&fox_let_head.list_node);
	list_add(&fox_b.list_node,&fox_let_head.list_node);
	list_add(&fox_c.list_node,&fox_let_head.list_node);
	printk("add letter_fox to letter_fox_list done\n");
	printk("\n");

	printk("add num_fox to num_fox_list\n");
	list_add(&fox_1.list_node,&fox_num_head.list_node);
	list_add(&fox_2.list_node,&fox_num_head.list_node);
	list_add(&fox_3.list_node,&fox_num_head.list_node);
	printk("add letter_fox to letter_fox_list done\n");
	printk("\n");

	//list_empty
	printk("if let_list is empty:\n");
	if (list_empty(&fox_let_head.list_node)) {
		printk("yes\n");
	} else {
		printk("no\n");
	}
	printk("\n");

	printk("if num_list is empty:\n");
	if (list_empty(&fox_num_head.list_node)) {
		printk("yes\n");
	} else {
		printk("no\n");
	}
	printk("\n");

	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	printk("all num_fox:\n");
	list_for_each_entry(fp,&fox_num_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	//list_del
	printk("wg fox_b next 1:%p",fox_b.list_node.next);//fox_b next指针指向的位置
	printk("wg fox_a 1:%p",&fox_a.list_node);//fox_a list_head的位置
	printk("del fox_b from letter_fox_list\n");
	list_del(&fox_b.list_node);
	printk("del fox_b from letter_fox_list done\n");
	printk("wg fox_b next 2:%p",fox_b.list_node.next);
	printk("wg fox_a 2:%p",&fox_a.list_node);
	printk("\n");

	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	//list_add
	printk("add fox_b to letter_fox_list\n");
	list_add(&fox_b.list_node,&fox_let_head.list_node);
	printk("add fox_b to letter_fox_list done\n");
	printk("\n");

	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	//list_move
	printk("move fox_b from letter_fox_list to number_fox_list\n");
	list_move(&fox_b.list_node,&fox_num_head.list_node);
	printk("move fox_b from letter_fox_list to number_fox_list done\n");
	printk("\n");

	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	printk("all num_fox:\n");
	list_for_each_entry(fp,&fox_num_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	printk("move fox_b from number_fox_list to letter_fox_list\n");
	list_move(&fox_b.list_node,&fox_let_head.list_node);
	printk("move fox_b from number_fox_list to letter_fox_list done\n");
	printk("\n");

	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	printk("all num_fox:\n");
	list_for_each_entry(fp,&fox_num_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	//list_entry
	printk("get letter_head data\n");
	fp = list_entry(&fox_let_head.list_node,struct fox,list_node);
	printk("fox id: %s\n",fp->fox_name);
	printk("get letter_head data done\n");
	printk("\n");

	//list_splice_init
	printk("splice number_fox_list to letter_fox_list \n");
	list_splice_init(&fox_num_head.list_node,&fox_let_head.list_node);
	printk("splice number_fox_list to letter_fox_list done\n");
	printk("\n");

	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	printk("all num_fox:\n");
	list_for_each_entry(fp,&fox_num_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}
	printk("\n");

	//list_del_init
	printk("del_init fox_b from letter_fox_list\n");
	list_del_init(&fox_b.list_node);
	printk("del_init fox_b from letter_fox_list done\n");
	printk("\n");

	printk("all letter_fox:\n");
	list_for_each_entry(fp,&fox_let_head.list_node,list_node){
		printk("fox id: %s\n",fp->fox_name);
	}

	fp = &fox_b;
	fp  = list_next_entry(fp,list_node);
	printk("fox_next of fox_b: %s\n",fp->fox_name);

	printk("\n");

	return 0;
}

void wgtest_exit(void)
{
	printk("wgtest_exit11.29\n");
}
module_init(wgtest_init);
module_exit(wgtest_exit);
MODULE_LICENSE("GPL");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值