documentation: RCU-protected array indexes no longer supported
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>hifive-unleashed-5.1
parent
1ebee8017d
commit
cf9fbf8017
|
@ -10,7 +10,19 @@ also be used to protect arrays. Three situations are as follows:
|
||||||
|
|
||||||
3. Resizeable Arrays
|
3. Resizeable Arrays
|
||||||
|
|
||||||
Each of these situations are discussed below.
|
Each of these three situations involves an RCU-protected pointer to an
|
||||||
|
array that is separately indexed. It might be tempting to consider use
|
||||||
|
of RCU to instead protect the index into an array, however, this use
|
||||||
|
case is -not- supported. The problem with RCU-protected indexes into
|
||||||
|
arrays is that compilers can play way too many optimization games with
|
||||||
|
integers, which means that the rules governing handling of these indexes
|
||||||
|
are far more trouble than they are worth. If RCU-protected indexes into
|
||||||
|
arrays prove to be particularly valuable (which they have not thus far),
|
||||||
|
explicit cooperation from the compiler will be required to permit them
|
||||||
|
to be safely used.
|
||||||
|
|
||||||
|
That aside, each of the three RCU-protected pointer situations are
|
||||||
|
described in the following sections.
|
||||||
|
|
||||||
|
|
||||||
Situation 1: Hash Tables
|
Situation 1: Hash Tables
|
||||||
|
@ -36,9 +48,9 @@ Quick Quiz: Why is it so important that updates be rare when
|
||||||
Situation 3: Resizeable Arrays
|
Situation 3: Resizeable Arrays
|
||||||
|
|
||||||
Use of RCU for resizeable arrays is demonstrated by the grow_ary()
|
Use of RCU for resizeable arrays is demonstrated by the grow_ary()
|
||||||
function used by the System V IPC code. The array is used to map from
|
function formerly used by the System V IPC code. The array is used
|
||||||
semaphore, message-queue, and shared-memory IDs to the data structure
|
to map from semaphore, message-queue, and shared-memory IDs to the data
|
||||||
that represents the corresponding IPC construct. The grow_ary()
|
structure that represents the corresponding IPC construct. The grow_ary()
|
||||||
function does not acquire any locks; instead its caller must hold the
|
function does not acquire any locks; instead its caller must hold the
|
||||||
ids->sem semaphore.
|
ids->sem semaphore.
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,6 @@ checking of rcu_dereference() primitives:
|
||||||
Use explicit check expression "c" along with
|
Use explicit check expression "c" along with
|
||||||
srcu_read_lock_held()(). This is useful in code that
|
srcu_read_lock_held()(). This is useful in code that
|
||||||
is invoked by both SRCU readers and updaters.
|
is invoked by both SRCU readers and updaters.
|
||||||
rcu_dereference_index_check(p, c):
|
|
||||||
Use explicit check expression "c", but the caller
|
|
||||||
must supply one of the rcu_read_lock_held() functions.
|
|
||||||
This is useful in code that uses RCU-protected arrays
|
|
||||||
that is invoked by both RCU readers and updaters.
|
|
||||||
rcu_dereference_raw(p):
|
rcu_dereference_raw(p):
|
||||||
Don't check. (Use sparingly, if at all.)
|
Don't check. (Use sparingly, if at all.)
|
||||||
rcu_dereference_protected(p, c):
|
rcu_dereference_protected(p, c):
|
||||||
|
@ -64,11 +59,6 @@ checking of rcu_dereference() primitives:
|
||||||
but retain the compiler constraints that prevent duplicating
|
but retain the compiler constraints that prevent duplicating
|
||||||
or coalescsing. This is useful when when testing the
|
or coalescsing. This is useful when when testing the
|
||||||
value of the pointer itself, for example, against NULL.
|
value of the pointer itself, for example, against NULL.
|
||||||
rcu_access_index(idx):
|
|
||||||
Return the value of the index and omit all barriers, but
|
|
||||||
retain the compiler constraints that prevent duplicating
|
|
||||||
or coalescsing. This is useful when when testing the
|
|
||||||
value of the index itself, for example, against -1.
|
|
||||||
|
|
||||||
The rcu_dereference_check() check expression can be any boolean
|
The rcu_dereference_check() check expression can be any boolean
|
||||||
expression, but would normally include a lockdep expression. However,
|
expression, but would normally include a lockdep expression. However,
|
||||||
|
|
|
@ -25,17 +25,6 @@ o You must use one of the rcu_dereference() family of primitives
|
||||||
for an example where the compiler can in fact deduce the exact
|
for an example where the compiler can in fact deduce the exact
|
||||||
value of the pointer, and thus cause misordering.
|
value of the pointer, and thus cause misordering.
|
||||||
|
|
||||||
o Do not use single-element RCU-protected arrays. The compiler
|
|
||||||
is within its right to assume that the value of an index into
|
|
||||||
such an array must necessarily evaluate to zero. The compiler
|
|
||||||
could then substitute the constant zero for the computation, so
|
|
||||||
that the array index no longer depended on the value returned
|
|
||||||
by rcu_dereference(). If the array index no longer depends
|
|
||||||
on rcu_dereference(), then both the compiler and the CPU
|
|
||||||
are within their rights to order the array access before the
|
|
||||||
rcu_dereference(), which can cause the array access to return
|
|
||||||
garbage.
|
|
||||||
|
|
||||||
o Avoid cancellation when using the "+" and "-" infix arithmetic
|
o Avoid cancellation when using the "+" and "-" infix arithmetic
|
||||||
operators. For example, for a given variable "x", avoid
|
operators. For example, for a given variable "x", avoid
|
||||||
"(x-x)". There are similar arithmetic pitfalls from other
|
"(x-x)". There are similar arithmetic pitfalls from other
|
||||||
|
@ -76,14 +65,15 @@ o Do not use the results from the boolean "&&" and "||" when
|
||||||
dereferencing. For example, the following (rather improbable)
|
dereferencing. For example, the following (rather improbable)
|
||||||
code is buggy:
|
code is buggy:
|
||||||
|
|
||||||
int a[2];
|
int *p;
|
||||||
int index;
|
int *q;
|
||||||
int force_zero_index = 1;
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
r1 = rcu_dereference(i1)
|
p = rcu_dereference(gp)
|
||||||
r2 = a[r1 && force_zero_index]; /* BUGGY!!! */
|
q = &global_q;
|
||||||
|
q += p != &oom_p1 && p != &oom_p2;
|
||||||
|
r1 = *q; /* BUGGY!!! */
|
||||||
|
|
||||||
The reason this is buggy is that "&&" and "||" are often compiled
|
The reason this is buggy is that "&&" and "||" are often compiled
|
||||||
using branches. While weak-memory machines such as ARM or PowerPC
|
using branches. While weak-memory machines such as ARM or PowerPC
|
||||||
|
@ -94,14 +84,15 @@ o Do not use the results from relational operators ("==", "!=",
|
||||||
">", ">=", "<", or "<=") when dereferencing. For example,
|
">", ">=", "<", or "<=") when dereferencing. For example,
|
||||||
the following (quite strange) code is buggy:
|
the following (quite strange) code is buggy:
|
||||||
|
|
||||||
int a[2];
|
int *p;
|
||||||
int index;
|
int *q;
|
||||||
int flip_index = 0;
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
r1 = rcu_dereference(i1)
|
p = rcu_dereference(gp)
|
||||||
r2 = a[r1 != flip_index]; /* BUGGY!!! */
|
q = &global_q;
|
||||||
|
q += p > &oom_p;
|
||||||
|
r1 = *q; /* BUGGY!!! */
|
||||||
|
|
||||||
As before, the reason this is buggy is that relational operators
|
As before, the reason this is buggy is that relational operators
|
||||||
are often compiled using branches. And as before, although
|
are often compiled using branches. And as before, although
|
||||||
|
|
|
@ -879,9 +879,7 @@ SRCU: Initialization/cleanup
|
||||||
|
|
||||||
All: lockdep-checked RCU-protected pointer access
|
All: lockdep-checked RCU-protected pointer access
|
||||||
|
|
||||||
rcu_access_index
|
|
||||||
rcu_access_pointer
|
rcu_access_pointer
|
||||||
rcu_dereference_index_check
|
|
||||||
rcu_dereference_raw
|
rcu_dereference_raw
|
||||||
rcu_lockdep_assert
|
rcu_lockdep_assert
|
||||||
rcu_sleep_check
|
rcu_sleep_check
|
||||||
|
|
Loading…
Reference in New Issue