linux内核双向链表使用list 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

代码如下(示例):

c 复制代码
#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

代码如下(示例):

多线程暂不完善仅供参考

c 复制代码
#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和测试代码,仅供参考

相关推荐
leoufung1 小时前
vim 多个关键字高亮插件介绍
linux·编辑器·vim
Nerd Nirvana4 小时前
软考—系统架构设计(案例 | 论文)
linux·系统架构·软件工程·软考·计算机基础
勤奋的凯尔森同学5 小时前
webmin配置终端显示样式,模仿UbuntuDesktop终端
linux·运维·服务器·ubuntu·webmin
打不了嗝 ᥬ᭄10 小时前
Linux的权限
linux
落幕10 小时前
C语言-进程
linux·运维·服务器
深度Linux10 小时前
C++程序员内功修炼——Linux C/C++编程技术汇总
linux·项目实战·c/c++
风静如云12 小时前
OpenBMC:BmcWeb定义service
linux
leoufung12 小时前
VIM FZF 安裝和使用
linux·编辑器·vim
liuyuzhongcc12 小时前
List 接口中的 sort 和 forEach 方法
java·数据结构·python·list
bugtraq202113 小时前
XiaoMi Mi5(gemini) 刷入Ubuntu Touch 16.04——安卓手机刷入Linux
linux·运维·ubuntu