* (d) release the locks on the TVars, writing updates to them in the case of a
* commit, (e) unlock the STM.
*
- * Queues of waiting threads hang off the first_watch_queue_entry field of each
- * TVar. This may only be manipulated when holding that TVar's lock. In
- * particular, when a thread is putting itself to sleep, it mustn't release
- * the TVar's lock until it has added itself to the wait queue and marked its
- * TSO as BlockedOnSTM -- this makes sure that other threads will know to wake it.
+ * Queues of waiting threads hang off the first_watch_queue_entry
+ * field of each TVar. This may only be manipulated when holding that
+ * TVar's lock. In particular, when a thread is putting itself to
+ * sleep, it mustn't release the TVar's lock until it has added itself
+ * to the wait queue and marked its TSO as BlockedOnSTM -- this makes
+ * sure that other threads will know to wake it.
*
* ---------------------------------------------------------------------------*/
#include "PosixSource.h"
#include "Rts.h"
-#include "RtsFlags.h"
+
#include "RtsUtils.h"
-#include "Storage.h"
#include "Schedule.h"
-#include "SMP.h"
#include "STM.h"
#include "Trace.h"
+#include "Threads.h"
-#include <stdlib.h>
#include <stdio.h>
#define TRUE 1
do {
do {
result = s -> current_value;
- } while (GET_INFO(result) == &stg_TREC_HEADER_info);
+ } while (GET_INFO(UNTAG_CLOSURE(result)) == &stg_TREC_HEADER_info);
} while (cas((void *)&(s -> current_value),
(StgWord)result, (StgWord)trec) != (StgWord)result);
return result;
static void unpark_waiters_on(Capability *cap, StgTVar *s) {
StgTVarWatchQueue *q;
+ StgTVarWatchQueue *trail;
TRACE("unpark_waiters_on tvar=%p", s);
- for (q = s -> first_watch_queue_entry;
- q != END_STM_WATCH_QUEUE;
+ // unblock TSOs in reverse order, to be a bit fairer (#2319)
+ for (q = s -> first_watch_queue_entry, trail = q;
+ q != END_STM_WATCH_QUEUE;
q = q -> next_queue_entry) {
+ trail = q;
+ }
+ q = trail;
+ for (;
+ q != END_STM_WATCH_QUEUE;
+ q = q -> prev_queue_entry) {
if (watcher_is_tso(q)) {
unpark_tso(cap, (StgTSO *)(q -> closure));
}
static StgInvariantCheckQueue *new_stg_invariant_check_queue(Capability *cap,
StgAtomicInvariant *invariant) {
StgInvariantCheckQueue *result;
- result = (StgInvariantCheckQueue *)allocateLocal(cap, sizeofW(StgInvariantCheckQueue));
+ result = (StgInvariantCheckQueue *)allocate(cap, sizeofW(StgInvariantCheckQueue));
SET_HDR (result, &stg_INVARIANT_CHECK_QUEUE_info, CCS_SYSTEM);
result -> invariant = invariant;
result -> my_execution = NO_TREC;
static StgTVarWatchQueue *new_stg_tvar_watch_queue(Capability *cap,
StgClosure *closure) {
StgTVarWatchQueue *result;
- result = (StgTVarWatchQueue *)allocateLocal(cap, sizeofW(StgTVarWatchQueue));
+ result = (StgTVarWatchQueue *)allocate(cap, sizeofW(StgTVarWatchQueue));
SET_HDR (result, &stg_TVAR_WATCH_QUEUE_info, CCS_SYSTEM);
result -> closure = closure;
return result;
static StgTRecChunk *new_stg_trec_chunk(Capability *cap) {
StgTRecChunk *result;
- result = (StgTRecChunk *)allocateLocal(cap, sizeofW(StgTRecChunk));
+ result = (StgTRecChunk *)allocate(cap, sizeofW(StgTRecChunk));
SET_HDR (result, &stg_TREC_CHUNK_info, CCS_SYSTEM);
result -> prev_chunk = END_STM_CHUNK_LIST;
result -> next_entry_idx = 0;
static StgTRecHeader *new_stg_trec_header(Capability *cap,
StgTRecHeader *enclosing_trec) {
StgTRecHeader *result;
- result = (StgTRecHeader *) allocateLocal(cap, sizeofW(StgTRecHeader));
+ result = (StgTRecHeader *) allocate(cap, sizeofW(StgTRecHeader));
SET_HDR (result, &stg_TREC_HEADER_info, CCS_SYSTEM);
result -> enclosing_trec = enclosing_trec;
/*......................................................................*/
-StgTRecHeader *stmGetEnclosingTRec(StgTRecHeader *trec) {
- StgTRecHeader *outer;
- TRACE("%p : stmGetEnclosingTRec", trec);
- outer = trec -> enclosing_trec;
- TRACE("%p : stmGetEnclosingTRec()=%p", trec, outer);
- return outer;
-}
-
-/*......................................................................*/
-
StgBool stmValidateNestOfTransactions(StgTRecHeader *trec) {
StgTRecHeader *t;
StgBool result;
// 1. Allocate an StgAtomicInvariant, set last_execution to NO_TREC
// to signal that this is a new invariant in the current atomic block
- invariant = (StgAtomicInvariant *) allocateLocal(cap, sizeofW(StgAtomicInvariant));
+ invariant = (StgAtomicInvariant *) allocate(cap, sizeofW(StgAtomicInvariant));
TRACE("%p : stmAddInvariantToCheck allocated invariant=%p", trec, invariant);
SET_HDR (invariant, &stg_ATOMIC_INVARIANT_info, CCS_SYSTEM);
invariant -> code = code;
result = tvar -> current_value;
#if defined(STM_FG_LOCKS)
- while (GET_INFO(result) == &stg_TREC_HEADER_info) {
+ while (GET_INFO(UNTAG_CLOSURE(result)) == &stg_TREC_HEADER_info) {
TRACE("%p : read_current_value(%p) saw %p", trec, tvar, result);
result = tvar -> current_value;
}
StgTVar *stmNewTVar(Capability *cap,
StgClosure *new_value) {
StgTVar *result;
- result = (StgTVar *)allocateLocal(cap, sizeofW(StgTVar));
+ result = (StgTVar *)allocate(cap, sizeofW(StgTVar));
SET_HDR (result, &stg_TVAR_info, CCS_SYSTEM);
result -> current_value = new_value;
result -> first_watch_queue_entry = END_STM_WATCH_QUEUE;