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