-freeSparkPool(SparkPool *pool) {
- /* 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(cap): 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(Capability *cap) {
- SparkPool *deque = cap->sparks;
- /* 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;
-}
-
-/* -----------------------------------------------------------------------------
- *
- * findSpark: find a spark on the current Capability that we can fork
- * into a thread.
- *
- * May be called by concurrent threads, which synchronise on top
- * variable. Returns a spark, or NULL if pool empty or race lost.
- *
- -------------------------------------------------------------------------- */
-
-StgClosurePtr steal(SparkPool *deque);
-
-/* steal an element from the read end. Synchronises multiple callers
- by failing with NULL return. Returns NULL when deque is empty. */
-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 */
- stolen = NULL;
- } /* else: OK, top has been incremented by the cas call */
-
-
- ASSERT_SPARK_POOL_INVARIANTS(deque);
- /* return NULL or stolen element */
- return stolen;
-}
-
-StgClosure *
-findSpark (Capability *cap)