淺析linux內核中的idr機制

来源:http://www.cnblogs.com/roucheng/archive/2016/06/23/linuxidr.html
-Advertisement-
Play Games

idr在linux內核中指的就是整數ID管理機制,從本質上來說,這就是一種將整數ID號和特定指針關聯在一起的機制。這個機制最早是在2003年2月加入內核的,當時是作為POSIX定時器的一個補丁。現在,在內核的很多地方都可以找到idr的身影。 idr機制適用在那些需要把某個整數和特定指針關聯在一起的地 ...


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);   推薦:http://www.cnblogs.com/roucheng/p/3470287.html
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ZIP壓縮包文件中允許存在“../”的字元串,攻擊者可通過精心構造ZIP文件,利用多個“../”從而改變ZIP包中某個文件的存放位置,覆蓋替換掉應用原有的文件。 ...
  • 8.Vsync 8.1概論 VSYNC(Vertical Synchronization)是一個相當古老的概念,對於游戲玩家,它有一個更加大名鼎鼎的中文名字—-垂直同步。 “垂直同步(vsync)”指的是顯卡的輸出幀數和屏幕的垂直刷新率相同,這完全是一個CRT顯示器上的概念。其實無論是VSYNC還是 ...
  • 打開Android Studio,依次【File】-【Settings】 在打開的settings界面里找到plugins設置項,點擊右側的“Browser。。”按鈕 在搜索欄里輸入genymotion關鍵字,可以看到右側已經搜索到插件,點擊install安裝。 開始下載,速度很快。安裝後重新啟動A ...
  • 大家好,本人是高三剛畢業,即將踏入校園的程式猿~我寫這篇文章呢,主要是想鞏固一下之前對於電腦的基礎知識理論,也希望能幫助沒有電腦基礎的同學能維護一下自己的電腦,要是能幫助女生修電腦那就是更好啦~~哈哈哈,話不多說,直接進入主題~!!(本教程出現的鏈接大家可以複製到網頁地址欄進入) 本教程總共分為: ...
  • WOL(從網卡喚醒)諸多限制,內網都不穩定,外網更不用說,放棄 斷電恢覆上次狀態,必須的 通電即開機,必須的 WIFI智能開關一個 受管理的伺服器 Esxi 6 2台,windows 2012 2台 統一使用WIFI開關,esxi6設置SSH自啟動,設置VM隨主機開關機,HYPERV設置VM自啟動 ... ...
  • ld --verbose | grep SEARCH ...
  • 如何保護你的linux操作系統 如何保護你的linux操作系統 導讀 在現在這個世道中,Linux操作系統的安全是十分重要的。但是,你得知道怎麼乾。一個簡單反惡意程式軟體是遠遠不夠的,你需要採取其它措施來協同工作。那麼試試下麵這些手段吧。 使用SELinux SELinux是用來對Linux進行安全 ...
  • Background Today I did stupid things that I went into the ~/Downloads/ and pressed [Alt] + [A] then [Shift] + [Delete]. Wtf... I didn't want to delete ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...