hlist_head和list_head区别以及container_of机制 - [linux内核]

25 篇文章 0 订阅

原文地址:http://www.blogbus.com/wanderer-zjhit-logs/149618655.html

一:hlist_head和list_head,为节省空间而诞生的双胞胎兄弟
1 struct hlist_head定义: 
struct hlist_head {
   struct hlist_node *first;
};
struct hlist_node {
   struct hlist_node *next, **pprev;
};
2 struct list_head定义:
struct list_head {
 struct list_node *next,*prev;
};
比较这两个结构体,可以看出双链表struct hlist_head仅仅比struct list_head在头部节省了一个存储字空间。
由于内核中大量使用哈希表,而每个元素都是链表结构,使用hlist_head从整体上考虑可以节省大量空间,但是却不能在O(1)时间访问双链表的尾。
当调用hlist_add_head()在头部添加一个元素(node_2)时,情况如下:

node_2的pprev指针指向hlist_head的first指针。*(node_2->pprev)=node_2地址,node->pprev等于前一个元素的next指针或者first指针的地址。这样可以根据局部元素地址来利用container_of函数求得前一元素的地址。
二:根据局部元素的地址来求得整体结构的地址
内核中大量的利用双链表结构,配合哈希表或者树结构,来迅速的定位内核中数以万计的各种数据结构,下列代码的使用在内核中可谓司空见惯:
370 * hlist_for_each_entry_rcu - iterate over rcu list of given type
371 * @tpos:       the type * to use as a loop cursor.
372 * @pos:        the &struct hlist_node to use as a loop cursor.
373 * @head:       the head for your list.
374 * @member:     the name of the hlist_node within the struct.
375 *
376 * This list-traversal primitive may safely run concurrently with
377 * the _rcu list-mutation primitives such as hlist_add_head_rcu()
378 * as long as the traversal is guarded by rcu_read_lock().
379 */
380 #define hlist_for_each_entry_rcu(tpos, pos, head, member)                \
381         for (pos = rcu_dereference((head)->first);                       \
382                 pos && ({ prefetch(pos->next); 1; }) &&                  \
383                 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
384                 pos = rcu_dereference(pos->next))
rcu是(read-copy-update)是一种相当新的内核同步机制,允许读写并发进行,该机制记录了指向共享数据结构的所有使用者,在该结构将被改变时,首先创建一个副本,在副本中进行修改。当所有的读访问结束后,指针将替换为新的,修改后的副本的指针。
其中tpos是要获取的数据结构。比如kprobe结构,该结构有一项名为member(一般为hlist_head结构),head是hlist_head指针,而pos显然从头到尾暂存hlist双链表的每一项。
该宏定义可以对该双链表所存储的每个结构体进行某种操作。
而其中的关键是hlist_entry(pos,typeof(*tpos),member),
该结构由#define hlist_entry(ptr,type,member) container_of(ptr,type,member)得到
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr:     the pointer to the member.
* @type:     the type of the container struct this is embedded in.
* @member:     the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({             /
         const typeof( ((type *)0)->member ) *__mptr = (ptr);     /
         (type *)( (char *)__mptr - offsetof(type,member) );})
可见,container_of是实现的根本,首先定义与member类型一样(当然也与ptr类型一样)的指针__mpter
而offsetof获得该元素相当于该结构体得偏移量,定义如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
其他类型的实现原理大体类似。理解一个其他的就都掌握了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值