idr在linux内核中指的就是整数ID管理机制,从本质上来说,这就是一种将整数ID号和特定指针关联在一起的机制。这个机制最早是在2003年2月加入内核的,当时是作为POSIX定时器的一个补丁。现在,在内核的很多地方都可以找到idr的身影。
       idr机制适用在那些需要把某个整数和特定指针关联在一起的地方。举个例子,在I2C总线中,每个设备都有自己的地址,要想在总线上找到特定的设备,就必须要先发送该设备的地址。如果我们的PC是一个I2C总线上的主节点,那么要访问总线上的其他设备,首先要知道他们的ID号,同时要在pc的驱动程序中建立一个用于描述该设备的结构体。
      此时,问题来了,我们怎么才能将这个设备的ID号和他的设备结构体联系起来呢?最简单的方法当然是通过数组进行索引,但如果ID号的范围很大(比如32位的ID号),则用数组索引显然不可能;第二种方法是用链表,但如果网络中实际存在的设备较多,则链表的查询效率会很低。遇到这种清况,我们就可以采用idr机制,该机制内部采用radix树实现,可以很方便地将整数和指针关联起来,并且具有很高的搜索效率。
(1)获得idr
要在代码中使用idr,首先要包括<linux/idr.h>。接下来,我们要在代码中分配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号。这些函数都定义在<linux-2.6.xx/lib/idr.c>中

下面,我们通过分析I2C协议的核心代码,来看一看idr机制的实际应用:
<linux-2.6.23/drivers/i2c/i2c-core.c>
...
<linux/idr.h>   /* 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);

浅析linux内核中的idr机制相关推荐

  1. Linux内核中的platform机制

    Linux内核中的platform机制 从Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver.Linux中大部分的设备驱动,都可以使用 ...

  2. linux内核定时器死机,浅析linux内核中timer定时器的生成和sofirq软中断调用流程

    浅析linux内核中timer定时器的生成和sofirq软中断调用流程 mod_timer添加的定时器timer在内核的软中断中发生调用,__run_timers会spin_lock_irq(& ...

  3. linux 信号优先级,linux内核中的信号机制

    linux内核中的信号机制--信号处理 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csdn.net ...

  4. Linux内核中的RCU机制

    http://blog.chinaunix.net/uid-23769728-id-3080134.html RCU的设计思想比较明确,通过新老指针替换的方式来实现免锁方式的共享保护.但是具体到代码的 ...

  5. 深入理解 Linux 内核中的 RCU 机制

    RCU(Read-Copy Update),是 Linux 中比较重要的一种同步机制.顾名思义就是"读,拷贝更新",再直白点是"随意读,但更新数据的时候,需要先复制一份副 ...

  6. linux做预警机制,预警通告:Linux内核中TCP SACK机制远程DoS

    漏洞描述 2019年6月18日,RedHat官网发布报告:安全研究人员在Linux内核处理TCP SACK数据包模块中发现了三个漏洞,CVE编号为CVE-2019-11477.CVE-2019-114 ...

  7. linux通过信号回调函数,信号机制的管理结构 - Linux内核中的信号机制_Linux编程_Linux公社-Linux系统门户网站...

    信号只是一个数字,数字为0-31表示不同的信号,如下表所示. 编号 信号名 默认动作 说明 1 SIGHUP 进程终止 终端断开连接 2 SIGINT 进程终止 用户在键盘上按下CTRL+C 3 SI ...

  8. linux内核层是什么,从用户层到内核层 - Linux内核中的信号机制_Linux编程_Linux公社-Linux系统门户网站...

    1.简介 如果进程要处理某一信号,那么要在进程中注册该信号.注册信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个进程和该信号被传递给进程时,将执行何种操作.主要有两个函 ...

  9. Linux内核中的同步原语:自旋锁,信号量,互斥锁,读写信号量,顺序锁

    Linux内核中的同步原语 自旋锁,信号量,互斥锁,读写信号量,顺序锁 rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. Linux 内核中的同步原 ...

最新文章

  1. python3 命令行参数处理库 argparse、docopt、click、fire 简介
  2. 对计算机应用的认识100,计算机应用基础
  3. springboot 切换日志实现
  4. assert()函数
  5. linux uvc支持H264格式
  6. Android笔记 对话框demo大全
  7. 前人栽树,后人擦屁股
  8. Objective-C的对象模型
  9. Linux内核多线程——补充(各种平台下的多线程)
  10. LAMMPS分子动力学模拟技术及应用
  11. DSP(数字信号处理器)技术概要
  12. AI和人工智能入门级视频
  13. XML文档类型定义---XML Schema结构
  14. 佰落暑期java自学记录-11
  15. 华为交换机配置syslog发送_华为交换机的 syslog功能
  16. 如何制作出漂亮精致的思维导图?MindNow来帮你
  17. 【低碳发展案例研究】中国西部中小城市低碳发展研究——以泸州市为例
  18. Linux树莓派实战案例论文,树莓派|树莓派使用实例之:2 Pi R
  19. 记一次从某多多上买的斐讯N1黑盒的电视盒子刷机经历
  20. 【长按图片识别】uniapp vue开发时,点击图片识别—实现转发、收藏、识别图片二维码

热门文章

  1. 添加面部跟踪和实时识别到您的Android应用程序
  2. 团队开发冲刺第二阶段_4
  3. php 发送邮件乱码
  4. Html内容超出标记宽度后自动隐藏
  5. CMS:文章管理之模型和Store
  6. sqlite 实例教程 IOS下用sqlite打造词典
  7. 游戏的革命从虚拟现实开始
  8. Neutron 物理部署方案 - 每天5分钟玩转 OpenStack(68)
  9. TCP的三次握手,四次断开
  10. centso7 install Mariadb