LWN给出了以下关于 RCU 的示例:
Subscribing to an RCU-protected hlist is also similar to the circular list:
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();
Quick Quiz 3: Why do we need to pass two pointers into hlist_for_each_entry_rcu() when only one is needed for list_for_each_entry_rcu()?
Answer: Because in an hlist it is necessary to check for NULL rather than for encountering the head. (Try coding up a single-pointer hlist_for_each_entry_rcu(). If you come up with a nice solution, it would be a very good thing!)
我认为它必须引用 hlist_for_each_entry_rcu() 的旧版本,因为 rculist.h
header 中的当前版本(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)); \
最佳答案
我也想知道同样的事情!深入研究源代码,似乎四参数版本被 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->成员: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 的扩展,这可能解释为什么在撰写本文时这是不可能的。
关于c - hlist_for_each_entry_rcu 是否需要向其中传递额外的指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32258197/