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

相关推荐
橘子真甜~12 分钟前
Linux基础4-进程2(Linux中的进程状态,R,S,D,T,t,Z,X,僵尸进程,孤儿进程)
linux·运维·服务器·孤儿进程·进程状态·僵尸状态
燕雀安知鸿鹄之志哉.17 分钟前
玄机:第五章 linux实战-挖矿
linux·运维·服务器·网络·安全·web安全·网络安全
秦jh_39 分钟前
【Linux】进程替换
linux·运维·服务器
职场人参1 小时前
怎么将太大的pdf文件压缩变小?超详细的10种压缩方法介绍!
linux·网络
弥琉撒到我2 小时前
linux系统的常用命令
linux·运维·服务器
fasewer2 小时前
第五章 linux实战-黑链
linux·运维·服务器
大侠之运维3 小时前
安全常用的kali linux是怎样的,如何安装?
linux·安全·web安全
StevenZeng学堂3 小时前
【Kubernetes知识点】 解读 Service 和 EndpointSlice 之间的关系
linux·云原生·容器·kubernetes·云计算·go
小码哥呀3 小时前
CentOS修改主机名
linux·运维·centos