Commit 952f622c authored by Austin Seipp's avatar Austin Seipp
Browse files

rts: detab/dewhitespace WSDeque.c


Signed-off-by: default avatarAustin Seipp <austin@well-typed.com>
parent cf2980cb
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* (c) The GHC Team, 2009 * (c) The GHC Team, 2009
* *
* Work-stealing Deque data structure * Work-stealing Deque data structure
* *
* The implementation uses Double-Ended Queues with lock-free access * The implementation uses Double-Ended Queues with lock-free access
* (thereby often called "deque") as described in * (thereby often called "deque") as described in
* *
...@@ -18,24 +18,24 @@ ...@@ -18,24 +18,24 @@
* array is accessed with indices modulo array-size. While this bears * array is accessed with indices modulo array-size. While this bears
* the risk of overflow, we assume that (with 64 bit indices), a * the risk of overflow, we assume that (with 64 bit indices), a
* program must run very long to reach that point. * program must run very long to reach that point.
* *
* The write end of the queue (position bottom) can only be used with * The write end of the queue (position bottom) can only be used with
* mutual exclusion, i.e. by exactly one caller at a time. At this * mutual exclusion, i.e. by exactly one caller at a time. At this
* end, new items can be enqueued using pushBottom()/newSpark(), and * end, new items can be enqueued using pushBottom()/newSpark(), and
* removed using popBottom()/reclaimSpark() (the latter implying a cas * removed using popBottom()/reclaimSpark() (the latter implying a cas
* synchronisation with potential concurrent readers for the case of * synchronisation with potential concurrent readers for the case of
* just one element). * just one element).
* *
* Multiple readers can steal from the read end (position top), and * Multiple readers can steal from the read end (position top), and
* are synchronised without a lock, based on a cas of the top * are synchronised without a lock, based on a cas of the top
* position. One reader wins, the others return NULL for a failure. * position. One reader wins, the others return NULL for a failure.
* *
* Both popWSDeque and stealWSDeque also return NULL when the queue is empty. * Both popWSDeque and stealWSDeque also return NULL when the queue is empty.
* *
* Testing: see testsuite/tests/rts/testwsdeque.c. If * Testing: see testsuite/tests/rts/testwsdeque.c. If
* there's anything wrong with the deque implementation, this test * there's anything wrong with the deque implementation, this test
* will probably catch it. * will probably catch it.
* *
* ---------------------------------------------------------------------------*/ * ---------------------------------------------------------------------------*/
#include "PosixSource.h" #include "PosixSource.h"
...@@ -56,7 +56,7 @@ static StgWord ...@@ -56,7 +56,7 @@ static StgWord
roundUp2(StgWord val) roundUp2(StgWord val)
{ {
StgWord rounded = 1; StgWord rounded = 1;
/* StgWord is unsigned anyway, only catch 0 */ /* StgWord is unsigned anyway, only catch 0 */
if (val == 0) { if (val == 0) {
barf("DeQue,roundUp2: invalid size 0 requested"); barf("DeQue,roundUp2: invalid size 0 requested");
...@@ -71,11 +71,11 @@ roundUp2(StgWord val) ...@@ -71,11 +71,11 @@ roundUp2(StgWord val)
WSDeque * WSDeque *
newWSDeque (nat size) newWSDeque (nat size)
{ {
StgWord realsize; StgWord realsize;
WSDeque *q; WSDeque *q;
realsize = roundUp2(size); /* to compute modulo as a bitwise & */ realsize = roundUp2(size); /* to compute modulo as a bitwise & */
q = (WSDeque*) stgMallocBytes(sizeof(WSDeque), /* admin fields */ q = (WSDeque*) stgMallocBytes(sizeof(WSDeque), /* admin fields */
"newWSDeque"); "newWSDeque");
q->elements = stgMallocBytes(realsize * sizeof(StgClosurePtr), /* dataspace */ q->elements = stgMallocBytes(realsize * sizeof(StgClosurePtr), /* dataspace */
...@@ -83,11 +83,11 @@ newWSDeque (nat size) ...@@ -83,11 +83,11 @@ newWSDeque (nat size)
q->top=0; q->top=0;
q->bottom=0; q->bottom=0;
q->topBound=0; /* read by writer, updated each time top is read */ q->topBound=0; /* read by writer, updated each time top is read */
q->size = realsize; /* power of 2 */ q->size = realsize; /* power of 2 */
q->moduloSize = realsize - 1; /* n % size == n & moduloSize */ q->moduloSize = realsize - 1; /* n % size == n & moduloSize */
ASSERT_WSDEQUE_INVARIANTS(q); ASSERT_WSDEQUE_INVARIANTS(q);
return q; return q;
} }
...@@ -103,7 +103,7 @@ freeWSDeque (WSDeque *q) ...@@ -103,7 +103,7 @@ freeWSDeque (WSDeque *q)
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* *
* popWSDeque: remove an element from the write end of the queue. * popWSDeque: remove an element from the write end of the queue.
* Returns the removed spark, and NULL if a race is lost or the pool * Returns the removed spark, and NULL if a race is lost or the pool
* empty. * empty.
...@@ -123,9 +123,9 @@ popWSDeque (WSDeque *q) ...@@ -123,9 +123,9 @@ popWSDeque (WSDeque *q)
StgWord t, b; StgWord t, b;
long currSize; long currSize;
void * removed; void * removed;
ASSERT_WSDEQUE_INVARIANTS(q); ASSERT_WSDEQUE_INVARIANTS(q);
b = q->bottom; b = q->bottom;
// "decrement b as a test, see what happens" // "decrement b as a test, see what happens"
...@@ -153,7 +153,7 @@ popWSDeque (WSDeque *q) ...@@ -153,7 +153,7 @@ popWSDeque (WSDeque *q)
if (currSize > 0) { /* no danger, still elements in buffer after b-- */ if (currSize > 0) { /* no danger, still elements in buffer after b-- */
// debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed); // debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed);
return removed; return removed;
} }
/* otherwise, has someone meanwhile stolen the same (last) element? /* otherwise, has someone meanwhile stolen the same (last) element?
Check and increment top value to know */ Check and increment top value to know */
if ( !(CASTOP(&(q->top),t,t+1)) ) { if ( !(CASTOP(&(q->top),t,t+1)) ) {
...@@ -161,10 +161,10 @@ popWSDeque (WSDeque *q) ...@@ -161,10 +161,10 @@ popWSDeque (WSDeque *q)
} }
q->bottom = t+1; /* anyway, empty now. Adjust bottom consistently. */ q->bottom = t+1; /* anyway, empty now. Adjust bottom consistently. */
q->topBound = t+1; /* ...and cached top value as well */ q->topBound = t+1; /* ...and cached top value as well */
ASSERT_WSDEQUE_INVARIANTS(q); ASSERT_WSDEQUE_INVARIANTS(q);
ASSERT(q->bottom >= q->top); ASSERT(q->bottom >= q->top);
// debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed); // debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed);
return removed; return removed;
...@@ -178,27 +178,27 @@ void * ...@@ -178,27 +178,27 @@ void *
stealWSDeque_ (WSDeque *q) stealWSDeque_ (WSDeque *q)
{ {
void * stolen; void * stolen;
StgWord b,t; StgWord b,t;
// Can't do this on someone else's spark pool: // Can't do this on someone else's spark pool:
// ASSERT_WSDEQUE_INVARIANTS(q); // ASSERT_WSDEQUE_INVARIANTS(q);
// NB. these loads must be ordered, otherwise there is a race // NB. these loads must be ordered, otherwise there is a race
// between steal and pop. // between steal and pop.
t = q->top; t = q->top;
load_load_barrier(); load_load_barrier();
b = q->bottom; b = q->bottom;
// NB. b and t are unsigned; we need a signed value for the test // NB. b and t are unsigned; we need a signed value for the test
// below, because it is possible that t > b during a // below, because it is possible that t > b during a
// concurrent popWSQueue() operation. // concurrent popWSQueue() operation.
if ((long)b - (long)t <= 0 ) { if ((long)b - (long)t <= 0 ) {
return NULL; /* already looks empty, abort */ return NULL; /* already looks empty, abort */
} }
/* now access array, see pushBottom() */ /* now access array, see pushBottom() */
stolen = q->elements[t & q->moduloSize]; stolen = q->elements[t & q->moduloSize];
/* now decide whether we have won */ /* now decide whether we have won */
if ( !(CASTOP(&(q->top),t,t+1)) ) { if ( !(CASTOP(&(q->top),t,t+1)) ) {
/* lost the race, someon else has changed top in the meantime */ /* lost the race, someon else has changed top in the meantime */
...@@ -208,8 +208,8 @@ stealWSDeque_ (WSDeque *q) ...@@ -208,8 +208,8 @@ stealWSDeque_ (WSDeque *q)
// debugBelch("stealWSDeque_: t=%d b=%d\n", t, b); // debugBelch("stealWSDeque_: t=%d b=%d\n", t, b);
// Can't do this on someone else's spark pool: // Can't do this on someone else's spark pool:
// ASSERT_WSDEQUE_INVARIANTS(q); // ASSERT_WSDEQUE_INVARIANTS(q);
return stolen; return stolen;
} }
...@@ -217,11 +217,11 @@ void * ...@@ -217,11 +217,11 @@ void *
stealWSDeque (WSDeque *q) stealWSDeque (WSDeque *q)
{ {
void *stolen; void *stolen;
do { do {
stolen = stealWSDeque_(q); stolen = stealWSDeque_(q);
} while (stolen == NULL && !looksEmptyWSDeque(q)); } while (stolen == NULL && !looksEmptyWSDeque(q));
return stolen; return stolen;
} }
...@@ -238,17 +238,17 @@ pushWSDeque (WSDeque* q, void * elem) ...@@ -238,17 +238,17 @@ pushWSDeque (WSDeque* q, void * elem)
{ {
StgWord t; StgWord t;
StgWord b; StgWord b;
StgWord sz = q->moduloSize; StgWord sz = q->moduloSize;
ASSERT_WSDEQUE_INVARIANTS(q); ASSERT_WSDEQUE_INVARIANTS(q);
/* we try to avoid reading q->top (accessed by all) and use /* we try to avoid reading q->top (accessed by all) and use
q->topBound (accessed only by writer) instead. q->topBound (accessed only by writer) instead.
This is why we do not just call empty(q) here. This is why we do not just call empty(q) here.
*/ */
b = q->bottom; b = q->bottom;
t = q->topBound; t = q->topBound;
if ( (StgInt)b - (StgInt)t >= (StgInt)sz ) { if ( (StgInt)b - (StgInt)t >= (StgInt)sz ) {
/* NB. 1. sz == q->size - 1, thus ">=" /* NB. 1. sz == q->size - 1, thus ">="
2. signed comparison, it is possible that t > b 2. signed comparison, it is possible that t > b
*/ */
...@@ -260,20 +260,20 @@ pushWSDeque (WSDeque* q, void * elem) ...@@ -260,20 +260,20 @@ pushWSDeque (WSDeque* q, void * elem)
will in the meantime use the old one and modify only top. will in the meantime use the old one and modify only top.
This means: we cannot safely free the old space! Can keep it This means: we cannot safely free the old space! Can keep it
on a free list internally here... on a free list internally here...
Potential bug in combination with steal(): if array is Potential bug in combination with steal(): if array is
replaced, it is unclear which one concurrent steal operations replaced, it is unclear which one concurrent steal operations
use. Must read the array base address in advance in steal(). use. Must read the array base address in advance in steal().
*/ */
#if defined(DISCARD_NEW) #if defined(DISCARD_NEW)
ASSERT_WSDEQUE_INVARIANTS(q); ASSERT_WSDEQUE_INVARIANTS(q);
return rtsFalse; // we didn't push anything return rtsFalse; // we didn't push anything
#else #else
/* could make room by incrementing the top position here. In /* could make room by incrementing the top position here. In
* this case, should use CASTOP. If this fails, someone else has * this case, should use CASTOP. If this fails, someone else has
* removed something, and new room will be available. * removed something, and new room will be available.
*/ */
ASSERT_WSDEQUE_INVARIANTS(q); ASSERT_WSDEQUE_INVARIANTS(q);
#endif #endif
} }
} }
...@@ -289,7 +289,7 @@ pushWSDeque (WSDeque* q, void * elem) ...@@ -289,7 +289,7 @@ pushWSDeque (WSDeque* q, void * elem)
*/ */
write_barrier(); write_barrier();
q->bottom = b + 1; q->bottom = b + 1;
ASSERT_WSDEQUE_INVARIANTS(q); ASSERT_WSDEQUE_INVARIANTS(q);
return rtsTrue; return rtsTrue;
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment