Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 70688
b: refs/heads/master
c: 8d7b52d
h: refs/heads/master
v: v3
  • Loading branch information
Matti Linnanvuori authored and Linus Torvalds committed Oct 17, 2007
1 parent 4fb2f7d commit ed43139
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5f519d728169fa9975bcba001de425f11e18e8e3
refs/heads/master: 8d7b52dfc9b0c672a3c39a82b896c8eedabb2a63
55 changes: 50 additions & 5 deletions trunk/Documentation/atomic_ops.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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; };
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit ed43139

Please sign in to comment.