当前位置:   article > 正文

Linux内核链表 list_head学习笔记_head_list

head_list

Linux内核链表 list_head学习笔记

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

struct list_head {
	struct list_head *next, *prev;
};
//list_head为包含指针的结构体
  • 1
  • 2
  • 3
  • 4

  • 链表创建

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} ;   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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

  • 创建结构体:
struct birthday {
	int day;
	int month;
	int year;
	struct list_head list;
}
//嵌套了list_head的结构体birthday
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

先创建链表头

static LIST_HEAD(header);
  • 1

创建首节点

  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)代表一个大括号及其俩地址
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

而后将此节点插入header之后

list_add_tail(&me.list,&birthday.list);
  • 1
  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)代表一个大括号及其俩地址
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

而后将此节点插入header之后

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

链表操作

  • 插入节点

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);
//删除链表中的任意节点
  • 1
  • 2

e.g.:

list_del(&me.list);
  • 1

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

从前向后遍历

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

从后向前遍历

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

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

  • 找出宿主结构
container_of(ptr, type, member)
//根据结构体重的一个成员变量地址导出包含这个成员变量member的struct地址
  • 1
  • 2
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.
 */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

获取链表的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.
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

遍历结构体

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.
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

e.g.

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/128084
推荐阅读
相关标签
  

闽ICP备14008679号