- /* should not interfere with concurrent findSpark() calls! And
- nobody should use the pointer any more. We cross our fingers...*/
- stgFree(pool->elements);
- stgFree(pool);
-}
-
-/* -----------------------------------------------------------------------------
- *
- * reclaimSpark: remove a spark from the write end of the queue.
- * Returns the removed spark, and NULL if a race is lost or the pool
- * empty.
- *
- * If only one spark is left in the pool, we synchronise with
- * concurrently stealing threads by using cas to modify the top field.
- * This routine should NEVER be called by a task which does not own
- * the capability. Can this be checked here?
- *
- * -------------------------------------------------------------------------- */
-
-StgClosure *
-reclaimSpark (SparkPool *deque)
-{
- /* 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;
- StgClosurePtr* pos;
- long currSize;
- StgClosurePtr removed;
-
- ASSERT_SPARK_POOL_INVARIANTS(deque);
-
- b = deque->bottom;
- /* "decrement b as a test, see what happens" */
- deque->bottom = --b;
- pos = (deque->elements) + (b & (deque->moduloSize));
- t = deque->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 */
- deque->topBound = t;
- currSize = b - t;
- if (currSize < 0) { /* was empty before decrementing b, set b
- consistently and abort */
- deque->bottom = t;
- return NULL;
- }
- removed = *pos;
- if (currSize > 0) { /* no danger, still elements in buffer after b-- */
- return removed;
- }
- /* otherwise, has someone meanwhile stolen the same (last) element?
- Check and increment top value to know */
- if ( !(CASTOP(&(deque->top),t,t+1)) ) {
- removed = NULL; /* no success, but continue adjusting bottom */
- }
- deque->bottom = t+1; /* anyway, empty now. Adjust bottom consistently. */
- deque->topBound = t+1; /* ...and cached top value as well */
-
- ASSERT_SPARK_POOL_INVARIANTS(deque);
-
- return removed;
-}
-
-/* -----------------------------------------------------------------------------
- *
- * tryStealSpark: try to steal a spark from a Capability.
- *
- * Returns a valid spark, or NULL if the pool was empty, and can
- * occasionally return NULL if there was a race with another thread
- * stealing from the same pool. In this case, try again later.
- *
- -------------------------------------------------------------------------- */
-
-static StgClosurePtr
-steal(SparkPool *deque)
-{
- StgClosurePtr* pos;
- StgClosurePtr* arraybase;
- StgWord sz;
- StgClosurePtr stolen;
- StgWord b,t;
-
- ASSERT_SPARK_POOL_INVARIANTS(deque);
-
- b = deque->bottom;
- t = deque->top;
- if (b - t <= 0 ) {
- return NULL; /* already looks empty, abort */
- }
-
- /* now access array, see pushBottom() */
- arraybase = deque->elements;
- sz = deque->moduloSize;
- pos = arraybase + (t & sz);
- stolen = *pos;
-
- /* now decide whether we have won */
- if ( !(CASTOP(&(deque->top),t,t+1)) ) {
- /* lost the race, someon else has changed top in the meantime */
- return NULL;
- } /* else: OK, top has been incremented by the cas call */
-
- ASSERT_SPARK_POOL_INVARIANTS(deque);
- /* return stolen element */
- return stolen;
-}
-
-StgClosure *
-tryStealSpark (SparkPool *pool)
-{
- StgClosure *stolen;
-
- do {
- stolen = steal(pool);
- } while (stolen != NULL && !closure_SHOULD_SPARK(stolen));
-
- return stolen;
-}
-
-
-/* -----------------------------------------------------------------------------
- *
- * "guesses" whether a deque is empty. Can return false negatives in
- * presence of concurrent steal() calls, and false positives in
- * presence of a concurrent pushBottom().
- *
- * -------------------------------------------------------------------------- */
-
-rtsBool
-looksEmpty(SparkPool* deque)
-{
- StgWord t = deque->top;
- StgWord b = deque->bottom;
- /* try to prefer false negatives by reading top first */
- return (b - t <= 0);
- /* => array is *never* completely filled, always 1 place free! */