浅析linux内核中的idr机制

idr在linux内核中指的就是整数ID管理机制,从本质上来说,这就是一种将整数ID号和特定指针关联在一起的机制。这个机制最早是在2003年2月加入内核的,当时是作为POSIX定时器的一个补丁。现在,

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

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

(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;
  }/* 何问起 hovertree.com */

(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);
 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120299.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • COM聚合技术中的QueryInterface

    COM聚合技术中的QueryInterface最近在看COM聚合技术时遇到一个关于QueryInterface的问题。在《COM技术内幕》和《COM原理与应用》中都是寥寥数句带过,看起来很易理解,我却看了许久才有所领悟。先说明一下,为了节省篇幅,对于一些约定俗成的代码和变量,下文不再进行说明,如内部组件指向外部组件的m_pUnknownOuter和外部组件指向内部组件的m_pUnknownInner等,这些内容在相关书籍都有描述。问题

  • 知识管理工具有哪些_效率管理app

    知识管理工具有哪些_效率管理app转载自:http://xbeta.info/pkm2.htmPKM2:优秀的个人知识管理工具目录:1.前言2.推荐PKM2的6条理由3.不足4.官方介绍附:作者留言1.前言一直想把PKM2

  • 一维卷积神经网络处理序列模型

    一维卷积神经网络处理序列模型fromkeras.datasetsimportimdbfromkeras.modelsimportSequentialfromkeras.layersimportEmbedding,Conv1D,MaxPooling1D,GlobalMaxPooling1D,Densefromkeras.optimizersimportRMSpropmax_featu…

  • Layui二级菜单优化

    Layui二级菜单优化刚开始学习layui框架,碰到一个缺陷是二级菜单每次点击都会收缩到原始状态。用 Request.Url.ToString();获取URL判断点击页面前哪些节点是展开的,添加class=\"layui-nav-itemlayui-nav-itemed\"&gt;(展开子节点)解决了。代码如下:for(vari=0;i&lt;data.length;i++){…

  • 手把手教你制作一个简单的聊天机器人(图灵api)「建议收藏」

    手把手教你制作一个简单的聊天机器人(图灵api)「建议收藏」前言:在无聊的时候打打游戏、听听歌还不如来找个人来陪你聊天,今天来教大家制作一个聊天机器人,这样就不会无聊了,在线聊天机器人地址借愁哥哥机器人(可能有点丑,大家将就一下(????))这个接口就目前的一天100次聊天机会,大家要珍惜哦,源码在文章末尾哦!效果图:目录:一.准备工作二.项目开始1.页面布局:2.样式层:3.逻辑实现:一.准备工作通过分析我们需要以下的具体准备:对于界面的分析,我们需要用到的插件:jQuery,我们采用的是flex弹性布局,既然使用的是图灵机器人

  • FFmepg_ffmpeg下载

    FFmepg_ffmpeg下载FFMpeg0.6版源码下载:来自:http://sourceforge.net/projects/mplayer-win32/files/FFmpeg/FFmpeg-svn-24623.7zffmpeg-r24623.tar.bz2我收集到的相关开发资料:(均来自网络) FFMpeg中apiexample_c例子分析——解码分析.txtffmpeg初级教程.rarff

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号