From 8d7b52dfc9b0c672a3c39a82b896c8eedabb2a63 Mon Sep 17 00:00:00 2001 From: Matti Linnanvuori Date: Tue, 16 Oct 2007 23:30:08 -0700 Subject: [PATCH] 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 Cc: Nick Piggin Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/atomic_ops.txt | 55 ++++++++++++++++++++++++++++++++---- 1 file 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, -- 2.20.1