Remove SMP-only fields from STM data structures from non-SMP builds
StgHeader header;
StgClosure *volatile current_value;
StgTVarWaitQueue *volatile first_wait_queue_entry;
StgHeader header;
StgClosure *volatile current_value;
StgTVarWaitQueue *volatile first_wait_queue_entry;
struct StgTRecHeader_ *volatile last_update_by;
struct StgTRecHeader_ *volatile last_update_by;
} StgTVar;
/* new_value == expected_value for read-only accesses */
} StgTVar;
/* new_value == expected_value for read-only accesses */
StgTVar *tvar;
StgClosure *expected_value;
StgClosure *new_value;
StgTVar *tvar;
StgClosure *expected_value;
StgClosure *new_value;
struct StgTRecHeader_ *saw_update_by;
struct StgTRecHeader_ *saw_update_by;
} TRecEntry;
#define TREC_CHUNK_NUM_ENTRIES 256
} TRecEntry;
#define TREC_CHUNK_NUM_ENTRIES 256
/*----------------------------------------------------------------------
/*----------------------------------------------------------------------
+ TVar management operations
+ --------------------------
+*/
+
+extern StgTVar *stmNewTVar(StgRegTable *reg,
+ StgClosure *new_value);
+
+/*----------------------------------------------------------------------
+
Data access operations
----------------------
*/
Data access operations
----------------------
*/
closure_field(StgMVar,tail);
closure_field(StgMVar,value);
closure_field(StgMVar,tail);
closure_field(StgMVar,value);
- closure_size(StgTVar);
- closure_field(StgTVar,current_value);
- closure_field(StgTVar,first_wait_queue_entry);
- closure_field(StgTVar,last_update_by);
-
closure_size(StgBCO);
closure_field(StgBCO, instrs);
closure_field(StgBCO, literals);
closure_size(StgBCO);
closure_field(StgBCO, instrs);
closure_field(StgBCO, literals);
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
p += sizeofW(StgTVar);
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
p += sizeofW(StgTVar);
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
break;
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
break;
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
evac_gen = 0;
tvar->current_value = evacuate((StgClosure*)tvar->current_value);
tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
tvar->last_update_by = (StgTRecHeader *)evacuate((StgClosure*)tvar->last_update_by);
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
break;
evac_gen = saved_evac_gen;
failed_to_evac = rtsTrue; // mutable
break;
StgTVar *tvar = (StgTVar *)p;
thread((StgPtr)&tvar->current_value);
thread((StgPtr)&tvar->first_wait_queue_entry);
StgTVar *tvar = (StgTVar *)p;
thread((StgPtr)&tvar->current_value);
thread((StgPtr)&tvar->first_wait_queue_entry);
thread((StgPtr)&tvar->last_update_by);
thread((StgPtr)&tvar->last_update_by);
return p + sizeofW(StgTVar);
}
return p + sizeofW(StgTVar);
}
/* Args: R1 = initialisation value */
/* Args: R1 = initialisation value */
- ALLOC_PRIM( SIZEOF_StgTVar, R1_PTR, newTVarzh_fast);
- tv = Hp - SIZEOF_StgTVar + WDS(1);
- SET_HDR(tv,stg_TVAR_info,W_[CCCS]);
- StgTVar_current_value(tv) = R1;
- StgTVar_first_wait_queue_entry(tv) = stg_END_STM_WAIT_QUEUE_closure;
-#if defined(SMP)
- trec = StgTSO_trec(CurrentTSO);
- StgTVar_last_update_by(tv) = trec;
-#else
- StgTVar_last_update_by(tv) = NO_TREC;
-#endif
-
+ MAYBE_GC (R1_PTR, newTVarzh_fast);
+ new_value = R1;
+ tv = foreign "C" stmNewTVar(BaseReg "ptr", new_value "ptr");
/*......................................................................*/
/*......................................................................*/
+#define IF_STM_UNIPROC(__X) do { } while (0)
+#define IF_STM_CG_LOCK(__X) do { } while (0)
+#define IF_STM_FG_LOCKS(__X) do { } while (0)
+
+#undef IF_STM_UNIPROC
+#define IF_STM_UNIPROC(__X) do { __X } while (0)
static const StgBool use_read_phase = FALSE;
static void lock_stm(StgTRecHeader *trec STG_UNUSED) {
static const StgBool use_read_phase = FALSE;
static void lock_stm(StgTRecHeader *trec STG_UNUSED) {
StgClosure *result;
TRACE("%p : cond_lock_tvar(%p, %p)\n", trec, s, expected);
result = s -> current_value;
StgClosure *result;
TRACE("%p : cond_lock_tvar(%p, %p)\n", trec, s, expected);
result = s -> current_value;
- TRACE("%p : %d\n", (result == expected) ? "success" : "failure");
+ TRACE("%p : %s\n", trec, (result == expected) ? "success" : "failure");
return (result == expected);
}
#endif
#if defined(STM_CG_LOCK) /*........................................*/
return (result == expected);
}
#endif
#if defined(STM_CG_LOCK) /*........................................*/
+#undef IF_STM_CG_LOCK
+#define IF_STM_CG_LOCK(__X) do { __X } while (0)
static const StgBool use_read_phase = FALSE;
static volatile StgTRecHeader *smp_locked = NULL;
static const StgBool use_read_phase = FALSE;
static volatile StgTRecHeader *smp_locked = NULL;
#if defined(STM_FG_LOCKS) /*...................................*/
#if defined(STM_FG_LOCKS) /*...................................*/
+#undef IF_STM_FG_LOCKS
+#define IF_STM_FG_LOCKS(__X) do { __X } while (0)
static const StgBool use_read_phase = TRUE;
static void lock_stm(StgTRecHeader *trec STG_UNUSED) {
static const StgBool use_read_phase = TRUE;
static void lock_stm(StgTRecHeader *trec STG_UNUSED) {
+static StgTVar *new_tvar(StgRegTable *reg,
+ StgClosure *new_value) {
+ StgTVar *result;
+ result = (StgTVar *)allocateLocal(reg, sizeofW(StgTVar));
+ SET_HDR (result, &stg_TVAR_info, CCS_SYSTEM);
+ result -> current_value = new_value;
+ result -> first_wait_queue_entry = END_STM_WAIT_QUEUE;
+#if defined(SMP)
+ result -> last_update_by = NO_TREC;
+#endif
+ return result;
+}
+
/*......................................................................*/
// Helper functions for managing waiting lists
/*......................................................................*/
// Helper functions for managing waiting lists
BREAK_FOR_EACH;
}
} else {
BREAK_FOR_EACH;
}
} else {
- TRACE("%p : will need to check %p\n", trec, s);
- if (s -> current_value != e -> expected_value) {
- TRACE("%p : doesn't match\n", trec);
- result = FALSE;
- BREAK_FOR_EACH;
- }
- e -> saw_update_by = s -> last_update_by;
- if (s -> current_value != e -> expected_value) {
- TRACE("%p : doesn't match (race)\n", trec);
- result = FALSE;
- BREAK_FOR_EACH;
- } else {
- TRACE("%p : need to check update by %p\n", trec, e -> saw_update_by);
- }
+ ASSERT(use_read_phase);
+ IF_STM_FG_LOCKS({
+ TRACE("%p : will need to check %p\n", trec, s);
+ if (s -> current_value != e -> expected_value) {
+ TRACE("%p : doesn't match\n", trec);
+ result = FALSE;
+ BREAK_FOR_EACH;
+ }
+ e -> saw_update_by = s -> last_update_by;
+ if (s -> current_value != e -> expected_value) {
+ TRACE("%p : doesn't match (race)\n", trec);
+ result = FALSE;
+ BREAK_FOR_EACH;
+ } else {
+ TRACE("%p : need to check update by %p\n", trec, e -> saw_update_by);
+ }
+ });
// Keir Fraser's PhD dissertation "Practical lock-free programming" discuss
// this kind of algorithm.
// Keir Fraser's PhD dissertation "Practical lock-free programming" discuss
// this kind of algorithm.
-static StgBool check_read_only(StgTRecHeader *trec) {
+static StgBool check_read_only(StgTRecHeader *trec STG_UNUSED) {
- FOR_EACH_ENTRY(trec, e, {
- StgTVar *s;
- s = e -> tvar;
- if (entry_is_read_only(e)) {
- TRACE("%p : check_read_only for TVar %p, saw %p\n", trec, s, e -> saw_update_by);
- if (s -> last_update_by != e -> saw_update_by) {
- // ||s -> current_value != e -> expected_value) {
- TRACE("%p : mismatch\n", trec);
- result = FALSE;
- BREAK_FOR_EACH;
+ ASSERT (use_read_phase);
+ IF_STM_FG_LOCKS({
+ FOR_EACH_ENTRY(trec, e, {
+ StgTVar *s;
+ s = e -> tvar;
+ if (entry_is_read_only(e)) {
+ TRACE("%p : check_read_only for TVar %p, saw %p\n", trec, s, e -> saw_update_by);
+ if (s -> last_update_by != e -> saw_update_by) {
+ // ||s -> current_value != e -> expected_value) {
+ TRACE("%p : mismatch\n", trec);
+ result = FALSE;
+ BREAK_FOR_EACH;
+ }
if (use_read_phase) {
TRACE("%p : doing read check\n", trec);
result = check_read_only(trec);
if (use_read_phase) {
TRACE("%p : doing read check\n", trec);
result = check_read_only(trec);
+ TRACE("%p : read-check %s\n", trec, result ? "succeeded" : "failed");
// at the end of the call to validate_and_acquire_ownership. This forms the
// linearization point of the commit.
// at the end of the call to validate_and_acquire_ownership. This forms the
// linearization point of the commit.
- TRACE("%p : read-check succeeded\n", trec);
FOR_EACH_ENTRY(trec, e, {
StgTVar *s;
s = e -> tvar;
FOR_EACH_ENTRY(trec, e, {
StgTVar *s;
s = e -> tvar;
ACQ_ASSERT(tvar_is_locked(s, trec));
TRACE("%p : writing %p to %p, waking waiters\n", trec, e -> new_value, s);
unpark_waiters_on(s);
ACQ_ASSERT(tvar_is_locked(s, trec));
TRACE("%p : writing %p to %p, waking waiters\n", trec, e -> new_value, s);
unpark_waiters_on(s);
- s -> last_update_by = trec;
+ IF_STM_FG_LOCKS({
+ s -> last_update_by = trec;
+ });
unlock_tvar(trec, s, e -> new_value, TRUE);
}
ACQ_ASSERT(!tvar_is_locked(s, trec));
unlock_tvar(trec, s, e -> new_value, TRUE);
}
ACQ_ASSERT(!tvar_is_locked(s, trec));
/*......................................................................*/
/*......................................................................*/
+StgTVar *stmNewTVar(StgRegTable *reg,
+ StgClosure *new_value) {
+ StgTVar *result;
+ result = new_tvar(reg, new_value);
+ return result;
+}
+
+/*......................................................................*/
+