* are synchronised without a lock, based on a cas of the top
* position. One reader wins, the others return NULL for a failure.
*
- * Both popBottom and steal also return NULL when the queue is empty.
+ * Both popWSDeque and stealWSDeque also return NULL when the queue is empty.
+ *
+ * Testing: see testsuite/tests/ghc-regress/rts/testwsdeque.c. If
+ * there's anything wrong with the deque implementation, this test
+ * will probably catch it.
*
* ---------------------------------------------------------------------------*/
b = q->bottom;
/* "decrement b as a test, see what happens" */
- q->bottom = --b;
+
+ b--;
+ q->bottom = b;
+
+ // very important that the following read of q->top does not occur
+ // before the earlier write to q->bottom.
+ store_load_barrier();
+
pos = (q->elements) + (b & (q->moduloSize));
t = q->top; /* using topBound would give an *upper* bound, we
need a lower bound. We use the real top here, but
can update the topBound value */
q->topBound = t;
- currSize = b - t;
+ currSize = (long)b - (long)t;
if (currSize < 0) { /* was empty before decrementing b, set b
consistently and abort */
q->bottom = t;
}
removed = *pos;
if (currSize > 0) { /* no danger, still elements in buffer after b-- */
+ // debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed);
return removed;
}
/* otherwise, has someone meanwhile stolen the same (last) element?
ASSERT_WSDEQUE_INVARIANTS(q);
ASSERT(q->bottom >= q->top);
+ // debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed);
+
return removed;
}
t = q->top;
// NB. b and t are unsigned; we need a signed value for the test
- // below.
+ // below, because it is possible that t > b during a
+ // concurrent popWSQueue() operation.
if ((long)b - (long)t <= 0 ) {
return NULL; /* already looks empty, abort */
}
return NULL;
} /* else: OK, top has been incremented by the cas call */
+ // debugBelch("stealWSDeque_: t=%d b=%d\n", t, b);
+
// Can't do this on someone else's spark pool:
// ASSERT_WSDEQUE_INVARIANTS(q);
return stolen;
}
+/* -----------------------------------------------------------------------------
+ * pushWSQueue
+ * -------------------------------------------------------------------------- */
#define DISCARD_NEW
}
pos = (q->elements) + (b & sz);
*pos = elem;
- (q->bottom)++;
+ q->bottom = b + 1;
ASSERT_WSDEQUE_INVARIANTS(q);
return rtsTrue;