Pseudocode from article of the above name, IJPP, August 1994. Michael L. Scott and John M. Mellor-Crummey. Inspired by an earlier paper on adaptive combining tree barriers by Gupta and Hill (IJPP, June 1989).
shared pseudodata : Boolean
type node = record
// Volatile fields may change spontaneously; there are no locks.
visitor : volatile ^Boolean := &pseudodata
// first process to visit this node; may be temporarily inconsistent,
// but will stabilize before being dereferenced
bin_left, bin_right, bin_parent : ^node := // tree
left, right, parent : volatile ^node := bin_left, bin_right, bin_parent
depth, inorder : integer := // as appropriate, in unmodified tree;
// inorder allows us to determine left and right descendancy.
type instance = record
f : Boolean := false
root, my_leaf, my_internal_node : ^node := // as appropriate, in tree
// my_internal_node is used only for reinitialization.
private instances : array [0..2] of instance
// separate copy for each process, but allocated
// in memory accessible to other processes
private current_instance : ^instance := &instances[0]
private previous_instance : ^instance := &instances[2]
procedure barrier ()
// find place to wait:
n : ^node := current_instance->my_leaf
loop
w : ^node := n->parent
if w = nil
// signal achievement of barrier:
current_instance->root->visitor^ := true
// may unblock a process at the spin below
goto rtn
x : ^node := fetch_and_store (&w->visitor, ¤t_instance->f)
if x = &pseudodata
exit loop
w->visitor := x // already visited; put it back
n := w // continue up the tree
// adapt tree:
if n->inorder < w->inorder
o : ^node := w->right
else
o : ^node := w->left
p : ^node := w->parent
if p = nil
o->parent := nil
else
// update down pointer:
if w->inorder < p->inorder
p->left := o
else
p->right := o
// update up pointer:
loop
t : ^node := fetch_and_store (&o->parent, p)
if t != nil and then (p = nil or else t->depth > p->depth)
exit loop // swap was a good thing
// else some other process linked o even higher in the tree;
// continue loop to undo our poorer update
p := t
// await notification and pass on the news:
repeat until current_instance->f // spin
// set at the root by line 7 of this procedure;
// set at other nodes by the code below
w->bin_left->visitor^ := true
w->bin_right->visitor^ := true
rtn:
reinitialize (previous_instance)
previous_instance := current_instance
if current_instance = &instances[2]
current_instance := &instances[0]
else
current_instance := current_instance + 1
NB: The termination test for the inner loop above differs from that published in the IJPP paper. The version here reflects a bug fix submitted by Alexander Malkis of the IMDEA Software Institute in March 2012.
shared pseudodata : ^node
type node = record
// Volatile fields may change spontaneously; there are no locks.
visited, notified : volatile Boolean := false, false
// visited = true iff some process has visited this node in
// enter_barrier.
// notified will eventually become true once the barrier is achieved.
owner : volatile ^node := // address of appropriate f field for leaves,
// &pseudodata for internal nodes
// address of f field of a recent visitor in exit_barrier
// (not necessarily the *most* recent)
bin_left, bin_right, bin_parent : ^node := // tree
depth, inorder : integer := // as appropriate, in unmodified tree;
// inorder allows us to determine left and right descendancy.
left, right, parent : volatile ^node := bin_left, bin_right, bin_parent
type instance = record
f : ^node := nil // node at which we were awakened
root, my_leaf, my_internal_node : ^node := // as appropriate, in tree
// my_internal_node is used only for reinitialization.
private instances : array [0..2] of instance
// separate copy for each process, but allocated
// in memory accessible to other processes
private current_instance : ^instance := &instances[0]
private previous_instance : ^instance := &instances[2]
procedure enter_barrier ()
n : ^node := current_instance->my_leaf
loop
w : ^node := n->parent
if w = nil
// signal achievement of barrier:
current_instance->root->notified := true
current_instance->root->owner^ := current_instance->root
// may unblock a process at the spin in exit_barrier,
// informing it that we woke it up at the root
return
if fetch_and_store (&n->visited, true) = false
exit loop
n := w // continue up the tree
// adapt tree:
if n->inorder < w->inorder
o : ^node := w->right
else
o : ^node := w->left
p : ^node := w->parent
if p = nil
o->parent := nil
else
// update down pointer:
if w->inorder < p^inorder
p->left := o
else
p->right := o
// update up pointer:
loop
t : ^node := fetch_and_store (&o->parent, p)
if t != nil and then t->depth > p->depth
exit loop // swap was a good thing
// else some other process linked o even higher in the tree;
// continue loop to undo our poorer update
p := t
procedure exit_barrier ()
n : ^node := current_instance->my_leaf
if n->notified
goto rtn
p : ^node := n->bin_parent
loop
if p->owner = &pseudodata
p->owner := ¤t_instance->f
if p->notified
exit loop
else if p->bin_parent = nil
repeat
p := current_instance->f
until p != nil // spin
// set at root by line 7 of enter_barrier;
// set at other nodes by the code below
exit loop
else
p := p->bin_parent
else if p->notified
exit loop
else
repeat
p := current_instance->f
until p != nil // spin
// set at root by line 7 of enter_barrier;
// set at other nodes by the code below
exit loop
// work way back down to leaf, giving notifications:
while p != current_instance->my_leaf
if n->inorder < p->inorder
o := p->bin_right
p := p->bin_left
else
o := p->bin_left
p := p->bin_right
o->notified := true
o->owner^ := o
// may unblock a process in the spin above,
// informing it that we woke it up at o
rtn:
reinitialize (previous_instance)
previous_instance := current_instance
if current_instance = &instances[2]
current_instance := &instances[0]
else
current_instance := current_instance + 1