Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 277231
b: refs/heads/master
c: 182dd4b
h: refs/heads/master
i:
  277229: 361135a
  277227: e6c9568
  277223: 6fb5ea4
  277215: b0bb206
v: v3
  • Loading branch information
Paul E. McKenney committed Dec 11, 2011
1 parent 187a11d commit 1adc768
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1268fbc746ea1cd279886a740dcbad4ba5232225
refs/heads/master: 182dd4b277177e8465ad11cd9f85f282946b5578
87 changes: 87 additions & 0 deletions trunk/Documentation/atomic_ops.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,93 @@ compiler optimizes the section accessing atomic_t variables.

*** YOU HAVE BEEN WARNED! ***

Properly aligned pointers, longs, ints, and chars (and unsigned
equivalents) may be atomically loaded from and stored to in the same
sense as described for atomic_read() and atomic_set(). The ACCESS_ONCE()
macro should be used to prevent the compiler from using optimizations
that might otherwise optimize accesses out of existence on the one hand,
or that might create unsolicited accesses on the other.

For example consider the following code:

while (a > 0)
do_something();

If the compiler can prove that do_something() does not store to the
variable a, then the compiler is within its rights transforming this to
the following:

tmp = a;
if (a > 0)
for (;;)
do_something();

If you don't want the compiler to do this (and you probably don't), then
you should use something like the following:

while (ACCESS_ONCE(a) < 0)
do_something();

Alternatively, you could place a barrier() call in the loop.

For another example, consider the following code:

tmp_a = a;
do_something_with(tmp_a);
do_something_else_with(tmp_a);

If the compiler can prove that do_something_with() does not store to the
variable a, then the compiler is within its rights to manufacture an
additional load as follows:

tmp_a = a;
do_something_with(tmp_a);
tmp_a = a;
do_something_else_with(tmp_a);

This could fatally confuse your code if it expected the same value
to be passed to do_something_with() and do_something_else_with().

The compiler would be likely to manufacture this additional load if
do_something_with() was an inline function that made very heavy use
of registers: reloading from variable a could save a flush to the
stack and later reload. To prevent the compiler from attacking your
code in this manner, write the following:

tmp_a = ACCESS_ONCE(a);
do_something_with(tmp_a);
do_something_else_with(tmp_a);

For a final example, consider the following code, assuming that the
variable a is set at boot time before the second CPU is brought online
and never changed later, so that memory barriers are not needed:

if (a)
b = 9;
else
b = 42;

The compiler is within its rights to manufacture an additional store
by transforming the above code into the following:

b = 42;
if (a)
b = 9;

This could come as a fatal surprise to other code running concurrently
that expected b to never have the value 42 if a was zero. To prevent
the compiler from doing this, write something like:

if (a)
ACCESS_ONCE(b) = 9;
else
ACCESS_ONCE(b) = 42;

Don't even -think- about doing this without proper use of memory barriers,
locks, or atomic operations if variable a can change at runtime!

*** WARNING: ACCESS_ONCE() DOES NOT IMPLY A BARRIER! ***

Now, we move onto the atomic operation interfaces typically implemented with
the help of assembly code.

Expand Down

0 comments on commit 1adc768

Please sign in to comment.