linux 內核 hash table 的使用

The kernel (as of 2.6.38) does not include a generic hash table implementation, but does include some pieces:

  • hlist_*/HLIST_* in list.h are single-pointer-head doubly-linked list structs and macros useful for hash buckets. (answer below from adobriyan)
  • hash.h includes hashing routines for ints, longs, and pointers. This article by Chuck Lever studies the performance of these routines.
  • See pid_hash in pid.c for an example constructed from these primitives.

uthash is a generic hash table for C implemented as macros defined in a single header file. This solution may be appropriate for many third-party kernel modules (e.g., device drivers). However, reliance on uthash might impede mainlining of a module. 

 
很早以前就想學習一下如何使用linux內核中的散列函數。google了幾次,發現
網上有大量介紹有關hlist的東西。可找來找去也找不到究竟該如何使用散列。
原來,我先入爲主的認爲內核中的散列函數會像那些高級語言中實現的散列功能
類似:我提供一對對的(key value)給內核,然後再調用某一個api,傳給它一個
key,就可以得到對應的value。

後來參考了一些內核中應用散列的實例才發現,原來根本不是這麼回事。實際
上,對於如何將輸入數據散列到一個指定範圍的算法,需要使用散列的人自己決
定。內核只提供了一個發射碰撞時把碰撞的項鍊接到一起的hlist結構。

例如,你創建了一個長度爲m的散列表,並且已經選擇了一個將輸入數據映射到
範圍0 ~ m-1的散列函數。接下來,你就要在這個長度爲m的散列表的每個表項內
放上一個hlist_head結構體。然後在每個輸入數據的結構體中定義一個
hlist_node的結構體。每當把一個輸入通過散列函數映射到0 ~ m-1的範圍內時,就
把這個輸入的hlist_node掛到散列表對應的槽的hlist_head上面。當給定一個
key,想獲取它的value的時候,就先用散列函數算出這個key對應的槽的位置,
然後遍歷這個槽的hlist_node鏈表,找到與key相等的項。把它的value返回。

例如,有這樣一個數組:
0x01, 0x02, 0x04, 0x08,0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8,
0xcd, 0x87, 0x13,
其中每個元素對應的索引號爲:
1, 2, 3, 4, 5, ... 15
也就是說,當輸入0x01時,我希望得到索引號1,當輸入0x08時,得到4,當輸入
0x3a時,得到10...
這種從數值到索引號的轉換,可通過散列來實現。

下面是實現該功能的一個內核代碼,散列函數我選擇的是:
value = ((104 * key + 52) % 233) % 15
(實際上,對於輸入固定的情況,使用完全散列可以獲得完全固定的訪問時間,
上面這個散列函數就是我想使用完全散列時搜索一個全域散列族得到的第一級散
列函數,但我發先這個散列函數已經足夠好,總共才只有一次碰撞。所以就沒有
必要像完全散列那樣使用二級散列了。)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>

struct q_coef
{
    u8 coef;
    u8 index;
    struct hlist_node hash;
};

#define HASH_NUMBER 15
u8 coef[HASH_NUMBER] = {
    0x01, 0x02, 0x04, 0x08,0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13,
};
struct q_coef q_coef_list[HASH_NUMBER];

struct hlist_head hashtbl[HASH_NUMBER];

static inline int hash_func(u8 k)
{
    int a, b, p, m;
    a = 104;
    b = 52;
    p = 233;
    m = HASH_NUMBER;
    return ((a * k + b) % p) % m;
}

static void hash_init(void)
{
    int i, j;
    for (i = 0 ; i < HASH_NUMBER ; i++) {
        INIT_HLIST_HEAD(&hashtbl[i]);
        INIT_HLIST_NODE(&q_coef_list[i].hash);
        q_coef_list[i].coef = coef[i];
        q_coef_list[i].index = i + 1;
    }
    for (i = 0 ; i < HASH_NUMBER ; i++) {
        j = hash_func(q_coef_list[i].coef);
        hlist_add_head(&q_coef_list[i].hash, &hashtbl[j]);
    }
}

static void hash_test(void)
{
    int i, j;
    struct q_coef *q;
    struct hlist_node *hn;
    for (i = 0 ; i < HASH_NUMBER ; i++) {
        j = hash_func(coef[i]);
        hlist_for_each_entry(q, hn, &hashtbl[j], hash)
            if (q->coef == coef[i])
                printk("found: coef=0x%02x index=%d\n", q->coef, q->index);
    }
}
static int htest_init (void)
{
    hash_init();
    hash_test();
    return -1;
}

static void htest_exit (void)
{
}

module_init(htest_init);
module_exit(htest_exit);

MODULE_LICENSE("Dual BSD/GPL");
 
 來自http://yupeng0921.blogspot.com/2010/10/linux-hash-table.html?showComment=1350877062473#c3513363701255844366

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章