- 论坛徽章:
- 0
|
回复 2# 爻易
1 从宏定义就可以看出它是强制读操作,写操作当然用不上,因为写操作本身就说明你已经有数据的最新版本了,不需要再读。
可能这个我没太说清楚。可以看下下面我对代码的理解
2 在函数中:
加锁
读a
解锁
其他操作 // 这引入了竞争条件
加锁
读a // 是否数据最新版本,依赖于具体编译器的实现。如果要从语言层面消除此不确定性,加关键字声明
解锁
您这个理解跟我是一样的。那能否解释下下面代码的理解?
其实 这个问题是看内核netfilter模块rcu锁的使用时产生的。不知道有人看过这块没
代码如下
int nf_register_hook(struct nf_hook_ops *reg)
{
struct nf_hook_ops *elem;
int err;
err = mutex_lock_interruptible(&nf_hook_mutex);
if (err < 0)
return err;
list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {
/*这里没有使用ACCESS_ONCE相关的函数.基本上相关的资料显示跟您说的是一致的,因为mutex_lock_interruptible屏蔽掉了其它的写操作。那么当前寄存器的值肯定是最新的。那么我的疑问产生了
1.根据大多数资料的显示。volatile类型的变量。其写和读都是立即响应到内存的。那么一个ACCESS_ONCE如何能达到volatile的写目的?
还是说那些资料中说的写其实是很多人的误解,就好像很多人误认为volatile跟cache有关系一样
2.锁屏蔽掉了其他的写操作好像不能说一定就不会出问题吧。
如 cpu1
rcu_read_lock()
list_for_each_continue_rcu //这里使用了 ACCESS_ONCE保证寄存器中为最新的。这里假设链表为空,即表头的next和prev都指向自己
rcu_read_unlock()
//这个间隔cpu2 在表里加了一个list节点。这里就有个问题cpu2的寄存器的值会立马写回内存吗?
cpu1继续执行
mutex_lock
list_for_each_entry //这里没有使用ACCESS_ONCE访问,那么有没有可能寄存中的值还是旧的如现在读到的表为空。那么继续的写操作可就非常危险了。
mutex_unlock
*/
if (reg->priority < elem->priority)
break;
}
list_add_rcu(®->list, elem->list.prev);
mutex_unlock(&nf_hook_mutex);
return 0;
}
int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
{
……
rcu_read_lock();
elem = &nf_hooks[pf][hook];
next_hook:
verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,
outdev, &elem, okfn, hook_thresh);
……
}
rcu_read_unlock();
……
}
unsigned int nf_iterate(struct list_head *head,
struct sk_buff *skb,
unsigned int hook,
const struct net_device *indev,
const struct net_device *outdev,
struct list_head **i,
int (*okfn)(struct sk_buff *),
int hook_thresh)
{
……
list_for_each_continue_rcu(*i, head) {
}
……
}
#define list_for_each_continue_rcu(pos, head) \
for ((pos) = rcu_dereference_raw((pos)->next); \
prefetch((pos)->next), (pos) != (head); \
(pos) = rcu_dereference_raw((pos)->next))
#define rcu_dereference_raw(p) ({ \
typeof(p) _________p1 = ACCESS_ONCE(p); \
smp_read_barrier_depends(); \
(_________p1); \
})
|
|