Linux内核链表 list_head学习笔记

Linux内核链表 list_head学习笔记

kernel/inclue/linux/types.h中定义的list_head结构如下

struct list_head {
	struct list_head *next, *prev;
};
//list_head为包含指针的结构体

  • 链表创建

Linux内核中的定义:


#define LIST_HEAD_INIT(name) { &(name), &(name) }
//括号内参数为地址/指针

#define LIST_HEAD(name) \
	struct list_head name = LIST_HEAD_INIT(name)
//LIST_HEAD(name) 即为创建一个名为‘name’的list_head结构体,即链表头,pre和next指针都指向自己

	static inline void INIT_LIST_HEAD(struct list_head *list)
{
	WRITE_ONCE(list->next, list);
	list->prev = list;
}
//已经创建了所需的结构体地址
```c
LIST_HEAD(name);
//等价于
struct list_head name = {&name,  &name} ;   

实际应用:list_head单独使用没有意义,需要再嵌套入结构体中,加入所需的可赋值变量

  • 创建结构体:
struct birthday {
	int day;
	int month;
	int year;
	struct list_head list;
}
//嵌套了list_head的结构体birthday

先创建链表头

static LIST_HEAD(header);

创建首节点

  1. 方法一:
struct birthday me={
.day=22,
.month=8,
.2000,
.list=LIST_HEAD_INIT(me.list);
};
//#define LIST_HEAD_INIT(name) { &(name), &(name) }
//LIST_HEAD_INIT(name)代表一个大括号及其俩地址

而后将此节点插入header之后

list_add_tail(&me.list,&birthday.list);
  1. 方法二
struct birthday *me;
me.day=22;
me.month=8;
me.2000;
INIT_LIST_HEAD(&me.list);
//#define LIST_HEAD_INIT(name) { &(name), &(name) }
//LIST_HEAD_INIT(name)代表一个大括号及其俩地址

而后将此节点插入header之后

list_add_tail(&me.list,&birthday.list);

链表操作

  • 插入节点

list_addlist_add_tail区别:

list_add(&me.list,&header)list_add_tail(&me.list,&header)
list_addlist_add_tail
在链表头head后方插入一个新节点在链表头前方依次插入新的节点

  • 删除节点
list_del(struct list_head *entry);
//删除链表中的任意节点

e.g.:

list_del(&me.list);

  • 链表遍历(只是list_head的遍历)
    内核中的遍历方式

从前向后遍历

#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)
//从前向后遍历

从后向前遍历

#define list_for_each_prev(pos, head) \
	for (pos = (head)->prev; pos != (head); pos = pos->prev)
//从后向前遍历

  • 宿主结构(包含list_head的结构体)

  • 找出宿主结构
container_of(ptr, type, member)
//根据结构体重的一个成员变量地址导出包含这个成员变量member的struct地址
ptrtypemember
ptr : 成员变量mem的地址type: 包含成员变量mem的宿主结构体的类型member: 在宿主结构中的mem成员变量的名称

  • 宿主结构的遍历

获取链表的首元素

list_first_entry(ptr, type, member)
// get the first element from a list
/**
 * list_first_entry - get the first element from a list
 * @ptr:	the list head to take the element from.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_head within the struct.
 *
 * Note, that list is expected to be not empty.
 */

获取链表的next

list_next_entry(pos, member)
// get the next element from a list

/**
 * list_next_entry - get the next element in list
 * @pos:	the type * to cursor(确定指针类型)
 * @member:	the name of the list_head within the struct.
 */

遍历结构体

list_for_each_entry(pos, head, member)	
//pos只是用来typeof获得结构类型
#define list_for_each_entry(pos, head, member)				\
for (pos = list_first_entry(head, typeof(*pos), member);	\
	     &pos->member != (head);					\
	     pos = list_next_entry(pos, member))
/**
 * 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.
 */

e.g.

struct birthday *ptr;
list_for_each_entry(ptr,&birthday_list,list)
{ 
         printk ("val =  %d\n" , ptr->val); 
}

资料source:CSDN博主:风亦路 All Rights Reserved
万分感谢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值