我试图理解和使用kernel hash tables,我已经阅读了this和this链接,但我不理解他们中的任何一个。为什么我们的结构体必须包含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");
但是这甚至不能编译,我做错了什么?我需要这个键和struct h_node
中的同名,所以我希望我的哈希表是这样的:
PS:在我的哈希表中,它永远不会发生冲突(我会处理它,使其永远不会发生),所以键可以是struct h_node
中的名称
1条答案
按热度按时间ybzsozfc1#
为什么我们的结构体里面必须有
struct h_list
?如果我们要通过struct h_list
访问我们的结构体,我们的结构体不应该在struct h_list
里面,而不是相反?这是因为哈希表是如何在Linux内核中实现的。哈希表只是一个固定大小为
struct hlist_head
的数组。每个数组代表一个桶,并且是一个链表的头。哈希表只包含一堆struct hlist_node
的链表,没有其他内容。它并没有真正“存储”整个用户定义的结构体。它仅保存指向每个元素的struct hlist_node
字段的指针。当你添加一个元素到哈希表中时,一个bucket被选中,并且一个指向你的结构体的
struct hlist_node
字段的指针被插入到bucket列表中。(例如通过hash_for_each()
),container_of()
宏用于获取您的真实的结构,知道它的类型和用户定义的结构中struct hlist_node
类型的结构成员的名称。这可以在下面的源代码中看到。例如,对于
hash_for_each()
,我们有:hash_for_each(name, bkt, obj, member)
剂量:hlist_for_each_entry()
剂量:hlist_entry_safe()
剂量:1.最后,
hlist_entry()
使用container_of()
来获得真实的的结构体:我需要密钥与
struct h_node
中存在的名称相同。Linux内核哈希表API只处理整数键,如果你看一下
linux/hashtable.h
中的实现,你会发现使用的哈希函数是hash_32()
和hash_64()
,它们都接受无符号整数值(分别是u32
和u64
)。Linux内核的哈希表API非常有限,它绝对不会实现你在其他编程语言中所使用的那种哈希表,它不能使用字符串作为键,而且它有固定的大小。
如果你想使用字符串,你必须散列这些字符串来生成一个无符号整数。要做到这一点,你可以使用
xxhash()
或编写自己的函数。xxhash()
函数相对较新,似乎还没有在内核代码中使用,所以我认为你的内核很可能没有配置它,你也没有它。在任何情况下,都要注意,如果哈希函数将 * 不同 * 的字符串转换为 * 相同 * 的键,或者如果
hash_add()
最终选择哈希表数组中的相同索引来插入元素,那么这两个元素将被放置在相同的哈希表桶中。当检索任何元素时(例如使用hash_for_each_possible()
),您 * 需要 * 考虑到这一点并正确检查其name
。工作示例
下面是一个完整的工作示例,演示了内核哈希表的基本用法,在内核v4.9上进行了测试。但应该也能在最新的v5.7上运行。注意,在这个例子中,我只是为了简单起见而在模块
_init
函数的堆栈上分配变量。这意味着我不能在代码的任何其他地方执行hash_for_each_possible()
,除非在该函数内部。如果您想要一个全局哈希表,能够保存稍后由不同函数访问的元素,则需要使用kmalloc()
动态分配它们。我的计算机上的
dmesg
输出: