linux内核双向链表使用list klist

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、list和klist是什么?
  • 二、代码示例
    • 1.list
    • 2.klist
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:
linux内核中大量使用了链表数据结构来存储各种数据,比如device和driver使用klist存储,下面是list和klist使用示例


提示:以下是本篇文章正文内容,下面案例可供参考

一、list和klist是什么?

list:
list_head:双向链表,不带头节点,适用于需要按顺序存储和访问数据的场景。
在这里插入图片描述

klist:
klist: Linux 内核中用于管理和操作内核对象列表的数据结构。可以理解为一种带有引用计数的链表,主要用于跟踪和管理一组相关的对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
内核接口:
list_head:api:include\linux\list.h 中
LIST_HEAD_INIT \宏初始化
LIST_HEAD \宏初始化
INIT_LIST_HEAD \初始化

list_add \添加到头节点后面,头部添加
list_add_tail \添加到头节点前面,尾部添加

list_del \删除list中元素
list_replace 替换旧元素为新的元素

list_for_each
list_for_each_safe

RCU版:
INIT_LIST_HEAD_RCU
list_add_rcu
list_add_tail_rcu
list_del_rcu
list_for_each_entry_rcu
list_for_each_entry_srcu

klist:api:include\linux\klist.h 中
DEFINE_KLIST
klist_init
klist_add_tail
klist_add_head
klist_add_behind
klist_add_before
klist_del
klist_remove
klist_node_attached

二、代码示例

1.list

代码如下(示例):

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("ChatGPT");
MODULE_DESCRIPTION("A Simple List Head Example");struct my_data {int value;struct list_head list; // 使用 list_head 实现链表
};static LIST_HEAD(my_list); // 创建链表头// 初始化链表并添加元素
static void init_list(void) {struct my_data *data;int i = 0;for (i = 0; i < 5; i++) {data = kmalloc(sizeof(struct my_data), GFP_KERNEL);data->value = i;//INIT_LIST_HEAD(&data->list); // 初始化链表节点printk("no INIT_LIST_HEAD i = %d\n", i);// 将新节点添加到链表头list_add_tail(&data->list, &my_list);}
}// 遍历链表并打印值
static void print_list(void) {struct my_data *data;struct list_head *pos;list_for_each(pos, &my_list) {data = list_entry(pos, struct my_data, list);pr_info("Value: %d\n", data->value);}
}// 清理链表并释放内存
static void cleanup_list(void) {struct my_data *data;struct list_head *pos, *q;list_for_each_safe(pos, q, &my_list) {data = list_entry(pos, struct my_data, list);list_del(pos); // 从链表中删除节点kfree(data);   // 释放内存}
}static int __init my_module_init(void) {pr_info("Initializing module...\n");init_list();print_list();return 0;
}static void __exit my_module_exit(void) {pr_info("Cleaning up module...\n");cleanup_list();
}module_init(my_module_init);
module_exit(my_module_exit);

2.klist

代码如下(示例):
多线程暂不完善仅供参考

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/klist.h>
#include <linux/kref.h>struct my_klist_node {struct klist_node n_klist; // klist_node int data;                // 额外的数据
};// 自定义的获取和释放函数
void my_get(struct klist_node *node) {struct my_klist_node *my_node = container_of(node, struct my_klist_node, n_klist);printk(KERN_INFO "Getting node with data: %d\n", my_node->data);//kref_get(&node->n_ref); // 增加引用计数
}void my_put(struct klist_node *node) {struct my_klist_node *my_node = container_of(node, struct my_klist_node, n_klist);printk(KERN_INFO "Putting node with data: %d\n", my_node->data);//kref_put(&node->n_ref, my_kref_release); // 释放内存并减少引用计数kfree(my_node);
}// 定义一个全局 klist 实例
DEFINE_KLIST(my_klist, my_get, my_put);// 添加节点到 klist 的函数
void my_add_node(int value) {struct my_klist_node *new_node;new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);if (!new_node)return;new_node->data = value;klist_add_head(&new_node->n_klist, &my_klist);
}void my_del_node(int value) {struct my_klist_node *new_node;klist_del(&new_node->n_klist);
}static void my_print(void)
{struct klist_iter i;struct klist_node *node;struct my_klist_node *my_node;klist_iter_init_node(&my_klist, &i, NULL);while ((node = klist_next(&i))){my_node = container_of(node, struct my_klist_node, n_klist);printk(KERN_INFO "klist_iter_init_node data: %d\n", my_node->data);}klist_iter_exit(&i);
}// 模块加载函数
static int __init my_module_init(void) {klist_init(&my_klist, my_get, my_put); // 初始化 klistint i = 0;for(i;i < 5; i++){my_add_node(i*10); // 添加一个节点}my_print();return 0;
}// 模块卸载函数
static void __exit my_module_exit(void) {struct klist_iter i;struct klist_node *node;struct my_klist_node *my_node;klist_iter_init_node(&my_klist, &i, NULL);while ((node = klist_next(&i))){my_node = container_of(node, struct my_klist_node, n_klist);printk(KERN_INFO "klist_iter_init_node data: %d\n", my_node->data);//klist_remove 不能在此使用,spin死锁klist_del(&my_node->n_klist); //这个会减少引用计数,可能并不会删除,线程可能不安全//kfree(my_node);}klist_iter_exit(&i);
}module_init(my_module_init);
module_exit(my_module_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Example of using klist in the Linux kernel.");

总结

上面介绍了内核中list和klist和测试代码,仅供参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1547190.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

上市一周暴涨20%,美的的出海之路开了个好头

“宁可走错一步&#xff0c;也不能走错半步”&#xff0c;这是美的集团创始人何享健的名言&#xff0c;也代表着美的集团在扩张方面长期以来一贯的风格&#xff1a;稳健。 映射在当下&#xff0c;就是当老对手海尔智家于2020年率先登陆港交所&#xff0c;国际化策略初显成效以…

JavaWeb 13.HTTP协议

和自己的情绪共处&#xff0c;永远保持乐观 —— 24.9.26 一、HTTP简介 HTTP 超文本传输协议 (HTTP-Hyper Text transfer protocol)&#xff0c;是一个属于应用层的面向对象的协议&#xff0c;由于其简捷、快速的方式&#xff0c;适用于分布式超媒体信息系统。它于1990年提出&a…

考研数据结构——C语言实现归并排序

包含头文件&#xff1a;程序首先包含了标准输入输出库stdio.h&#xff0c;以便使用printf等函数进行输入输出操作。 定义数组和数组大小&#xff1a;定义了一个宏N&#xff0c;其值为5&#xff0c;表示数组q的长度。数组q被初始化为{5, 3, 8, 4, 2}&#xff0c;这是我们要排序…

BFS 解决 FloodFill 算法

BFS 解决 FloodFill 算法 题目一&#xff1a; 图像渲染1. 题⽬链接&#xff1a;2. 题⽬描述&#xff1a;3. 算法思路&#xff1a;4.代码 题目二&#xff1a; 岛屿数量1. 题⽬链接&#xff1a;2. 题⽬描述&#xff1a;3. 算法思路&#xff1a;4.代码 题目三&#xff1a;被围绕的…

论文不会写怎么办?推荐这5款AI论文工具帮你一键搞定!

在当今的学术研究和写作领域&#xff0c;AI论文工具已经成为不可或缺的助手。这些工具不仅能够提高写作效率&#xff0c;还能帮助研究者生成高质量的论文。本文将推荐五款优秀的AI论文工具&#xff0c;并特别推荐千笔-AIPassPaper&#xff0c;以帮助读者更好地完成学术写作任务…

OJ在线评测系统 后端 判题机模块预开发 架构分析 使用工厂模式搭建

判题机模块预开发(架构师)(工厂模式) 判题机模块 是为了把代码交个代码沙箱去处理 得到结果返回 代码沙箱 梳理判题模块和代码沙箱的关系 判题模块&#xff1a;调用代码沙箱 把代码和输入交给代码沙箱去执行 代码沙箱&#xff1a;只负责接受代码和输入 返回编译的结果 不负…

初始化的代码块和@PostConstruct有什么区别

背景 在实际开发中&#xff0c;我们经常会需要进行一些初始化操作&#xff0c;比如进行一些预加载和赋值之类的。在代码中&#xff0c;常见的有通过静态代码块、非静态代码块&#xff0c;PostConstruct来实现初始化。那么既然他们都可以实现初始化操作&#xff0c;那么他们有什…

Ubuntu 开机自启动 .py / .sh 脚本,可通过脚本启动 roslaunch/roscore等

前言 项目中要求上电自启动定位程序&#xff0c;所以摸索了一种 Ubuntu 系统下开机自启动的方法&#xff0c;开机自启动 .sh 脚本&#xff0c;加载 ROS 环境的同时启动 .py 脚本。在 . py 脚本中启动一系列 ROS 节点。 一、 .sh 脚本的编写 #!/bin/bash # gnome-terminal -- …

JetPack03-ViewModel 保证界面数据稳定性

前提 Activity横竖屏切换后&#xff0c;Activity中的数据会丢失。 因为横竖屏切换后&#xff0c;Activity会销毁重建&#xff0c;生命周期会执行onPause->onStop->onDestroy->onCreate->onStart->onReusme。 简介 ViewModel能保证Activity中数据的稳定性&…

【C++】map和set的介绍和使用

1.序列式容器与关联式容器 序列式容器&#xff1a; 底层为线性序列的数据结构&#xff0c; 里面存储的是元素本身 。如vector/list/string/deque/forward_list。 关联式容器&#xff1a; 也是用来存储数据的&#xff0c;于序列式容器不同的是&#xff0c; 里面存储的是<key&…

Python酷库之旅-第三方库Pandas(127)

目录 一、用法精讲 566、pandas.DataFrame.swapaxes方法 566-1、语法 566-2、参数 566-3、功能 566-4、返回值 566-5、说明 566-6、用法 566-6-1、数据准备 566-6-2、代码示例 566-6-3、结果输出 567、pandas.DataFrame.melt方法 567-1、语法 567-2、参数 567-3…

第三十篇——总结:成功的捷径是没有捷径

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 最终的总结&#xff0c;釜底抽薪&#xff0c;又一次如雷贯耳&#xff0c;…

9月26日

1.虚函数与纯虚函数&#xff1a; 在类中定义函数时&#xff0c;在函数前加关键字 virtual &#xff0c;允许在派生类中重写的方法。那么该函数就是虚函数。 纯虚函数&#xff1a;没有实现的方法&#xff0c;用于定义接口。 2.基类为什么需要虚析构函数&#xff1a; 确保删除派生…

找不到MSVCR100.dll怎么办,解决MSVCR100.dll丢失的六种方法

在计算机的日常使用中&#xff0c;我们可能会遇到各种各样的问题&#xff0c;其中之一就是MSVCR100.dll文件丢失。这个文件是Microsoft Visual C 2010的一个组件&#xff0c;如果丢失&#xff0c;可能会导致某些程序无法正常运行。那么&#xff0c;如何解决这个问题呢&#xff…

记一次Windows状态栏不显示问题

文章目录 &#x1fa9f;解决方案☁️单次处理☁️有效处理 &#x1fa9f;现象&#x1fa9f;尝试的操作⭐END&#x1f31f;跋&#x1f31f;交流方式 &#x1fa9f;解决方案 ☁️单次处理 重启explorer.exe 命令行操作 注意&#xff0c;使用命令行操作的时候&#xff0c;出现…

[嵌入式] 3588测试镜头推流拉流步骤

1. RK驱动下载 识别不出来设备&#xff0c;成砖了之后&#xff0c;在插上电源之前&#xff0c;按住boot键&#xff0c;再上电。 2. 在嵌入式设备中&#xff0c;执行命令&#xff0c;rtsp_server rtsp_server -I 1 -d /dev/video22 -w 640 -h 480 推流&#xff0c;用vlc拉流…

linux信号 | 学习信号三步走 | 全解析信号的产生方式

前言&#xff1a;本节内容是信号&#xff0c; 主要讲解的是信号的产生。信号的产生是我们学习信号的第二个阶段。 我们已经学习过第一个阶段——信号的概念与预备知识&#xff08;没有学过的友友可以查看我的前一篇文章&#xff09;。 以及我们还没有学习信号的第三个阶段——信…

【理解 Java 中的 for 循环】

理解 Java 中的 for 循环 for 循环是 Java 中用于迭代的常用控制结构&#xff0c;它可以帮助我们重复执行某段代码&#xff0c;直到满足特定条件。本文将介绍 for 循环的基本语法、执行流程、注意事项及一些练习。 基本语法 for 循环的基本语法如下&#xff1a; for (循环变…

你知道吗?制造手机芯片的关键竟然是一台“打印机”?

在我们每天离不开的智能手机里&#xff0c;藏着一颗小小的“心脏”——芯片。它虽小&#xff0c;却拥有着强大的计算能力&#xff0c;能够让我们随时随地与世界保持连接。你可能想象不到&#xff0c;制造这些精密芯片的关键设备&#xff0c;竟然与我们日常使用的打印机有着惊人…

PD快充是如何诱骗取电的

PD诱骗取电原理&#xff0c;主要指的是在使用USB Power Delivery(USB PD)协议的场景中&#xff0c;通过一种特殊设计的芯片来模拟受电设备&#xff08;如移动设备、充电宝等&#xff09;支持特定功率等级的过程。通常情况下&#xff0c;当一个支持PD协议的充电器连接到设备时…