On sparc, pass -mcpu=v9 when assembling with object splitting enabled
[ghc-hetmet.git] / rts / parallel / WSDeque.c
index ec34a8c..4ae9417 100644 (file)
  * 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.
  * 
  * ---------------------------------------------------------------------------*/
 
@@ -126,13 +130,20 @@ popWSDeque (WSDeque *q)
     
     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;
@@ -140,6 +151,7 @@ popWSDeque (WSDeque *q)
     }
     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?
@@ -153,6 +165,8 @@ popWSDeque (WSDeque *q)
     ASSERT_WSDEQUE_INVARIANTS(q); 
     ASSERT(q->bottom >= q->top);
     
+    // debugBelch("popWSDeque: t=%ld b=%ld = %ld\n", t, b, removed);
+
     return removed;
 }
 
@@ -176,7 +190,8 @@ stealWSDeque_ (WSDeque *q)
     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 */
   }
@@ -193,6 +208,8 @@ stealWSDeque_ (WSDeque *q)
         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); 
     
@@ -211,6 +228,9 @@ stealWSDeque (WSDeque *q)
     return stolen;
 }
 
+/* -----------------------------------------------------------------------------
+ * pushWSQueue
+ * -------------------------------------------------------------------------- */
 
 #define DISCARD_NEW
 
@@ -262,7 +282,7 @@ pushWSDeque (WSDeque* q, void * elem)
     }
     pos = (q->elements) + (b & sz);
     *pos = elem;
-    (q->bottom)++;
+    q->bottom = b + 1;
     
     ASSERT_WSDEQUE_INVARIANTS(q); 
     return rtsTrue;