当前位置: 首页 > news >正文

linux内核中list的基本用法

内核链表

1 list_head 结构

为了使用链表机制,驱动程序需要包含<linux/types.h>头文件,该文件定义了如下结构体实现双向链:

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

2 链表的初始化

2.1 链表宏定义和初始化

可使用以下宏定义并初始化一个链表头部list_head,list_head 不包含数据部分。LIST_HEAD_INIT将链表头的 next 和 prev 指针都指向链表头部,从而形成一个循环结构,和下面介绍的INIT_LIST_HEAD函数一样。

#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) \struct list_head name = LIST_HEAD_INIT(name)
2.2 链表的初始化

INIT_LIST_HEAD 是一个用于初始化链表头的函数,它将链表头的 next 和 prev 指针都指向自己,从而形成一个循环结构。

static inline void INIT_LIST_HEAD(struct list_head *list)
{WRITE_ONCE(list->next, list);WRITE_ONCE(list->prev, list);
}

如下图所示,链表头的 next 和 prev 指针都指向自己。
在这里插入图片描述

3 list_add

在链表的头部添加新链表项,以下是实现:

static inline void list_add(struct list_head *new, struct list_head *head)
{__list_add(new, head, head->next);
}static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)
{if (!__list_add_valid(new, prev, next))return;next->prev = new;new->next = next;new->prev = prev;WRITE_ONCE(prev->next, new);
}

以下为添加示意图,可以看出后添加节点放在链表的头部,先添加节点靠后,先进后出,后进先出,类似栈结构。
在这里插入图片描述

4 list_add_tail

在链表的尾部添加新链表项,以下是实现:


static inline void list_add_tail(struct list_head *new, struct list_head *head)
{__list_add(new, head->prev, head);
}static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)
{if (!__list_add_valid(new, prev, next))return;next->prev = new;new->next = next;new->prev = prev;WRITE_ONCE(prev->next, new);
}

以下为添加示意图,可以看出新添加节点放在链表的尾部,后添加节点靠,先进先出,后进后出,类似FIFO结构。
list_add_tail

5 遍历节点

5.1 list_entry

list_entry 宏通过调用 container_of 宏,从链表节点指针获取包含该节点的结构体指针。

/*** list_entry - get the struct for this entry* @ptr: 指向 &struct list_head 的指针。* @type: 包含该节点的结构体类型。* @member: 结构体中的 list_struct 名称。*/
#define list_entry(ptr, type, member) \container_of(ptr, type, member)
5.2 list_for_each

list_for_each 从链表的头部往后依次遍历(next方向)。

/*** list_for_each	-	iterate over a list* @pos:	the &struct list_head to use as a loop cursor.* @head:	the head for your list.*/
#define list_for_each(pos, head) \for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)
5.3 list_for_each_entry

通过for循环,依次遍历链表中的每个节点,next方向遍历,每个节点的宿主为pos。

/*** 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))

a. list_first_entry 宏:

#define list_first_entry(ptr, type, member) \container_of((ptr)->next, type, member)

list_first_entry 宏用于获取链表的第一个节点的结构体指针。通过 (ptr)->next 获取到链表头部之后的第一个节点的指针,然后通过 container_of 宏获取包含该节点的整个结构体指针。

b. list_entry_is_head 宏:

#define list_entry_is_head(pos, head, member) \((pos)->member == (head))

list_entry_is_head 宏用于检查当前节点是否是链表的头部。比较 pos->member 是否等于 head,如果相等,则说明当前节点是链表的头部,即遍历结束。

c. list_next_entry 宏:

#define list_next_entry(pos, member) \list_entry((pos)->member.next, typeof(*(pos)), member)

list_next_entry 宏用于获取下一个节点的结构体指针。通过 (pos)->member.next 获取到当前节点的下一个节点的指针,然后通过 list_entry 宏获取包含该节点的整个结构体指针。

5.4 list_for_each_prev

通过for循环,依次遍历链表中的每个节点,与list_for_each_entry不同的是list_for_each_prev按照pre方向遍历,每个节点的宿主为pos。

/*** list_for_each_prev	-	iterate over a list backwards* @pos:	the &struct list_head to use as a loop cursor.* @head:	the head for your list.*/
#define list_for_each_prev(pos, head) \for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
5.5 删除链表

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;
}

list_del_init
删除列表中的给定项,如果删除后的链表可能被插入新的链表中,应该使用list_del_init,它会初始化链表的指针。

/*** list_del_init - deletes entry from list and reinitialize it.* @entry: the element to delete from the list.*/
static inline void list_del_init(struct list_head *entry)
{__list_del_entry(entry);INIT_LIST_HEAD(entry);
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • ELK日志分析系统部署文档
  • Memcached开发(八):使用PHP进行操作
  • Websocket自动消息回复服务端工具
  • elementUI在手机端使用遇到的问题总结
  • 计算机视觉发展历程
  • docker compose 容器 编排分组
  • 基于python深度学习遥感影像地物分类与目标识别、分割实践技术应用
  • Uniapp鸿蒙项目实战
  • PostgreSQL 中如何解决因大量并发删除和插入操作导致的索引抖动?
  • 用C语言写的一个扫雷小游戏
  • Composition API实现逻辑复用
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • Matlab课程设计——手指静脉识别项目
  • 项目名称:C语言在线学习平台(README)
  • nginx配置文件说明
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • java8 Stream Pipelines 浅析
  • Mysql数据库的条件查询语句
  • spring-boot List转Page
  • Web Storage相关
  • 彻底搞懂浏览器Event-loop
  • 代理模式
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 实习面试笔记
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 首页查询功能的一次实现过程
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • - 转 Ext2.0 form使用实例
  • HanLP分词命名实体提取详解
  • Mac 上flink的安装与启动
  • ​字​节​一​面​
  • ‌前端列表展示1000条大量数据时,后端通常需要进行一定的处理。‌
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (第三期)书生大模型实战营——InternVL(冷笑话大师)部署微调实践
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (汇总)os模块以及shutil模块对文件的操作
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • .htaccess配置重写url引擎
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .net Signalr 使用笔记
  • .net 获取url的方法
  • .NET分布式缓存Memcached从入门到实战
  • 。。。。。
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • @media screen 针对不同移动设备