hlist_for_each_entry_rcu是否需要将其他指针传递给它?

时间:2015-08-27 19:46:47

标签: c algorithm list linux-kernel rcu

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)); \

1 个答案:

答案 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的扩展,这可能解释了为什么它不可能在撰写文章的时间。