linux Hash表简介
一、Hash表简介
1. 哈希表(Hash table)又叫散列表,是根据(Key, Value) 键值对进行访问的数据结构。主要目的是提高查询效率,比如Hash表的order为5,也就是同时使用2^5个链表,理论上查询速度可以比链表快2^5倍,典型的
以空间换时间。
2. 主要实现在 include/linux/hashtable.h 中,基于hlist。
二、相关结构
/* include/linux/types.h */ struct hlist_head { struct hlist_node *first; };struct hlist_node {
struct hlist_node *next, **pprev;
};
使用二级指针 **pprev 可以使在删除节点上的处理变的简单,无需关心是否是head节点。而单链表或双向链表使用 *prev 成员需要单独判断是否是head节点。
三、相关函数
1. 定义Hash表
/* Hash表的表头就是一个数组,数组中每一个原生都是一个链表 */ #define DECLARE_HASHTABLE(name, bits) \ struct hlist_head name[1 << (bits)]/ 定义并初始化 /
#define DEFINE_HASHTABLE(name, bits)
struct hlist_head name[1 << (bits)] =
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
2. Hash表初始化
/* 初始化Hash表 */ #define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
{
unsigned int i;</span><span style="color: rgba(0, 0, 255, 1)">for</span> (i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i < sz; i++<span style="color: rgba(0, 0, 0, 1)">) INIT_HLIST_HEAD(</span>&<span style="color: rgba(0, 0, 0, 1)">ht[i]);}
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
3. Hash表添加元素
/** * hash_add - add an object to a hashtable * @hashtable: hashtable to add to * @node: the &struct hlist_node of the object to be added * @key: the key of the object to be added */ #define hash_add(hashtable, node, key) \ hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])/
- hash_add_rcu - add an object to a rcu enabled hashtable
- @hashtable: hashtable to add to
- @node: the &struct hlist_node of the object to be added
- @key: the key of the object to be added
*/
#define hash_add_rcu(hashtable, node, key) <span style="color: rgba(0, 0, 0, 1)">
hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
4. Hash表遍历
/** * hash_for_each - iterate over a hashtable * @name: hashtable to iterate * @bkt: integer to use as bucket loop cursor * @obj: the type * to use as a loop cursor for each entry * @member: the name of the hlist_node within the struct */ #define 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)/
- hash_for_each_rcu - iterate over a rcu enabled hashtable
- @name: hashtable to iterate
- @bkt: integer to use as bucket loop cursor
- @obj: the type * to use as a loop cursor for each entry
- @member: the name of the hlist_node within the struct
*/
#define hash_for_each_rcu(name, bkt, obj, member)
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);
(bkt)++)
hlist_for_each_entry_rcu(obj, &name[bkt], member)/
- hash_for_each_safe - iterate over a hashtable safe against removal of
- hash entry
- @name: hashtable to iterate
- @bkt: integer to use as bucket loop cursor
- @tmp: a &struct hlist_node used for temporary storage
- @obj: the type * to use as a loop cursor for each entry
- @member: the name of the hlist_node within the struct
*/
#define hash_for_each_safe(name, bkt, tmp, obj, member)
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);
(bkt)++)
hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)/
- hash_for_each_possible - iterate over all possible objects hashing to the
- same bucket
- @name: hashtable to iterate
- @obj: the type * to use as a loop cursor for each entry
- @member: the name of the hlist_node within the struct
- @key: the key of the objects to iterate over
*/
#define hash_for_each_possible(name, obj, member, key) <span style="color: rgba(0, 0, 0, 1)">
hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member)/
- hash_for_each_possible_rcu - iterate over all possible objects hashing to the
- same bucket in an rcu enabled hashtable
- @name: hashtable to iterate
- @obj: the type * to use as a loop cursor for each entry
- @member: the name of the hlist_node within the struct
- @key: the key of the objects to iterate over
*/
#define hash_for_each_possible_rcu(name, obj, member, key, cond...) <span style="color: rgba(0, 0, 0, 1)">
hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],
member, ## cond)/
- hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing
- to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable
- @name: hashtable to iterate
- @obj: the type * to use as a loop cursor for each entry
- @member: the name of the hlist_node within the struct
- @key: the key of the objects to iterate over
- This is the same as hash_for_each_possible_rcu() except that it does
- not do any RCU debugging or tracing.
*/
#define hash_for_each_possible_rcu_notrace(name, obj, member, key) <span style="color: rgba(0, 0, 0, 1)">
hlist_for_each_entry_rcu_notrace(obj,
&name[hash_min(key, HASH_BITS(name))], member)/
- hash_for_each_possible_safe - iterate over all possible objects hashing to the
- same bucket safe against removals
- @name: hashtable to iterate
- @obj: the type * to use as a loop cursor for each entry
- @tmp: a &struct hlist_node used for temporary storage
- @member: the name of the hlist_node within the struct
- @key: the key of the objects to iterate over
*/
#define hash_for_each_possible_safe(name, obj, tmp, member, key) <span style="color: rgba(0, 0, 0, 1)">
hlist_for_each_entry_safe(obj, tmp,
&name[hash_min(key, HASH_BITS(name))], member)
5. Hash表元素删除
/** * hash_del - remove an object from a hashtable * @node: &struct hlist_node of the object to remove */ static inline void hash_del(struct hlist_node *node) { hlist_del_init(node); }/
- hash_del_rcu - remove an object from a rcu enabled hashtable
- @node: &struct hlist_node of the object to remove
*/
static inline void hash_del_rcu(struct hlist_node *node)
{
hlist_del_init_rcu(node);
}
注:更多API见 hashtable.h。
四、使用举例
1. 使用hash表缓存内核符号
#define pr_fmt(fmt) "Hash Table Debug: " fmtinclude <linux/kernel.h>
include <linux/module.h>
include <linux/errno.h>
include <linux/init.h>
include <linux/kallsyms.h>
include <linux/hashtable.h>
#define HASH_TABLE_BIT 5
#define HASH_TABLE_LEN (1 << HASH_TABLE_BIT)
#define HASH_KEY_MASK ((1 << HASH_TABLE_BIT) - 1)struct hash_node {
unsigned long addr;
char symbol[KSYM_SYMBOL_LEN];
struct hlist_node node;
};struct hash_test_desc {
struct hlist_head htbl[HASH_TABLE_LEN];
};static struct hash_test_desc *htd = NULL;
static const char *find_and_cache_symbol(unsigned long caller_addr)
{
struct hash_node *cur_node = NULL;
struct hash_node *new_node = NULL;
const char *cur_symbol = NULL;
unsigned int cur_key = 0;</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">htd) </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">NULL</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; cur_key </span>= (unsigned <span style="color: rgba(0, 0, 255, 1)">int</span>) caller_addr &<span style="color: rgba(0, 0, 0, 1)"> HASH_KEY_MASK; </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> try to find symbols from history records </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> hash_for_each_possible(htd</span>-><span style="color: rgba(0, 0, 0, 1)">htbl, cur_node, node, cur_key) { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cur_node->addr ==<span style="color: rgba(0, 0, 0, 1)"> caller_addr) { cur_symbol </span>= cur_node-><span style="color: rgba(0, 0, 0, 1)">symbol; </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> symbol not found, add new a record </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">cur_symbol) { new_node </span>= kzalloc(<span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> hash_node), GFP_ATOMIC); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">new_node) </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">NULL-no_mem</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; new_node</span>->addr =<span style="color: rgba(0, 0, 0, 1)"> caller_addr; sprint_symbol(new_node</span>-><span style="color: rgba(0, 0, 0, 1)">symbol, caller_addr); cur_symbol </span>= new_node-><span style="color: rgba(0, 0, 0, 1)">symbol; hash_add(htd</span>->htbl, &new_node-><span style="color: rgba(0, 0, 0, 1)">node, cur_key); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cur_symbol;}
static void remove_hash_table(struct hash_test_desc *ld)
{
int bkt = 0;
struct hash_node *cur = NULL;
struct hlist_node *tmp = NULL;
struct hlist_head *htbl = NULL;</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">ld) </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">; hash_for_each_safe(ld</span>-><span style="color: rgba(0, 0, 0, 1)">htbl, bkt, tmp, cur, node) { hash_del(</span>&cur-><span style="color: rgba(0, 0, 0, 1)">node); kfree(cur); }}
static void hash_table_hook_func(void)
{
void *location;</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">htd) </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">; location </span>= __builtin_return_address(<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">); pr_info(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">caller=%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, find_and_cache_symbol((unsigned <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)">)location));}
EXPORT_SYMBOL(hash_table_hook_func);static int __init hash_table_debug_init(void)
{
struct hash_test_desc *ld = kzalloc(sizeof(struct hash_test_desc), GFP_KERNEL);
if (!ld) {
pr_info("kzalloc failed!\n");
return -ENOMEM;
}
htd = ld;</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;}
static void __exit hash_table_debug_exit(void)
{
struct hash_test_desc *ld = htd;
htd = NULL;
remove_hash_table(ld);
kfree(ld);
}module_init(hash_table_debug_init);
module_exit(hash_table_debug_exit);MODULE_DESCRIPTION("Hash Table Debug");
MODULE_LICENSE("GPL v2");
参考:https://zhuanlan.zhihu.com/p/360217911
<a href="https://www.cnblogs.com/hellokitty2/p/16643381.html" class="p_n_p_prefix">« </a> 上一篇: <a href="https://www.cnblogs.com/hellokitty2/p/16643381.html" data-featured-image="" title="发布于 2022-08-31 15:51">调度器38—cpumask</a>
<br>
<a href="https://www.cnblogs.com/hellokitty2/p/16695009.html" class="p_n_p_prefix">» </a> 下一篇: <a href="https://www.cnblogs.com/hellokitty2/p/16695009.html" data-featured-image="" title="发布于 2022-09-14 23:17">进程管理上层代码-1—Process.java</a>
本文来自博客园,作者:谁家的喵,转载请注明原文链接:https://www.cnblogs.com/luof-man/articles/17954774




浙公网安备 33010602011771号