diff options
author | Matti Linnanvuori <mattilinnanvuori@yahoo.com> | 2007-10-17 10:30:08 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 19:42:58 +0400 |
commit | 8d7b52dfc9b0c672a3c39a82b896c8eedabb2a63 (patch) | |
tree | c1fe136c5b9ddafdb1c9e79e9aae0ff969117078 /Documentation/atomic_ops.txt | |
parent | 5f519d728169fa9975bcba001de425f11e18e8e3 (diff) | |
download | linux-8d7b52dfc9b0c672a3c39a82b896c8eedabb2a63.tar.xz |
atomic_ops.txt has incorrect, misleading and insufficient information [Bug 9020]
atomic_ops.txt has incorrect, misleading and insufficient information about
semantics of initializer, atomic_set, atomic_read and atomic_xchg.
It also incorrectly implies that operations mentioned above are not actual
atomic operations.
Included is most of the patch Document non-semantics of atomic_read() and
atomic_set() by Chris Snook, except the word "assignment".
Signed-off-by: Matti Linnanvuori <mattilinnanvuori@yahoo.com>
Cc: Nick Piggin <npiggin@suse.de>
Cc: "Paul E. McKenney" <paulmck@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'Documentation/atomic_ops.txt')
-rw-r--r-- | Documentation/atomic_ops.txt | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt index 938f99957052..d46306fea230 100644 --- a/Documentation/atomic_ops.txt +++ b/Documentation/atomic_ops.txt @@ -14,12 +14,15 @@ suffice: typedef struct { volatile int counter; } atomic_t; +Historically, counter has been declared volatile. This is now discouraged. +See Documentation/volatile-considered-harmful.txt for the complete rationale. + local_t is very similar to atomic_t. If the counter is per CPU and only updated by one CPU, local_t is probably more appropriate. Please see Documentation/local_ops.txt for the semantics of local_t. - The first operations to implement for atomic_t's are the -initializers and plain reads. +The first operations to implement for atomic_t's are the initializers and +plain reads. #define ATOMIC_INIT(i) { (i) } #define atomic_set(v, i) ((v)->counter = (i)) @@ -28,6 +31,12 @@ The first macro is used in definitions, such as: static atomic_t my_counter = ATOMIC_INIT(1); +The initializer is atomic in that the return values of the atomic operations +are guaranteed to be correct reflecting the initialized value if the +initializer is used before runtime. If the initializer is used at runtime, a +proper implicit or explicit read memory barrier is needed before reading the +value with atomic_read from another thread. + The second interface can be used at runtime, as in: struct foo { atomic_t counter; }; @@ -40,13 +49,43 @@ The second interface can be used at runtime, as in: return -ENOMEM; atomic_set(&k->counter, 0); +The setting is atomic in that the return values of the atomic operations by +all threads are guaranteed to be correct reflecting either the value that has +been set with this operation or set with another operation. A proper implicit +or explicit memory barrier is needed before the value set with the operation +is guaranteed to be readable with atomic_read from another thread. + Next, we have: #define atomic_read(v) ((v)->counter) -which simply reads the current value of the counter. - -Now, we move onto the actual atomic operation interfaces. +which simply reads the counter value currently visible to the calling thread. +The read is atomic in that the return value is guaranteed to be one of the +values initialized or modified with the interface operations if a proper +implicit or explicit memory barrier is used after possible runtime +initialization by any other thread and the value is modified only with the +interface operations. atomic_read does not guarantee that the runtime +initialization by any other thread is visible yet, so the user of the +interface must take care of that with a proper implicit or explicit memory +barrier. + +*** WARNING: atomic_read() and atomic_set() DO NOT IMPLY BARRIERS! *** + +Some architectures may choose to use the volatile keyword, barriers, or inline +assembly to guarantee some degree of immediacy for atomic_read() and +atomic_set(). This is not uniformly guaranteed, and may change in the future, +so all users of atomic_t should treat atomic_read() and atomic_set() as simple +C statements that may be reordered or optimized away entirely by the compiler +or processor, and explicitly invoke the appropriate compiler and/or memory +barrier for each use case. Failure to do so will result in code that may +suddenly break when used with different architectures or compiler +optimizations, or even changes in unrelated code which changes how the +compiler optimizes the section accessing atomic_t variables. + +*** YOU HAVE BEEN WARNED! *** + +Now, we move onto the atomic operation interfaces typically implemented with +the help of assembly code. void atomic_add(int i, atomic_t *v); void atomic_sub(int i, atomic_t *v); @@ -121,6 +160,12 @@ operation. Then: + int atomic_xchg(atomic_t *v, int new); + +This performs an atomic exchange operation on the atomic variable v, setting +the given new value. It returns the old value that the atomic variable v had +just before the operation. + int atomic_cmpxchg(atomic_t *v, int old, int new); This performs an atomic compare exchange operation on the atomic value v, |