gpt4 book ai didi

c - 如何使用内核哈希表 API?

转载 作者:行者123 更新时间:2023-12-03 16:11:34 26 4
gpt4 key购买 nike

我正在尝试理解和使用 kernel hash tables我已经阅读了thisthis链接,但我一个都没看懂。我的第一个问题是:为什么我们的结构必须有 struct h_list在里面?如果我们要通过 struct h_list 访问我们的结构我们的结构不应该在 struct h_list 内而不是相反?阅读教程后,我尝试编写以下代码:

DECLARE_HASHTABLE(nodes_hash, 3)

hash_init(nodes_hash);

struct h_node{
int data;
char name[MAX_NAME_SIZE]; /*The key is the name of lua state*/
struct hlist_node node;
};

struct h_node a = {
.data = 3,
.name = "foo",
.node = 0
};

struct h_node b = {
.data = 7,
.name = "bar",
.node = 0
};

hash_add(nodes_hash,&a.node, "foo");
hash_add(nodes_hash,&b.node, "bar");

但这甚至无法编译。我做错了什么?我需要 key 与 struct h_node 中存在的名称相同.所以我希望我的哈希表是这样的:

enter image description here

PS:在我的哈希表中它永远不会发生冲突(我会处理它永远不会发生)所以键可以是 struct h_node 中的名称

最佳答案

Why our struct has to have the struct h_list inside it? If we're gonna access our struct through the struct h_list our struct shouldn't be within struct h_list and not the opposite?


那是因为哈希表是如何在 Linux 内核中实现的。哈希表只是 struct hlist_head 的固定大小的数组。 .每一个都代表一个桶,并且是链表的头部。哈希表只包含 struct hlist_node 的一堆链表。 , 没有其他的。它并没有真正“存储”整个用户定义的结构,它只是保存一个指向 struct hlist_node 的指针。每个元素的字段。
当您将元素添加到哈希表时,将选择一个存储桶,并指向 struct hlist_node 的指针。您的结构的字段被插入到存储桶列表中。当您稍后检索元素时(例如通过 hash_for_each() ), container_of()宏用于获取你的真实结构,知道它的类型和类型 struct hlist_node 的结构成员的名称在您的用户定义结构中。
这可以在源代码之后看到。例如,对于 hash_for_each()我们有:
  • hash_for_each(name, bkt, obj, member) 做:
     for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
    (bkt)++)\
    hlist_for_each_entry(obj, &name[bkt], member)
  • hlist_for_each_entry() 做:
     for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
    pos; \
    pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
  • hlist_entry_safe() 做:
     ({ typeof(ptr) ____ptr = (ptr); \
    ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
    })
  • 最后 hlist_entry() 使用 container_of()获得真正的结构:
     #define hlist_entry(ptr, type, member) container_of(ptr,type,member)

  • I need that the key be the same name present in the struct h_node.


    这在本地是不可能的。 Linux 内核哈希表 API 仅处理整数键。如果你看一下 linux/hashtable.h 中的实现,可以看到使用的哈希函数是 hash_32() hash_64() ,并且它们都采用无符号整数值(分别为 u32u64)。
    Linux 内核哈希表 API 非常有限,它绝对不会实现您在其他编程语言中使用的那种哈希表。它不能使用字符串作为键,并且它具有固定的大小。
    如果要使用字符串,则必须对这些字符串进行散列以生成无符号整数。为此,您可以使用 xxhash() 或编写自己的函数。 xxhash()函数相对较新,似乎还没有在内核代码中使用,所以我认为你的内核很可能是在没有它的情况下配置的,而你没有它可用。
    在任何情况下,请注意如果散列函数将不同的字符串转换为相同的键,或者如果 hash_add()最终在哈希表数组中选择相同的索引来插入元素,那么这两个元素将被放置在同一个哈希表桶中。因此,在检索任何元素时(例如使用 hash_for_each_possible() ),您需要考虑到这一点并正确检查其 name .
    工作示例
    这是一个完整的工作示例,用于演示内核哈希表的基本用法,在内核 v4.9 上进行了测试,但也应该在最新的 v5.7 上工作。请注意,在本例中,我在模块 _init 的堆栈上分配变量。功能只是为了简单。这意味着我不能做 hash_for_each_possible()从代码中的其他任何地方,除了从该函数内部。如果你想要一个全局哈希表能够保存稍后被不同函数访问的元素,你需要使用 kmalloc() 动态分配它们。 .
    // SPDX-License-Identifier: GPL-3.0
    #include <linux/hashtable.h> // hashtable API
    #include <linux/module.h> // module_{init,exit}, MODULE_*
    #include <linux/string.h> // strcpy, strcmp
    #include <linux/types.h> // u32 etc.

    #define MAX 32

    struct h_node {
    int data;
    char name[MAX];
    struct hlist_node node;
    };

    DECLARE_HASHTABLE(tbl, 3);

    // Just to demonstrate the behavior when two keys are equal.
    static u32 myhash(const char *s) {
    u32 key = 0;
    char c;

    while ((c = *s++))
    key += c;

    return key;
    }

    static int __init myhashtable_init(void)
    {
    struct h_node a, b, *cur;
    u32 key_a, key_b;
    unsigned bkt;

    pr_info("myhashtable: module loaded\n");

    a.data = 3;
    strcpy(a.name, "foo");

    b.data = 7;
    strcpy(b.name, "oof");

    /* Calculate key for each element.
    * Since the above hash function only sums the characters, we will
    * end up having two identical keys here.
    */
    key_a = myhash(a.name);
    key_b = myhash(b.name);

    pr_info("myhashtable: key_a = %u, key_b = %u\n", key_a, key_b);

    // Initialize the hashtable.
    hash_init(tbl);

    // Insert the elements.
    hash_add(tbl, &a.node, key_a);
    hash_add(tbl, &b.node, key_b);

    // List all elements in the table.
    hash_for_each(tbl, bkt, cur, node) {
    pr_info("myhashtable: element: data = %d, name = %s\n",
    cur->data, cur->name);
    }

    // Get the element with name = "foo".
    hash_for_each_possible(tbl, cur, node, key_a) {
    pr_info("myhashtable: match for key %u: data = %d, name = %s\n",
    key_a, cur->data, cur->name);

    // Check the name.
    if (!strcmp(cur->name, "foo")) {
    pr_info("myhashtable: element named \"foo\" found!\n");
    break;
    }
    }

    // Remove elements.
    hash_del(&a.node);
    hash_del(&b.node);

    return 0;
    }

    static void __exit myhashtable_exit(void)
    {
    // Do nothing (needed to be able to unload the module).
    pr_info("myhashtable: module unloaded\n");
    }


    module_init(myhashtable_init);
    module_exit(myhashtable_exit);
    MODULE_VERSION("0.1");
    MODULE_DESCRIPTION("Silly kernel hashtable API example module.");
    MODULE_AUTHOR("Marco Bonelli");
    MODULE_LICENSE("GPL");
    dmesg我机器上的输出:
    [ 3174.567029] myhashtable: key_a = 324, key_b = 324
    [ 3174.567030] myhashtable: element: data = 7, name = oof
    [ 3174.567031] myhashtable: element: data = 3, name = foo
    [ 3174.567032] myhashtable: match for key 324: data = 7, name = oof
    [ 3174.567033] myhashtable: match for key 324: data = 3, name = foo
    [ 3174.567033] myhashtable: element named "foo" found!

    关于c - 如何使用内核哈希表 API?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60870788/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com