内核数据结构--哈希链表

Linux内核中,除了有通用了双向链表list,还有通用的哈希链表hlist。后者定义与前者有些不同。因为通常一个哈希表的表头要占用很大空间,而如果每个表头都用一个双向链表来做的话,就显得太浪费了。只用一个指针可以实现相同的功能,并且可以节省一半的表头存储空间。

双向链表定义如下:

struct list_head {
struct list_head *next, *prev;
};

哈希链表定义如下:

struct hlist_head {
    struct hlist_node *first;
}
 
struct hlist_node {
    struct hlist_node *next, **pprev;
}

在Linux内核的 hlist_node 结构中不使用通常的 prev 指针,而使用二级指针 pprev,是因为对每一个哈希表的表项来说,它并不组成循环的链表,这样就不能方便地用统一的形式操作。在双向链表中,表头和节点是同一个数据结构,直接用 prev 没有问题。而在 hlist 中,表头没有 prev,也没有 next,只有一个 first。为了能统一地修改表头的 first 指针,即表头的 first 指针必须能够被引用修改,hlist 就设计了 pprev, 从而在表头插入的操作可以通过一致的“*(node->pprev)”访问和修改前节点的next(或first)指针。

下面是hlist中常用的几个宏:

#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)

下面只列出hlist_add_before操作函数,其他hlist链表操作函数操作方法类似。这个函数中的参数next不能为空。它在next前面加入了n节点。函数的实现与list中对应函数类似。

static inline void __hlist_del(struct hlist_node *n){
       struct hlist_node *next = n->next;
       struct hlist_node **pprev = n->pprev;
       *pprev = next;
       if (next)
            next->pprev = pprev;
}

static inline void hlist_add_before(struct hlist_node *n,struct hlist_node *next){
         n->pprev = next->pprev;
         n->next = next;
         next->pprev = &n->next;
          *(n->pprev) = n;
}

#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值