Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+87
+87
Documentation/atomic_ops.txt
··· 84 84 85 85 *** YOU HAVE BEEN WARNED! *** 86 86 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 + 87 174 Now, we move onto the atomic operation interfaces typically implemented with 88 175 the help of assembly code. 89 176