我应该如何混合 RCU reader 和更新程序代码?
How should I be mixing RCU reader and updater code?
我有一个在树状数据库中查找结构的样板函数:
struct foo {
struct foo *child1; /* RCU-protected. */
struct foo *child2; /* RCU-protected. */
... /* Other stuff */
}
static struct foo *find_foo(int arg)
{
struct foo *parent;
... /* Do something to find parent. */
return rcu_dereference(parent->child1); /* or child2. Whatever. */
}
然后我有几个函数可以处理该结果:
void a(int arg)
{
struct foo *bar;
rcu_read_lock();
bar = find_foo(arg);
... /* Read something from bar and do something with it. */
rcu_read_unlock();
}
然后我有一个 updater/reclaimer。它需要像 "a" 函数一样找到对象(假设它已经从外部互斥):
void c(int arg)
{
struct foo *bar;
bar = find_foo(arg);
... /* make a backup pointer of bar->child1. */
rcu_assign_pointer(bar->child1, ...);
... /* free the old child or whatever. */
}
我的问题是,rcu_dereference()
的文档说它必须在读取端临界区内调用(即在 rcu_read_lock()
和 rcu_read_unlock()
之间)。 c()
通过调用 find_foo()
.
违反了这条规则
我犹豫要不要制作一个使用 rcu_dereference_protected()
而不是 rcu_dereference()
的全新版本 find_foo()
,因为它有太多重复代码,所以我想知道这是否c()
的实现是合法的:
void c(int arg)
{
struct foo *bar;
rcu_read_lock();
bar = find_foo(arg);
bar = rcu_dereference_protected(bar, ...); /* THIS. */
rcu_read_unlock();
... /* make a backup pointer of bar->child1. */
rcu_assign_pointer(bar->child1, ...);
... /* free the old child or whatever. */
}
如果这不合法,我应该如何混合使用 reader 和更新程序代码?
实际上,c()
的第一个变体是正确的(更新程序端不需要特定的取消引用),但它使 rcu 检查器感到困惑(检查器期望 rcu_dereference
发生在 rcu_read
节)。
即使从 rcu 检查器的角度来看,c()
的第二个变体也是正确的,但不需要 rcu_dereference_protected
:bar
已经是 rcu_dereference
的结果。
另一种让 rcu 检查器开心的方法是使用
rcu_dereference_check(<pointer>, <condition-when-in-updater>)
而不是
rcu_dereference(<pointer>)
内部 foo
实施。因此检查器不会抱怨 rcu_read
部分之外的 foo() 调用,直到它可以证明在这种情况下条件是 false
。
有了这样的 foo()
实现,c()
的第一个变体就可以了。
我有一个在树状数据库中查找结构的样板函数:
struct foo {
struct foo *child1; /* RCU-protected. */
struct foo *child2; /* RCU-protected. */
... /* Other stuff */
}
static struct foo *find_foo(int arg)
{
struct foo *parent;
... /* Do something to find parent. */
return rcu_dereference(parent->child1); /* or child2. Whatever. */
}
然后我有几个函数可以处理该结果:
void a(int arg)
{
struct foo *bar;
rcu_read_lock();
bar = find_foo(arg);
... /* Read something from bar and do something with it. */
rcu_read_unlock();
}
然后我有一个 updater/reclaimer。它需要像 "a" 函数一样找到对象(假设它已经从外部互斥):
void c(int arg)
{
struct foo *bar;
bar = find_foo(arg);
... /* make a backup pointer of bar->child1. */
rcu_assign_pointer(bar->child1, ...);
... /* free the old child or whatever. */
}
我的问题是,rcu_dereference()
的文档说它必须在读取端临界区内调用(即在 rcu_read_lock()
和 rcu_read_unlock()
之间)。 c()
通过调用 find_foo()
.
我犹豫要不要制作一个使用 rcu_dereference_protected()
而不是 rcu_dereference()
的全新版本 find_foo()
,因为它有太多重复代码,所以我想知道这是否c()
的实现是合法的:
void c(int arg)
{
struct foo *bar;
rcu_read_lock();
bar = find_foo(arg);
bar = rcu_dereference_protected(bar, ...); /* THIS. */
rcu_read_unlock();
... /* make a backup pointer of bar->child1. */
rcu_assign_pointer(bar->child1, ...);
... /* free the old child or whatever. */
}
如果这不合法,我应该如何混合使用 reader 和更新程序代码?
实际上,c()
的第一个变体是正确的(更新程序端不需要特定的取消引用),但它使 rcu 检查器感到困惑(检查器期望 rcu_dereference
发生在 rcu_read
节)。
即使从 rcu 检查器的角度来看,c()
的第二个变体也是正确的,但不需要 rcu_dereference_protected
:bar
已经是 rcu_dereference
的结果。
另一种让 rcu 检查器开心的方法是使用
rcu_dereference_check(<pointer>, <condition-when-in-updater>)
而不是
rcu_dereference(<pointer>)
内部 foo
实施。因此检查器不会抱怨 rcu_read
部分之外的 foo() 调用,直到它可以证明在这种情况下条件是 false
。
有了这样的 foo()
实现,c()
的第一个变体就可以了。