Do not link ghc stage1 using -threaded, only for stage2 or 3
[ghc-hetmet.git] / rts / parallel / WSDeque.c
index e7fd58a..acecb85 100644 (file)
@@ -43,8 +43,6 @@
 #include "WSDeque.h"
 #include "SMP.h" // for cas
 
-#if defined(THREADED_RTS)
-
 #define CASTOP(addr,old,new) ((old) == cas(((StgPtr)addr),(old),(new)))
 
 /* -----------------------------------------------------------------------------
@@ -122,27 +120,35 @@ popWSDeque (WSDeque *q)
     /* also a bit tricky, has to avoid concurrent steal() calls by
        accessing top with cas, when there is only one element left */
     StgWord t, b;
-    void ** pos;
     long  currSize;
     void * removed;
     
     ASSERT_WSDEQUE_INVARIANTS(q); 
     
     b = q->bottom;
-    /* "decrement b as a test, see what happens" */
-    q->bottom = --b; 
-    pos = (q->elements) + (b & (q->moduloSize));
+
+    // "decrement b as a test, see what happens"
+    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();
+
     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;
         return NULL;
     }
-    removed = *pos;
+
+    // read the element at b
+    removed = q->elements[b & q->moduloSize];
+
     if (currSize > 0) { /* no danger, still elements in buffer after b-- */
         // debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed);
         return removed;
@@ -170,17 +176,17 @@ popWSDeque (WSDeque *q)
 void *
 stealWSDeque_ (WSDeque *q)
 {
-    void ** pos;
-    void ** arraybase;
-    StgWord sz;
     void * stolen;
     StgWord b,t; 
     
 // Can't do this on someone else's spark pool:
 // ASSERT_WSDEQUE_INVARIANTS(q); 
     
-    b = q->bottom;
+    // NB. these loads must be ordered, otherwise there is a race
+    // between steal and pop.
     t = q->top;
+    load_load_barrier();
+    b = q->bottom;
     
     // NB. b and t are unsigned; we need a signed value for the test
     // below, because it is possible that t > b during a
@@ -190,10 +196,7 @@ stealWSDeque_ (WSDeque *q)
   }
     
     /* now access array, see pushBottom() */
-    arraybase = q->elements;
-    sz = q->moduloSize;
-    pos = arraybase + (t & sz);  
-    stolen = *pos;
+    stolen = q->elements[t & q->moduloSize];
     
     /* now decide whether we have won */
     if ( !(CASTOP(&(q->top),t,t+1)) ) {
@@ -233,9 +236,8 @@ rtsBool
 pushWSDeque (WSDeque* q, void * elem)
 {
     StgWord t;
-    void ** pos;
+    StgWord b;
     StgWord sz = q->moduloSize; 
-    StgWord b = q->bottom;
     
     ASSERT_WSDEQUE_INVARIANTS(q); 
     
@@ -243,6 +245,7 @@ pushWSDeque (WSDeque* q, void * elem)
        q->topBound (accessed only by writer) instead. 
        This is why we do not just call empty(q) here.
     */
+    b = q->bottom;
     t = q->topBound;
     if ( (StgInt)b - (StgInt)t >= (StgInt)sz ) { 
         /* NB. 1. sz == q->size - 1, thus ">="
@@ -273,12 +276,10 @@ pushWSDeque (WSDeque* q, void * elem)
 #endif
         }
     }
-    pos = (q->elements) + (b & sz);
-    *pos = elem;
-    (q->bottom)++;
+
+    q->elements[b & sz] = elem;
+    q->bottom = b + 1;
     
     ASSERT_WSDEQUE_INVARIANTS(q); 
     return rtsTrue;
 }
-
-#endif