Skip to content

Commit 182dd4b

Browse files
committed
doc: Add load/store guarantees to Documentation/atomic-ops.txt
An IRC discussion uncovered many conflicting opinions on what types of data may be atomically loaded and stored. This commit therefore calls this out the official set: pointers, longs, ints, and chars (but not shorts). This commit also gives some examples of compiler mischief that can thwart atomicity. Please note that this discussion is relevant to !SMP kernels if CONFIG_PREEMPT=y: preemption can cause almost as much trouble as can SMP. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Richard Henderson <rth@twiddle.net> Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: Matt Turner <mattst88@gmail.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Haavard Skinnemoen <hskinnemoen@gmail.com> Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no> Cc: Mike Frysinger <vapier@gentoo.org> Cc: Mikael Starvik <starvik@axis.com> Cc: Jesper Nilsson <jesper.nilsson@axis.com> Cc: David Howells <dhowells@redhat.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: Richard Kuo <rkuo@codeaurora.org> Cc: Jes Sorensen <jes@sgi.com> Cc: Hirokazu Takata <takata@linux-m32r.org> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Michal Simek <monstr@monstr.eu> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Koichi Yasutake <yasutake.koichi@jp.panasonic.com> Cc: Jonas Bonn <jonas@southpole.se> Cc: Kyle McMartin <kyle@mcmartin.ca> Cc: Helge Deller <deller@gmx.de> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Chen Liqin <liqin.chen@sunplusct.com> Cc: Lennox Wu <lennox.wu@gmail.com> Cc: Paul Mundt <lethal@linux-sh.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Chris Metcalf <cmetcalf@tilera.com> Cc: Jeff Dike <jdike@addtoit.com> Cc: Richard Weinberger <richard@nod.at> Cc: Guan Xuetao <gxt@mprc.pku.edu.cn> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Chris Zankel <chris@zankel.net>
1 parent 1268fbc commit 182dd4b

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

Documentation/atomic_ops.txt

+87
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,93 @@ compiler optimizes the section accessing atomic_t variables.
8484

8585
*** YOU HAVE BEEN WARNED! ***
8686

87+
Properly aligned pointers, longs, ints, and chars (and unsigned
88+
equivalents) may be atomically loaded from and stored to in the same
89+
sense as described for atomic_read() and atomic_set(). The ACCESS_ONCE()
90+
macro should be used to prevent the compiler from using optimizations
91+
that might otherwise optimize accesses out of existence on the one hand,
92+
or that might create unsolicited accesses on the other.
93+
94+
For example consider the following code:
95+
96+
while (a > 0)
97+
do_something();
98+
99+
If the compiler can prove that do_something() does not store to the
100+
variable a, then the compiler is within its rights transforming this to
101+
the following:
102+
103+
tmp = a;
104+
if (a > 0)
105+
for (;;)
106+
do_something();
107+
108+
If you don't want the compiler to do this (and you probably don't), then
109+
you should use something like the following:
110+
111+
while (ACCESS_ONCE(a) < 0)
112+
do_something();
113+
114+
Alternatively, you could place a barrier() call in the loop.
115+
116+
For another example, consider the following code:
117+
118+
tmp_a = a;
119+
do_something_with(tmp_a);
120+
do_something_else_with(tmp_a);
121+
122+
If the compiler can prove that do_something_with() does not store to the
123+
variable a, then the compiler is within its rights to manufacture an
124+
additional load as follows:
125+
126+
tmp_a = a;
127+
do_something_with(tmp_a);
128+
tmp_a = a;
129+
do_something_else_with(tmp_a);
130+
131+
This could fatally confuse your code if it expected the same value
132+
to be passed to do_something_with() and do_something_else_with().
133+
134+
The compiler would be likely to manufacture this additional load if
135+
do_something_with() was an inline function that made very heavy use
136+
of registers: reloading from variable a could save a flush to the
137+
stack and later reload. To prevent the compiler from attacking your
138+
code in this manner, write the following:
139+
140+
tmp_a = ACCESS_ONCE(a);
141+
do_something_with(tmp_a);
142+
do_something_else_with(tmp_a);
143+
144+
For a final example, consider the following code, assuming that the
145+
variable a is set at boot time before the second CPU is brought online
146+
and never changed later, so that memory barriers are not needed:
147+
148+
if (a)
149+
b = 9;
150+
else
151+
b = 42;
152+
153+
The compiler is within its rights to manufacture an additional store
154+
by transforming the above code into the following:
155+
156+
b = 42;
157+
if (a)
158+
b = 9;
159+
160+
This could come as a fatal surprise to other code running concurrently
161+
that expected b to never have the value 42 if a was zero. To prevent
162+
the compiler from doing this, write something like:
163+
164+
if (a)
165+
ACCESS_ONCE(b) = 9;
166+
else
167+
ACCESS_ONCE(b) = 42;
168+
169+
Don't even -think- about doing this without proper use of memory barriers,
170+
locks, or atomic operations if variable a can change at runtime!
171+
172+
*** WARNING: ACCESS_ONCE() DOES NOT IMPLY A BARRIER! ***
173+
87174
Now, we move onto the atomic operation interfaces typically implemented with
88175
the help of assembly code.
89176

0 commit comments

Comments
 (0)