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

Linux内核idr数据结构使用

Linux 内核的 idr(ID 映射)是一种用于将整数 ID 与指针(内核对象)关联的数据结构,核心功能是高效分配、查找、释放 ID,并通过 ID 快速定位对应的内核对象(如设备、会话、缓冲区等)。以下是其详细用法:

一、核心概念

idr 解决的问题:当需要用唯一整数 ID 标识动态创建的内核对象(如多个网卡实例、进程私有资源)时,idr 可自动分配不重复的 ID,并建立 ID 到对象指针的映射,方便通过 ID 快速访问对象。

二、使用步骤

1. 头文件与数据结构

需包含头文件 <linux/idr.h>,核心结构体为 struct idr

#include <linux/idr.h>struct idr my_idr; // 定义一个 idr 实例
2. 初始化与销毁
  • 初始化:使用 idr_init() 初始化 idr 结构(必须在使用前调用)。
  • 销毁:使用 idr_destroy() 释放资源(需确保所有 ID 已释放)。
// 初始化
idr_init(&my_idr);// 销毁(通常在模块退出时)
idr_destroy(&my_idr);
3. ID 分配(关联对象)

idr 提供多种分配方式,分配时需指定要关联的对象指针:

函数原型功能描述
int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)从 [start, end) 范围内分配最小可用 ID,关联到 ptrstart=0 表示从 0 开始,end=0 表示无上限)。
int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)循环分配 ID(超过 end 后从 start 重新开始),适合需要循环利用 ID 的场景。
  • 参数说明
    • ptr:要关联的内核对象指针(如 struct my_device *)。
    • gfp:内存分配标志(GFP_KERNEL 允许睡眠,GFP_ATOMIC 用于中断上下文)。
    • 返回值:成功返回分配的 ID(非负整数),失败返回负数(-ENOMEM 内存不足,-ENOSPC 无可用 ID)。
4. 通过 ID 查找对象

使用 idr_find() 根据 ID 查找关联的对象指针,支持无锁并发读(依赖 RCU 机制):

void *idr_find(const struct idr *idr, unsigned int id);
  • 返回值:成功返回关联的指针,失败返回 NULL(ID 未分配或已释放)。
5. 释放 ID 与解除关联

使用 idr_remove() 释放指定 ID,并解除与对象的关联(对象需手动释放):

void idr_remove(struct idr *idr, unsigned int id);
6. 迭代所有 ID 与对象

使用 idr_for_each() 遍历所有已分配的 ID 及其关联对象:

int idr_for_each(struct idr *idr, int (*fn)(int id, void *p, void *data), void *data);
  • fn:回调函数,每个 ID 会触发一次调用(id 为当前 ID,p 为关联的指针,data 为用户传入的参数)。
  • 返回值:回调函数返回非 0 时终止遍历,否则返回 0。

三、并发安全处理

idr 内部通过 RCU 和自旋锁保证并发安全:

  • 读操作(idr_find:需在 rcu_read_lock()/rcu_read_unlock() 保护下执行(无锁,高效)。
  • 写操作(分配 / 释放):需通过自旋锁保护(避免并发修改)。
#include <linux/spinlock.h>
#include <linux/rculist.h>static DEFINE_SPINLOCK(idr_lock); // 保护写操作的自旋锁// 分配 ID 并关联对象(带锁)
int alloc_id_and_obj(struct my_obj *obj) {int id;unsigned long flags;spin_lock_irqsave(&idr_lock, flags); // 加锁(禁止中断)id = idr_alloc(&my_idr, obj, 1, 0, GFP_ATOMIC); // 从 ID=1 开始分配spin_unlock_irqrestore(&idr_lock, flags); // 解锁return id;
}// 通过 ID 查找对象(无锁读)
struct my_obj *find_obj_by_id(int id) {struct my_obj *obj;rcu_read_lock(); // 进入 RCU 读临界区obj = idr_find(&my_idr, id);rcu_read_unlock(); // 退出读临界区return obj;
}// 释放 ID 与对象(带锁)
void free_id_and_obj(int id) {struct my_obj *obj;unsigned long flags;spin_lock_irqsave(&idr_lock, flags);obj = idr_find(&my_idr, id); // 先查找对象if (obj) {idr_remove(&my_idr, id); // 释放 IDkfree(obj); // 手动释放对象(idr 不管理对象内存)}spin_unlock_irqrestore(&idr_lock, flags);
}

四、完整示例(模块中使用)

#include <linux/module.h>
#include <linux/idr.h>
#include <linux/spinlock.h>
#include <linux/slab.h>// 定义需要用 ID 标识的对象
struct my_obj {int value;
};static struct idr my_idr;
static DEFINE_SPINLOCK(idr_lock);// 遍历回调函数:打印 ID 和对象值
static int print_id_obj(int id, void *p, void *data) {struct my_obj *obj = p;printk("ID: %d, value: %d\n", id, obj->value);return 0; // 继续遍历
}static int __init idr_demo_init(void) {int id1, id2;struct my_obj *obj1, *obj2;// 初始化 IDRidr_init(&my_idr);// 创建对象obj1 = kzalloc(sizeof(*obj1), GFP_KERNEL);obj2 = kzalloc(sizeof(*obj2), GFP_KERNEL);if (!obj1 || !obj2)return -ENOMEM;obj1->value = 100;obj2->value = 200;// 分配 ID 并关联对象spin_lock_irq(&idr_lock);id1 = idr_alloc(&my_idr, obj1, 1, 0, GFP_ATOMIC);id2 = idr_alloc(&my_idr, obj2, 1, 0, GFP_ATOMIC);spin_unlock_irq(&idr_lock);printk("Allocated IDs: %d, %d\n", id1, id2);// 遍历所有 ID 和对象idr_for_each(&my_idr, print_id_obj, NULL);return 0;
}static void __exit idr_demo_exit(void) {// 释放 ID 和对象(简化示例,实际需保存 id1、id2)spin_lock_irq(&idr_lock);idr_remove(&my_idr, id1);idr_remove(&my_idr, id2);kfree(idr_find(&my_idr, id1)); // 假设退出前仍能找到对象kfree(idr_find(&my_idr, id2));spin_unlock_irq(&idr_lock);// 销毁 IDRidr_destroy(&my_idr);printk("IDR demo exited\n");
}module_init(idr_demo_init);
module_exit(idr_demo_exit);
MODULE_LICENSE("GPL");

http://www.dtcms.com/a/500023.html

相关文章:

  • 3.3栈与队列的应用
  • 黑龙江网站开发公司宁波网站建设制作的公司
  • 《CopyOnWriteArrayList / CopyOnWriteArraySet 源码与“大对象复制”事故实录》
  • 做网站的品牌公司有哪些安康市110报警平台
  • 三水住房和城乡建设局的网站一键生成logo免费图
  • 自用EUBIU
  • 省住房城乡建设厅网站保险查询平台
  • 智能PDU在数据中心场景中的应用与解决方案
  • 网站登录界面图片用什么软件做深圳关键词优化报价
  • 中信建设证券官方网站佛山网页设计怎么做
  • Tomcat 类加载器隔离机制的实际应用
  • 咨询网站 模板国泰君安官方网站建设集团
  • Go基础知识(一)
  • 网站开发c外贸企业邮箱哪个好用
  • 鸿蒙Next振动开发指南:打造沉浸式触觉反馈体验
  • 网站美工外包公司改号宝网站搭建
  • h5游戏免费下载:滑雪大挑战
  • 高端制作网站哪家专业湖北建设工程注册中心网站
  • 包管理 pip ,conda;pycharm中使用conda 创建的虚拟环境
  • wordpress 域名使用网站内容优化细节
  • K8s Ingress 详解与部署实战
  • 一般网站开发的硬件要求使用flash做网站
  • 制作网站开发wordpress彻底禁用google
  • tauri + rust的环境搭建---初始化以及构建
  • 哪个网站可以做制图兼职嘉兴企业网站制作
  • 3.2队列
  • Particles Color and Depth Textures
  • 关键词搜不到我的网站竞价排名点击
  • Kolmogorov-Smirnov检验:从理论到实践的全解读
  • 怎么用wordpress建电商网站吗wordpress钩子函数