Blame doc/README_stack.txt

Packit fe9d6e
Note that the AO_stack implementation is licensed under the GPL,
Packit fe9d6e
unlike the lower level routines.
Packit fe9d6e
Packit fe9d6e
The header file atomic_ops_stack.h defines a linked stack abstraction.
Packit fe9d6e
Stacks may be accessed by multiple concurrent threads.  The implementation
Packit fe9d6e
is 1-lock-free, i.e. it will continue to make progress if at most one
Packit fe9d6e
thread becomes inactive while operating on the data structure.
Packit fe9d6e
Packit fe9d6e
(The implementation can be built to be N-lock-free for any given N.  But that
Packit fe9d6e
seems to rarely be useful, especially since larger N involve some slowdown.)
Packit fe9d6e
Packit fe9d6e
This makes it safe to access these data structures from non-reentrant
Packit fe9d6e
signal handlers, provided at most one non-signal-handler thread is
Packit fe9d6e
accessing the data structure at once.  This latter condition can be
Packit fe9d6e
ensured by acquiring an ordinary lock around the non-handler accesses
Packit fe9d6e
to the data structure.
Packit fe9d6e
Packit fe9d6e
For details see:
Packit fe9d6e
Packit fe9d6e
Hans-J. Boehm, "An Almost Non-Blocking Stack", PODC 2004,
Packit fe9d6e
http://portal.acm.org/citation.cfm?doid=1011767.1011774
Packit fe9d6e
(This is not exactly the implementation described there, since the
Packit fe9d6e
interface was cleaned up in the interim.  But it should perform
Packit fe9d6e
very similarly.)
Packit fe9d6e
Packit fe9d6e
We use a fully lock-free implementation when the underlying hardware
Packit fe9d6e
makes that less expensive, i.e. when we have a double-wide compare-and-swap
Packit fe9d6e
operation available.  (The fully lock-free implementation uses an AO_t-
Packit fe9d6e
sized version count, and assumes it does not wrap during the time any
Packit fe9d6e
given operation is active.  This seems reasonably safe on 32-bit hardware,
Packit fe9d6e
and very safe on 64-bit hardware.) If a fully lock-free implementation
Packit fe9d6e
is used, the macro AO_STACK_IS_LOCK_FREE will be defined.
Packit fe9d6e
Packit fe9d6e
The implementation is interesting only because it allows reuse of
Packit fe9d6e
existing nodes.  This is necessary, for example, to implement a memory
Packit fe9d6e
allocator.
Packit fe9d6e
Packit fe9d6e
Since we want to leave the precise stack node type up to the client,
Packit fe9d6e
we insist only that each stack node contains a link field of type AO_t.
Packit fe9d6e
When a new node is pushed on the stack, the push operation expects to be
Packit fe9d6e
passed the pointer to this link field, which will then be overwritten by
Packit fe9d6e
this link field.  Similarly, the pop operation returns a pointer to the
Packit fe9d6e
link field of the object that previously was on the top of the stack.
Packit fe9d6e
Packit fe9d6e
The cleanest way to use these routines is probably to define the stack node
Packit fe9d6e
type with an initial AO_t link field, so that the conversion between the
Packit fe9d6e
link-field pointer and the stack element pointer is just a compile-time
Packit fe9d6e
cast.  But other possibilities exist.  (This would be cleaner in C++ with
Packit fe9d6e
templates.)
Packit fe9d6e
Packit fe9d6e
A stack is represented by an AO_stack_t structure.  (This is normally
Packit fe9d6e
2 or 3 times the size of a pointer.)  It may be statically initialized
Packit fe9d6e
by setting it to AO_STACK_INITIALIZER, or dynamically initialized to
Packit fe9d6e
an empty stack with AO_stack_init.  There are only three operations for
Packit fe9d6e
accessing stacks:
Packit fe9d6e
Packit fe9d6e
void AO_stack_init(AO_stack_t *list);
Packit fe9d6e
void AO_stack_push_release(AO_stack_t *list, AO_t *new_element);
Packit fe9d6e
AO_t * AO_stack_pop_acquire(volatile AO_stack_t *list);
Packit fe9d6e
Packit fe9d6e
We require that the objects pushed as list elements remain addressable
Packit fe9d6e
as long as any push or pop operation are in progress.  (It is OK for an object
Packit fe9d6e
to be "pop"ped off a stack and "deallocated" with a concurrent "pop" on
Packit fe9d6e
the same stack still in progress, but only if "deallocation" leaves the
Packit fe9d6e
object addressable.  The second "pop" may still read the object, but
Packit fe9d6e
the value it reads will not matter.)
Packit fe9d6e
Packit fe9d6e
We require that the headers (AO_stack objects) remain allocated and
Packit fe9d6e
valid as long as any operations on them are still in-flight.
Packit fe9d6e
Packit fe9d6e
We also provide macros AO_REAL_HEAD_PTR that converts an AO_stack_t
Packit fe9d6e
to a pointer to the link field in the next element, and AO_REAL_NEXT_PTR
Packit fe9d6e
that converts a link field to a real, dereferencable, pointer to the link field
Packit fe9d6e
in the next element.  This is intended only for debugging, or to traverse
Packit fe9d6e
the list after modification has ceased.  There is otherwise no guarantee that
Packit fe9d6e
walking a stack using this macro will produce any kind of consistent
Packit fe9d6e
picture of the data structure.