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

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); // 初始化 klist
    int 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.kler.cn/a/326167.html

相关文章:

  • 通过shell脚本分析部署nginx网络服务
  • 设计模式-Adapter(适配器模式)GO语言版本
  • DHTMLX-gantt组件显示不同的颜色
  • SpringBoot总结
  • shell 100例
  • workerman的安装与使用
  • YOLOv11改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制
  • L2-004 这是二叉搜索树吗?
  • C++中vector类的使用
  • Google Tag Manager - 服务器端代码植入
  • Python与SQL Server数据库结合导出Excel并做部分修改
  • ElasticSearch安装分词器与整合SpringBoot
  • 【制作自解压程序】使用7Z制作自解压程序
  • OceanBase技术解析:自适应分布式下压技术
  • 【软件整理资料】软件项目配套资料,项目计划书(word)
  • IDEA使用技巧和插件推荐
  • 爬虫及数据可视化——运用Hadoop和MongoDB数据进行分析
  • js中的深拷贝与浅拷贝 手写深拷贝代码
  • 深入剖析 Android Lifecycle:构建高效稳定的应用
  • 如何设计能吸引下载的截图以及注意事项
  • SpringBoot助力墙绘艺术市场创新
  • golang学习笔记16-数组
  • java 解析excel (本地资源)
  • Android常用C++特性之std::find_if
  • CF1619D.New Year‘s Problem
  • 解决 TypeError: Expected state_dict to be dict-like, , got <class ‘*‘>.