c - hlist_for_each_entry_rcu 是否需要向其中传递额外的指针?

标签 c algorithm list linux-kernel rcu

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/

相关文章:

python - for循环,如果元素不等于值,则替换为空字符串

在C中将字节数组转换为字符数组

c++ - 如何将源代码附加到 Eclipse CDT 上的库

java - 判断一个数是否是4的幂,logNum % logBase == 0 vs (logNum/logBase) % 1 == 0

list - Scala - future 列表首先完成有条件

python 使用嵌套列表检查列表

c - 如何在 Nim 中访问指针数组的元素?

用系统在 C 中编译

java - 如何创建简单的扑克手牌算法?

performance - Scala 的理解性能