LWN在RCU上给出了以下示例:
订阅受RCU保护的hlist也类似于通告 列表:
1 rcu_read_lock(); 2 hlist_for_each_entry_rcu(p, q, head, list) { 3 do_something_with(p->a, p->b, p->c); 4 } 5 rcu_read_unlock();
快速测验3 :当只需要一个指针时,我们为什么需要将两个指针传递给hlist_for_each_entry_rcu() list_for_each_entry_rcu()?
回答:因为在hlist中需要检查NULL而不是遇到头部。 (尝试编写单指针编码 hlist_for_each_entry_rcu()。如果你想出一个很好的解决方案,它 会是一件非常好的事情!)
我认为它必须引用旧版本的hlist_for_each_entry_rcu(),因为rculist.h
标题中的当前版本(3.13.0)实际上呈现了hlist_for_each_entry_rcu
定义了3个参数,因此无需额外的第四个指针,似乎很难发明:
#define hlist_for_each_entry_rcu(pos, head, member) \
for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
typeof(*(pos)), member); \
pos; \
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
&(pos)->member)), typeof(*(pos)), member))
我是否遗漏了当前rculist.h中给出的某些内容或以上版本非常好的?
我们可以看到__rcu_dereference_check
中创建了额外指针的微妙内容:
#define rcu_dereference_raw(p) rcu_dereference_check(p, 1) /*@@@ needed? @@@*/
#define rcu_dereference_check(p, c) \
__rcu_dereference_check((p), rcu_read_lock_held() || (c), __rcu)
#define __rcu_dereference_check(p, c, space) \
({ \
typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \
" usage"); \
rcu_dereference_sparse(p, space); \
smp_read_barrier_depends(); \
((typeof(*p) __force __kernel *)(_________p1)); \
答案 0 :(得分:2)
我想知道同样的事情!挖掘源代码,似乎四个参数版本被三个参数版本替换,介于3.8(https://github.com/torvalds/linux/blob/v3.8/include/linux/rculist.h#L457)和3.9(https://github.com/torvalds/linux/blob/v3.9/include/linux/rculist.h#L456)之间
要比较两个宏,这里是旧的四个参数版本:
#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
for (pos = rcu_dereference_raw(hlist_first_rcu(head)); \
pos && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
pos = rcu_dereference_raw(hlist_next_rcu(pos)))
这是新的三参数版本:
#define hlist_for_each_entry_rcu(pos, head, member) \
for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
typeof(*(pos)), member); \
pos; \
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
&(pos)->member)), typeof(*(pos)), member))
所以关键区别似乎是hlist_entry_safe
宏,基本上是ptr? ptr->member : NULL
。
这显然不可能,因为hlist_entry_safe
是一个宏,因此ptr
可能是一个表达式,并且该表达式不应被多次评估。例如,显而易见的解决方案 - #define hlist_entry_safe(ptr, member) ((ptr)? (ptr)->member : NULL)
- 将不起作用,因为(ptr)
将被评估两次。
基于this answer,我假设在3.9中使用的语法 - … ({ typeof(ptr) ____ptr = (ptr); … })
- 是仅限GCC的扩展,这可能解释了为什么它不可能在撰写文章的时间。