博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅析linux内核中的idr机制
阅读量:4051 次
发布时间:2019-05-25

本文共 3123 字,大约阅读时间需要 10 分钟。

原文:http://blogold.chinaunix.net/u3/93926/showart_1874142.html
尚观科技原创文章
浅析linux内核中的idr机制 
 
 
尚观讲师原创文章
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;
};
(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) {
 
 
 
 
}
 
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机制的实际应用:
...
 
 
...
static DEFINE_IDR(i2c_adapter_idr);
...
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);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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);
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);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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);
int i2c_del_adapter(struct i2c_adapter *adap)
{
 
...
 
 
idr_remove(&i2c_adapter_idr, adap->nr);
 
...
 
return res;
}
EXPORT_SYMBOL(i2c_del_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);

转载地址:http://pyvci.baihongyu.com/

你可能感兴趣的文章
简单理解Socket及TCP/IP、Http、Socket的区别
查看>>
利用HTTP Cache来优化网站
查看>>
利用负载均衡优化和加速HTTP应用
查看>>
消息队列设计精要
查看>>
分布式缓存负载均衡负载均衡的缓存处理:虚拟节点对一致性hash的改进
查看>>
分布式存储系统设计(1)—— 系统架构
查看>>
MySQL数据库的高可用方案总结
查看>>
常用排序算法总结(一) 比较算法总结
查看>>
SSH原理与运用
查看>>
SIGN UP BEC2
查看>>
S3C2440中对LED驱动电路的理解
查看>>
《天亮了》韩红
查看>>
Windows CE下USB摄像头驱动开发(以OV511为例,附带全部源代码以及讲解) [转]
查看>>
出现( linker command failed with exit code 1)错误总结
查看>>
iOS开发中一些常见的并行处理
查看>>
iOS获取手机的Mac地址
查看>>
ios7.1发布企业证书测试包的问题
查看>>
如何自定义iOS中的控件
查看>>
iOS 开发百问
查看>>
Mac环境下svn的使用
查看>>