Skip to content

Commit

Permalink
documentation: RCU-protected array indexes no longer supported
Browse files Browse the repository at this point in the history
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
  • Loading branch information
Paul E. McKenney committed May 27, 2015
1 parent 1ebee80 commit cf9fbf8
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 37 deletions.
20 changes: 16 additions & 4 deletions Documentation/RCU/arrayRCU.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@ also be used to protect arrays. Three situations are as follows:

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
Expand All @@ -36,9 +48,9 @@ Quick Quiz: Why is it so important that updates be rare when
Situation 3: Resizeable Arrays

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
semaphore, message-queue, and shared-memory IDs to the data structure
that represents the corresponding IPC construct. The grow_ary()
function formerly used by the System V IPC code. The array is used
to map from semaphore, message-queue, and shared-memory IDs to the data
structure that represents the corresponding IPC construct. The grow_ary()
function does not acquire any locks; instead its caller must hold the
ids->sem semaphore.

Expand Down
10 changes: 0 additions & 10 deletions Documentation/RCU/lockdep.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ checking of rcu_dereference() primitives:
Use explicit check expression "c" along with
srcu_read_lock_held()(). This is useful in code that
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):
Don't check. (Use sparingly, if at all.)
rcu_dereference_protected(p, c):
Expand All @@ -64,11 +59,6 @@ checking of rcu_dereference() primitives:
but retain the compiler constraints that prevent duplicating
or coalescsing. This is useful when when testing the
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
expression, but would normally include a lockdep expression. However,
Expand Down
33 changes: 12 additions & 21 deletions Documentation/RCU/rcu_dereference.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
operators. For example, for a given variable "x", avoid
"(x-x)". There are similar arithmetic pitfalls from other
Expand Down Expand Up @@ -76,14 +65,15 @@ o Do not use the results from the boolean "&&" and "||" when
dereferencing. For example, the following (rather improbable)
code is buggy:

int a[2];
int index;
int force_zero_index = 1;
int *p;
int *q;

...

r1 = rcu_dereference(i1)
r2 = a[r1 && force_zero_index]; /* BUGGY!!! */
p = rcu_dereference(gp)
q = &global_q;
q += p != &oom_p1 && p != &oom_p2;
r1 = *q; /* BUGGY!!! */

The reason this is buggy is that "&&" and "||" are often compiled
using branches. While weak-memory machines such as ARM or PowerPC
Expand All @@ -94,14 +84,15 @@ o Do not use the results from relational operators ("==", "!=",
">", ">=", "<", or "<=") when dereferencing. For example,
the following (quite strange) code is buggy:

int a[2];
int index;
int flip_index = 0;
int *p;
int *q;

...

r1 = rcu_dereference(i1)
r2 = a[r1 != flip_index]; /* BUGGY!!! */
p = rcu_dereference(gp)
q = &global_q;
q += p > &oom_p;
r1 = *q; /* BUGGY!!! */

As before, the reason this is buggy is that relational operators
are often compiled using branches. And as before, although
Expand Down
2 changes: 0 additions & 2 deletions Documentation/RCU/whatisRCU.txt
Original file line number Diff line number Diff line change
Expand Up @@ -879,9 +879,7 @@ SRCU: Initialization/cleanup

All: lockdep-checked RCU-protected pointer access

rcu_access_index
rcu_access_pointer
rcu_dereference_index_check
rcu_dereference_raw
rcu_lockdep_assert
rcu_sleep_check
Expand Down

0 comments on commit cf9fbf8

Please sign in to comment.