[转]浅析linux内核中的idr机制

这里idr是否是ID RADIX缩写,就是说将ID组织到了一棵RADIX树中. idr在linux内核中指的就是整数ID管理机制,从本质上来说,这就是一种将整数ID号和特定指针关联在一起的机制。这个机制最早是在2003年2月加入内核的,当时是作为POSIX定时器的一个补丁。现在,在内核的很多地方都可以找到idr的身影。idr机制适用在那些需要把某个整数和特定指针关联在一起的地方。举个例子,在I2C总线中,每个设备都有自己的地址,要想在总线上找到特定的设备,就必须要先发送该设备的地址。如果我们的PC是一个I2C总线上的主节点,那么要访问总线上的其他设备,首先要知道他们的ID号,同时要在pc的驱动程序中建立一个用于描述该设备的结构体。此时,问题来了,我们怎么才能将这个设备的ID号和他的设备结构体联系起来呢?最简单的方法当然是通过数组进行索引,但如果ID号的范围很大(比如32位的ID号),则用数组索引显然不可能;第二种方法是用链表,但如果网络中实际存在的设备较多,则链表的查询效率会很低。遇到这种清况,我们就可以采用idr机制,该机制内部采用radix树实现,可以很方便地将整数和指针关联起来,并且具有很高的搜索效率。(1)获得idr要在代码中使用idr,首先要包括。接下来,我们要在代码中分配idr结构体,并初始化:void idr_init(struct idr *idp);其中idr定义如下:struct idr { struct idr_layer *top; struct idr_layer *id_free; int layers; int id_free_cnt; spinlock_t lock;};/* idr是idr机制的核心结构体 */(2)为idr分配内存int idr_pre_get(struct idr *idp, unsigned int gfp_mask);每次通过idr获得ID号之前,需要先分配内存。返回0表示错误,非零值代表正常(3)分配ID号并将ID号和指针关联int idr_get_new(struct idr *idp, void *ptr, int *id);int idr_get_new_above(struct idr *idp, void *ptr, int start_id, int *id);idp: 之前通过idr_init初始化的idr指针id: 由内核自动分配的ID号ptr: 和ID号相关联的指针start_id: 起始ID号。内核在分配ID号时,会从start_id开始。如果为I2C节点分配ID号,可以将设备地址作为start_id函数调用正常返回0,如果没有ID可以分配,则返回-ENOSPC在实际中,上述函数常常采用如下方式使用:again: if (idr_pre_get(&my_idr, GFP_KERNEL) == 0) {/* No memory, give up entirely */ } spin_lock(&my_lock); result = idr_get_new(&my_idr, &target, &id); if (result == -EAGAIN) {sigh();spin_unlock(&my_lock);goto again; }(4)通过ID号搜索对应的指针void *idr_find(struct idr *idp, int id);返回值是和给定id相关联的指针,如果没有,则返回NULL(5)删除ID要删除一个ID,使用:void idr_remove(struct idr *idp, int id);通过上面这些方法,内核代码可以为子设备,inode生成对应的ID号。这些函数都定义在中下面,我们通过分析I2C协议的核心代码,来看一看idr机制的实际应用:... /* idr头文件 */...static DEFINE_IDR(i2c_adapter_idr); /* 声明idr */.../* 采用动态总线号声明并注册一个i2c适配器(adapter),可睡眠 针对总线号可动态指定的设备,如基于USB的i2c设备或pci卡*/int i2c_add_adapter(struct i2c_adapter *adapter){ int id, res = 0;retry: if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) return -ENOMEM; mutex_lock(&core_lists); /* __i2c_first_dynamic_bus_num是当前系统允许的动态总线号的最大值 */ res = idr_get_new_above(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, &id); mutex_unlock(&core_lists); if (res < 0) { if (res == -EAGAIN) goto retry; return res; } adapter->nr = id; return i2c_register_adapter(adapter);}EXPORT_SYMBOL(i2c_add_adapter);/* 采用静态总线号声明并注册一个i2c适配器(adapter)*/int i2c_add_numbered_adapter(struct i2c_adapter *adap){ int id; int status; if (adap->nr & ~MAX_ID_MASK) return -EINVAL;retry: if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) return -ENOMEM; mutex_lock(&core_lists); /* "above" here means "above or equal to", sigh; * we need the "equal to" result to force the result */ status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id); if (status == 0 && id != adap->nr) { status = -EBUSY; idr_remove(&i2c_adapter_idr, id); } mutex_unlock(&core_lists); if (status == -EAGAIN) goto retry; if (status == 0) status = i2c_register_adapter(adap); return status;}EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);/* 注销一个i2c适配器 */int i2c_del_adapter(struct i2c_adapter *adap){ ... /* free bus id */ idr_remove(&i2c_adapter_idr, adap->nr); ... return res;}EXPORT_SYMBOL(i2c_del_adapter);/* 通过ID号获得i2c_adapter设备结构体 */struct i2c_adapter* i2c_get_adapter(int id){ struct i2c_adapter *adapter; mutex_lock(&core_lists); adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; mutex_unlock(&core_lists); return adapter;}EXPORT_SYMBOL(i2c_get_adapter);
利用 TensorFlow 训练自己的目标识别器。本文内容来自于我的毕业设计,基于 TensorFlow 1.15.0,其他 TensorFlow 版本运行可能存在问题。.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计,皆可应用在项目、毕业设计、课程设计、期末/期/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值