Add a write barrier to the TSO link field (#1589)

parent 9de1ad50
...@@ -544,9 +544,6 @@ ...@@ -544,9 +544,6 @@
#define END_TSO_QUEUE stg_END_TSO_QUEUE_closure #define END_TSO_QUEUE stg_END_TSO_QUEUE_closure
#define END_INVARIANT_CHECK_QUEUE stg_END_INVARIANT_CHECK_QUEUE_closure #define END_INVARIANT_CHECK_QUEUE stg_END_INVARIANT_CHECK_QUEUE_closure
#define dirtyTSO(tso) \
StgTSO_flags(tso) = StgTSO_flags(tso) | TSO_DIRTY::I32;
#define recordMutableCap(p, gen, regs) \ #define recordMutableCap(p, gen, regs) \
W_ __bd; \ W_ __bd; \
W_ mut_list; \ W_ mut_list; \
......
...@@ -260,6 +260,11 @@ ...@@ -260,6 +260,11 @@
#define TSO_INTERRUPTIBLE 8 #define TSO_INTERRUPTIBLE 8
#define TSO_STOPPED_ON_BREAKPOINT 16 #define TSO_STOPPED_ON_BREAKPOINT 16
/*
* TSO_LINK_DIRTY is set when a TSO's link field is modified
*/
#define TSO_LINK_DIRTY 32
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
RET_DYN stack frames RET_DYN stack frames
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
......
...@@ -126,6 +126,4 @@ extern void revertCAFs( void ); ...@@ -126,6 +126,4 @@ extern void revertCAFs( void );
extern void dirty_MUT_VAR(StgRegTable *reg, StgClosure *p); extern void dirty_MUT_VAR(StgRegTable *reg, StgClosure *p);
extern void dirty_MVAR(StgRegTable *reg, StgClosure *p); extern void dirty_MVAR(StgRegTable *reg, StgClosure *p);
extern void dirty_TSO(StgClosure *tso);
#endif /* RTSEXTERNAL_H */ #endif /* RTSEXTERNAL_H */
...@@ -124,7 +124,21 @@ typedef union { ...@@ -124,7 +124,21 @@ typedef union {
typedef struct StgTSO_ { typedef struct StgTSO_ {
StgHeader header; StgHeader header;
struct StgTSO_* link; /* Links threads onto blocking queues */ /* The link field, for linking threads together in lists (e.g. the
run queue on a Capability.
*/
struct StgTSO_* _link;
/*
NOTE!!! do not modify _link directly, it is subject to
a write barrier for generational GC. Instead use the
setTSOLink() function. Exceptions to this rule are:
* setting the link field to END_TSO_QUEUE
* putting a TSO on the blackhole_queue
* setting the link field of the currently running TSO, as it
will already be dirty.
*/
struct StgTSO_* global_link; /* Links all threads together */ struct StgTSO_* global_link; /* Links all threads together */
StgWord16 what_next; /* Values defined in Constants.h */ StgWord16 what_next; /* Values defined in Constants.h */
...@@ -171,6 +185,13 @@ typedef struct StgTSO_ { ...@@ -171,6 +185,13 @@ typedef struct StgTSO_ {
StgWord stack[FLEXIBLE_ARRAY]; StgWord stack[FLEXIBLE_ARRAY];
} StgTSO; } StgTSO;
/* -----------------------------------------------------------------------------
functions
-------------------------------------------------------------------------- */
extern void dirty_TSO (Capability *cap, StgTSO *tso);
extern void setTSOLink (Capability *cap, StgTSO *tso, StgTSO *target);
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Invariants: Invariants:
......
...@@ -275,7 +275,7 @@ main(int argc, char *argv[]) ...@@ -275,7 +275,7 @@ main(int argc, char *argv[])
closure_field(StgArrWords, words); closure_field(StgArrWords, words);
closure_payload(StgArrWords, payload); closure_payload(StgArrWords, payload);
closure_field(StgTSO, link); closure_field(StgTSO, _link);
closure_field(StgTSO, global_link); closure_field(StgTSO, global_link);
closure_field(StgTSO, what_next); closure_field(StgTSO, what_next);
closure_field(StgTSO, why_blocked); closure_field(StgTSO, why_blocked);
......
...@@ -1561,9 +1561,10 @@ takeMVarzh_fast ...@@ -1561,9 +1561,10 @@ takeMVarzh_fast
if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) { if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
StgMVar_head(mvar) = CurrentTSO; StgMVar_head(mvar) = CurrentTSO;
} else { } else {
StgTSO_link(StgMVar_tail(mvar)) = CurrentTSO; foreign "C" setTSOLink(MyCapability() "ptr", StgMVar_tail(mvar),
CurrentTSO);
} }
StgTSO_link(CurrentTSO) = stg_END_TSO_QUEUE_closure; StgTSO__link(CurrentTSO) = stg_END_TSO_QUEUE_closure;
StgTSO_why_blocked(CurrentTSO) = BlockedOnMVar::I16; StgTSO_why_blocked(CurrentTSO) = BlockedOnMVar::I16;
StgTSO_block_info(CurrentTSO) = mvar; StgTSO_block_info(CurrentTSO) = mvar;
StgMVar_tail(mvar) = CurrentTSO; StgMVar_tail(mvar) = CurrentTSO;
...@@ -1584,15 +1585,18 @@ takeMVarzh_fast ...@@ -1584,15 +1585,18 @@ takeMVarzh_fast
/* actually perform the putMVar for the thread that we just woke up */ /* actually perform the putMVar for the thread that we just woke up */
tso = StgMVar_head(mvar); tso = StgMVar_head(mvar);
PerformPut(tso,StgMVar_value(mvar)); PerformPut(tso,StgMVar_value(mvar));
dirtyTSO(tso);
if (StgTSO_flags(tso) & TSO_DIRTY == 0) {
foreign "C" dirty_TSO(MyCapability(), tso);
}
#if defined(GRAN) || defined(PAR) #if defined(GRAN) || defined(PAR)
/* ToDo: check 2nd arg (mvar) is right */ /* ToDo: check 2nd arg (mvar) is right */
("ptr" tso) = foreign "C" unblockOne(StgMVar_head(mvar),mvar) []; ("ptr" tso) = foreign "C" unblockOne(StgMVar_head(mvar),mvar) [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#else #else
("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", ("ptr" tso) = foreign "C" unblockOne_(MyCapability() "ptr",
StgMVar_head(mvar) "ptr") []; StgMVar_head(mvar) "ptr", 1) [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#endif #endif
...@@ -1664,15 +1668,17 @@ tryTakeMVarzh_fast ...@@ -1664,15 +1668,17 @@ tryTakeMVarzh_fast
/* actually perform the putMVar for the thread that we just woke up */ /* actually perform the putMVar for the thread that we just woke up */
tso = StgMVar_head(mvar); tso = StgMVar_head(mvar);
PerformPut(tso,StgMVar_value(mvar)); PerformPut(tso,StgMVar_value(mvar));
dirtyTSO(tso); if (StgTSO_flags(tso) & TSO_DIRTY == 0) {
foreign "C" dirty_TSO(MyCapability(), tso);
}
#if defined(GRAN) || defined(PAR) #if defined(GRAN) || defined(PAR)
/* ToDo: check 2nd arg (mvar) is right */ /* ToDo: check 2nd arg (mvar) is right */
("ptr" tso) = foreign "C" unblockOne(StgMVar_head(mvar) "ptr", mvar "ptr") []; ("ptr" tso) = foreign "C" unblockOne(StgMVar_head(mvar) "ptr", mvar "ptr") [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#else #else
("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", ("ptr" tso) = foreign "C" unblockOne_(MyCapability() "ptr",
StgMVar_head(mvar) "ptr") []; StgMVar_head(mvar) "ptr", 1) [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#endif #endif
...@@ -1721,9 +1727,10 @@ putMVarzh_fast ...@@ -1721,9 +1727,10 @@ putMVarzh_fast
if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) { if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
StgMVar_head(mvar) = CurrentTSO; StgMVar_head(mvar) = CurrentTSO;
} else { } else {
StgTSO_link(StgMVar_tail(mvar)) = CurrentTSO; foreign "C" setTSOLink(MyCapability() "ptr", StgMVar_tail(mvar),
CurrentTSO);
} }
StgTSO_link(CurrentTSO) = stg_END_TSO_QUEUE_closure; StgTSO__link(CurrentTSO) = stg_END_TSO_QUEUE_closure;
StgTSO_why_blocked(CurrentTSO) = BlockedOnMVar::I16; StgTSO_why_blocked(CurrentTSO) = BlockedOnMVar::I16;
StgTSO_block_info(CurrentTSO) = mvar; StgTSO_block_info(CurrentTSO) = mvar;
StgMVar_tail(mvar) = CurrentTSO; StgMVar_tail(mvar) = CurrentTSO;
...@@ -1740,14 +1747,17 @@ putMVarzh_fast ...@@ -1740,14 +1747,17 @@ putMVarzh_fast
/* actually perform the takeMVar */ /* actually perform the takeMVar */
tso = StgMVar_head(mvar); tso = StgMVar_head(mvar);
PerformTake(tso, R2); PerformTake(tso, R2);
dirtyTSO(tso); if (StgTSO_flags(tso) & TSO_DIRTY == 0) {
foreign "C" dirty_TSO(MyCapability(), tso);
}
#if defined(GRAN) || defined(PAR) #if defined(GRAN) || defined(PAR)
/* ToDo: check 2nd arg (mvar) is right */ /* ToDo: check 2nd arg (mvar) is right */
("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", StgMVar_head(mvar) "ptr",mvar "ptr") []; ("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", StgMVar_head(mvar) "ptr",mvar "ptr") [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#else #else
("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", StgMVar_head(mvar) "ptr") []; ("ptr" tso) = foreign "C" unblockOne_(MyCapability() "ptr",
StgMVar_head(mvar) "ptr", 1) [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#endif #endif
...@@ -1812,14 +1822,17 @@ tryPutMVarzh_fast ...@@ -1812,14 +1822,17 @@ tryPutMVarzh_fast
/* actually perform the takeMVar */ /* actually perform the takeMVar */
tso = StgMVar_head(mvar); tso = StgMVar_head(mvar);
PerformTake(tso, R2); PerformTake(tso, R2);
dirtyTSO(tso); if (StgTSO_flags(tso) & TSO_DIRTY == 0) {
foreign "C" dirty_TSO(MyCapability(), tso);
}
#if defined(GRAN) || defined(PAR) #if defined(GRAN) || defined(PAR)
/* ToDo: check 2nd arg (mvar) is right */ /* ToDo: check 2nd arg (mvar) is right */
("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", StgMVar_head(mvar) "ptr",mvar "ptr") []; ("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", StgMVar_head(mvar) "ptr",mvar "ptr") [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#else #else
("ptr" tso) = foreign "C" unblockOne(MyCapability() "ptr", StgMVar_head(mvar) "ptr") []; ("ptr" tso) = foreign "C" unblockOne_(MyCapability() "ptr",
StgMVar_head(mvar) "ptr", 1) [];
StgMVar_head(mvar) = tso; StgMVar_head(mvar) = tso;
#endif #endif
...@@ -2037,11 +2050,11 @@ for2: ...@@ -2037,11 +2050,11 @@ for2:
* macro in Schedule.h). * macro in Schedule.h).
*/ */
#define APPEND_TO_BLOCKED_QUEUE(tso) \ #define APPEND_TO_BLOCKED_QUEUE(tso) \
ASSERT(StgTSO_link(tso) == END_TSO_QUEUE); \ ASSERT(StgTSO__link(tso) == END_TSO_QUEUE); \
if (W_[blocked_queue_hd] == END_TSO_QUEUE) { \ if (W_[blocked_queue_hd] == END_TSO_QUEUE) { \
W_[blocked_queue_hd] = tso; \ W_[blocked_queue_hd] = tso; \
} else { \ } else { \
StgTSO_link(W_[blocked_queue_tl]) = tso; \ foreign "C" setTSOLink(MyCapability() "ptr", W_[blocked_queue_tl], tso); \
} \ } \
W_[blocked_queue_tl] = tso; W_[blocked_queue_tl] = tso;
...@@ -2137,15 +2150,15 @@ delayzh_fast ...@@ -2137,15 +2150,15 @@ delayzh_fast
while: while:
if (t != END_TSO_QUEUE && StgTSO_block_info(t) < target) { if (t != END_TSO_QUEUE && StgTSO_block_info(t) < target) {
prev = t; prev = t;
t = StgTSO_link(t); t = StgTSO__link(t);
goto while; goto while;
} }
StgTSO_link(CurrentTSO) = t; StgTSO__link(CurrentTSO) = t;
if (prev == NULL) { if (prev == NULL) {
W_[sleeping_queue] = CurrentTSO; W_[sleeping_queue] = CurrentTSO;
} else { } else {
StgTSO_link(prev) = CurrentTSO; foreign "C" setTSOLink(MyCapability() "ptr", prev, CurrentTSO) [];
} }
jump stg_block_noregs; jump stg_block_noregs;
#endif #endif
......
...@@ -30,7 +30,7 @@ static void raiseAsync (Capability *cap, ...@@ -30,7 +30,7 @@ static void raiseAsync (Capability *cap,
static void removeFromQueues(Capability *cap, StgTSO *tso); static void removeFromQueues(Capability *cap, StgTSO *tso);
static void blockedThrowTo (StgTSO *source, StgTSO *target); static void blockedThrowTo (Capability *cap, StgTSO *source, StgTSO *target);
static void performBlockedException (Capability *cap, static void performBlockedException (Capability *cap,
StgTSO *source, StgTSO *target); StgTSO *source, StgTSO *target);
...@@ -152,7 +152,7 @@ throwTo (Capability *cap, // the Capability we hold ...@@ -152,7 +152,7 @@ throwTo (Capability *cap, // the Capability we hold
// follow ThreadRelocated links in the target first // follow ThreadRelocated links in the target first
while (target->what_next == ThreadRelocated) { while (target->what_next == ThreadRelocated) {
target = target->link; target = target->_link;
// No, it might be a WHITEHOLE: // No, it might be a WHITEHOLE:
// ASSERT(get_itbl(target)->type == TSO); // ASSERT(get_itbl(target)->type == TSO);
} }
...@@ -261,10 +261,10 @@ check_target: ...@@ -261,10 +261,10 @@ check_target:
// just moved this TSO. // just moved this TSO.
if (target->what_next == ThreadRelocated) { if (target->what_next == ThreadRelocated) {
unlockTSO(target); unlockTSO(target);
target = target->link; target = target->_link;
goto retry; goto retry;
} }
blockedThrowTo(source,target); blockedThrowTo(cap,source,target);
*out = target; *out = target;
return THROWTO_BLOCKED; return THROWTO_BLOCKED;
} }
...@@ -294,7 +294,7 @@ check_target: ...@@ -294,7 +294,7 @@ check_target:
info = lockClosure((StgClosure *)mvar); info = lockClosure((StgClosure *)mvar);
if (target->what_next == ThreadRelocated) { if (target->what_next == ThreadRelocated) {
target = target->link; target = target->_link;
unlockClosure((StgClosure *)mvar,info); unlockClosure((StgClosure *)mvar,info);
goto retry; goto retry;
} }
...@@ -309,12 +309,12 @@ check_target: ...@@ -309,12 +309,12 @@ check_target:
if ((target->flags & TSO_BLOCKEX) && if ((target->flags & TSO_BLOCKEX) &&
((target->flags & TSO_INTERRUPTIBLE) == 0)) { ((target->flags & TSO_INTERRUPTIBLE) == 0)) {
lockClosure((StgClosure *)target); lockClosure((StgClosure *)target);
blockedThrowTo(source,target); blockedThrowTo(cap,source,target);
unlockClosure((StgClosure *)mvar, info); unlockClosure((StgClosure *)mvar, info);
*out = target; *out = target;
return THROWTO_BLOCKED; // caller releases TSO return THROWTO_BLOCKED; // caller releases TSO
} else { } else {
removeThreadFromMVarQueue(mvar, target); removeThreadFromMVarQueue(cap, mvar, target);
raiseAsync(cap, target, exception, rtsFalse, NULL); raiseAsync(cap, target, exception, rtsFalse, NULL);
unblockOne(cap, target); unblockOne(cap, target);
unlockClosure((StgClosure *)mvar, info); unlockClosure((StgClosure *)mvar, info);
...@@ -333,12 +333,12 @@ check_target: ...@@ -333,12 +333,12 @@ check_target:
if (target->flags & TSO_BLOCKEX) { if (target->flags & TSO_BLOCKEX) {
lockTSO(target); lockTSO(target);
blockedThrowTo(source,target); blockedThrowTo(cap,source,target);
RELEASE_LOCK(&sched_mutex); RELEASE_LOCK(&sched_mutex);
*out = target; *out = target;
return THROWTO_BLOCKED; // caller releases TSO return THROWTO_BLOCKED; // caller releases TSO
} else { } else {
removeThreadFromQueue(&blackhole_queue, target); removeThreadFromQueue(cap, &blackhole_queue, target);
raiseAsync(cap, target, exception, rtsFalse, NULL); raiseAsync(cap, target, exception, rtsFalse, NULL);
unblockOne(cap, target); unblockOne(cap, target);
RELEASE_LOCK(&sched_mutex); RELEASE_LOCK(&sched_mutex);
...@@ -373,12 +373,12 @@ check_target: ...@@ -373,12 +373,12 @@ check_target:
goto retry; goto retry;
} }
if (target->what_next == ThreadRelocated) { if (target->what_next == ThreadRelocated) {
target = target->link; target = target->_link;
unlockTSO(target2); unlockTSO(target2);
goto retry; goto retry;
} }
if (target2->what_next == ThreadRelocated) { if (target2->what_next == ThreadRelocated) {
target->block_info.tso = target2->link; target->block_info.tso = target2->_link;
unlockTSO(target2); unlockTSO(target2);
goto retry; goto retry;
} }
...@@ -397,12 +397,12 @@ check_target: ...@@ -397,12 +397,12 @@ check_target:
if ((target->flags & TSO_BLOCKEX) && if ((target->flags & TSO_BLOCKEX) &&
((target->flags & TSO_INTERRUPTIBLE) == 0)) { ((target->flags & TSO_INTERRUPTIBLE) == 0)) {
lockTSO(target); lockTSO(target);
blockedThrowTo(source,target); blockedThrowTo(cap,source,target);
unlockTSO(target2); unlockTSO(target2);
*out = target; *out = target;
return THROWTO_BLOCKED; return THROWTO_BLOCKED;
} else { } else {
removeThreadFromQueue(&target2->blocked_exceptions, target); removeThreadFromQueue(cap, &target2->blocked_exceptions, target);
raiseAsync(cap, target, exception, rtsFalse, NULL); raiseAsync(cap, target, exception, rtsFalse, NULL);
unblockOne(cap, target); unblockOne(cap, target);
unlockTSO(target2); unlockTSO(target2);
...@@ -419,7 +419,7 @@ check_target: ...@@ -419,7 +419,7 @@ check_target:
} }
if ((target->flags & TSO_BLOCKEX) && if ((target->flags & TSO_BLOCKEX) &&
((target->flags & TSO_INTERRUPTIBLE) == 0)) { ((target->flags & TSO_INTERRUPTIBLE) == 0)) {
blockedThrowTo(source,target); blockedThrowTo(cap,source,target);
*out = target; *out = target;
return THROWTO_BLOCKED; return THROWTO_BLOCKED;
} else { } else {
...@@ -436,7 +436,7 @@ check_target: ...@@ -436,7 +436,7 @@ check_target:
// thread is blocking exceptions, and block on its // thread is blocking exceptions, and block on its
// blocked_exception queue. // blocked_exception queue.
lockTSO(target); lockTSO(target);
blockedThrowTo(source,target); blockedThrowTo(cap,source,target);
*out = target; *out = target;
return THROWTO_BLOCKED; return THROWTO_BLOCKED;
...@@ -449,7 +449,7 @@ check_target: ...@@ -449,7 +449,7 @@ check_target:
#endif #endif
if ((target->flags & TSO_BLOCKEX) && if ((target->flags & TSO_BLOCKEX) &&
((target->flags & TSO_INTERRUPTIBLE) == 0)) { ((target->flags & TSO_INTERRUPTIBLE) == 0)) {
blockedThrowTo(source,target); blockedThrowTo(cap,source,target);
return THROWTO_BLOCKED; return THROWTO_BLOCKED;
} else { } else {
removeFromQueues(cap,target); removeFromQueues(cap,target);
...@@ -469,12 +469,12 @@ check_target: ...@@ -469,12 +469,12 @@ check_target:
// complex to achieve as there's no single lock on a TSO; see // complex to achieve as there's no single lock on a TSO; see
// throwTo()). // throwTo()).
static void static void
blockedThrowTo (StgTSO *source, StgTSO *target) blockedThrowTo (Capability *cap, StgTSO *source, StgTSO *target)
{ {
debugTrace(DEBUG_sched, "throwTo: blocking on thread %lu", (unsigned long)target->id); debugTrace(DEBUG_sched, "throwTo: blocking on thread %lu", (unsigned long)target->id);
source->link = target->blocked_exceptions; setTSOLink(cap, source, target->blocked_exceptions);
target->blocked_exceptions = source; target->blocked_exceptions = source;
dirtyTSO(target); // we modified the blocked_exceptions queue dirty_TSO(cap,target); // we modified the blocked_exceptions queue
source->block_info.tso = target; source->block_info.tso = target;
write_barrier(); // throwTo_exception *must* be visible if BlockedOnException is. write_barrier(); // throwTo_exception *must* be visible if BlockedOnException is.
...@@ -748,11 +748,11 @@ removeFromQueues(Capability *cap, StgTSO *tso) ...@@ -748,11 +748,11 @@ removeFromQueues(Capability *cap, StgTSO *tso)
goto done; goto done;
case BlockedOnMVar: case BlockedOnMVar:
removeThreadFromMVarQueue((StgMVar *)tso->block_info.closure, tso); removeThreadFromMVarQueue(cap, (StgMVar *)tso->block_info.closure, tso);
goto done; goto done;
case BlockedOnBlackHole: case BlockedOnBlackHole:
removeThreadFromQueue(&blackhole_queue, tso); removeThreadFromQueue(cap, &blackhole_queue, tso);
goto done; goto done;
case BlockedOnException: case BlockedOnException:
...@@ -765,10 +765,10 @@ removeFromQueues(Capability *cap, StgTSO *tso) ...@@ -765,10 +765,10 @@ removeFromQueues(Capability *cap, StgTSO *tso)
// ASSERT(get_itbl(target)->type == TSO); // ASSERT(get_itbl(target)->type == TSO);
while (target->what_next == ThreadRelocated) { while (target->what_next == ThreadRelocated) {
target = target->link; target = target->_link;
} }
removeThreadFromQueue(&target->blocked_exceptions, tso); removeThreadFromQueue(cap, &target->blocked_exceptions, tso);
goto done; goto done;
} }
...@@ -778,7 +778,7 @@ removeFromQueues(Capability *cap, StgTSO *tso) ...@@ -778,7 +778,7 @@ removeFromQueues(Capability *cap, StgTSO *tso)
#if defined(mingw32_HOST_OS) #if defined(mingw32_HOST_OS)
case BlockedOnDoProc: case BlockedOnDoProc:
#endif #endif
removeThreadFromDeQueue(&blocked_queue_hd, &blocked_queue_tl, tso); removeThreadFromDeQueue(cap, &blocked_queue_hd, &blocked_queue_tl, tso);
#if defined(mingw32_HOST_OS) #if defined(mingw32_HOST_OS)
/* (Cooperatively) signal that the worker thread should abort /* (Cooperatively) signal that the worker thread should abort
* the request. * the request.
...@@ -788,7 +788,7 @@ removeFromQueues(Capability *cap, StgTSO *tso) ...@@ -788,7 +788,7 @@ removeFromQueues(Capability *cap, StgTSO *tso)
goto done; goto done;
case BlockedOnDelay: case BlockedOnDelay:
removeThreadFromQueue(&sleeping_queue, tso); removeThreadFromQueue(cap, &sleeping_queue, tso);
goto done; goto done;
#endif #endif
...@@ -797,7 +797,7 @@ removeFromQueues(Capability *cap, StgTSO *tso) ...@@ -797,7 +797,7 @@ removeFromQueues(Capability *cap, StgTSO *tso)
} }
done: done:
tso->link = END_TSO_QUEUE; tso->_link = END_TSO_QUEUE; // no write barrier reqd
tso->why_blocked = NotBlocked; tso->why_blocked = NotBlocked;
tso->block_info.closure = NULL; tso->block_info.closure = NULL;
appendToRunQueue(cap,tso); appendToRunQueue(cap,tso);
...@@ -871,7 +871,7 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, ...@@ -871,7 +871,7 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception,
#endif #endif
// mark it dirty; we're about to change its stack. // mark it dirty; we're about to change its stack.
dirtyTSO(tso); dirty_TSO(cap, tso);
sp = tso->sp; sp = tso->sp;
......
...@@ -1635,7 +1635,7 @@ inner_loop: ...@@ -1635,7 +1635,7 @@ inner_loop:
#ifdef DEBUG_RETAINER #ifdef DEBUG_RETAINER
debugBelch("ThreadRelocated encountered in retainClosure()\n"); debugBelch("ThreadRelocated encountered in retainClosure()\n");
#endif #endif
c = (StgClosure *)((StgTSO *)c)->link; c = (StgClosure *)((StgTSO *)c)->_link;
goto inner_loop; goto inner_loop;
} }
break; break;
......
...@@ -652,7 +652,7 @@ checkTSO(StgTSO *tso) ...@@ -652,7 +652,7 @@ checkTSO(StgTSO *tso)
StgPtr stack_end = stack + stack_size; StgPtr stack_end = stack + stack_size;
if (tso->what_next == ThreadRelocated) { if (tso->what_next == ThreadRelocated) {
checkTSO(tso->link); checkTSO(tso->_link);