Commit 5d52d9b6 authored by Simon Marlow's avatar Simon Marlow

New implementation of BLACKHOLEs

This replaces the global blackhole_queue with a clever scheme that
enables us to queue up blocked threads on the closure that they are
blocked on, while still avoiding atomic instructions in the common
case.

Advantages:

 - gets rid of a locked global data structure and some tricky GC code
   (replacing it with some per-thread data structures and different
   tricky GC code :)

 - wakeups are more prompt: parallel/concurrent performance should
   benefit.  I haven't seen anything dramatic in the parallel
   benchmarks so far, but a couple of threading benchmarks do improve
   a bit.

 - waking up a thread blocked on a blackhole is now O(1) (e.g. if
   it is the target of throwTo).

 - less sharing and better separation of Capabilities: communication
   is done with messages, the data structures are strictly owned by a
   Capability and cannot be modified except by sending messages.

 - this change will utlimately enable us to do more intelligent
   scheduling when threads block on each other.  This is what started
   off the whole thing, but it isn't done yet (#3838).

I'll be documenting all this on the wiki in due course.
parent 79957d77
...@@ -58,6 +58,7 @@ module CLabel ( ...@@ -58,6 +58,7 @@ module CLabel (
mkSplitMarkerLabel, mkSplitMarkerLabel,
mkDirty_MUT_VAR_Label, mkDirty_MUT_VAR_Label,
mkUpdInfoLabel, mkUpdInfoLabel,
mkBHUpdInfoLabel,
mkIndStaticInfoLabel, mkIndStaticInfoLabel,
mkMainCapabilityLabel, mkMainCapabilityLabel,
mkMAP_FROZEN_infoLabel, mkMAP_FROZEN_infoLabel,
...@@ -400,6 +401,7 @@ mkStaticConEntryLabel name c = IdLabel name c StaticConEntry ...@@ -400,6 +401,7 @@ mkStaticConEntryLabel name c = IdLabel name c StaticConEntry
mkSplitMarkerLabel = CmmLabel rtsPackageId (fsLit "__stg_split_marker") CmmCode mkSplitMarkerLabel = CmmLabel rtsPackageId (fsLit "__stg_split_marker") CmmCode
mkDirty_MUT_VAR_Label = CmmLabel rtsPackageId (fsLit "dirty_MUT_VAR") CmmCode mkDirty_MUT_VAR_Label = CmmLabel rtsPackageId (fsLit "dirty_MUT_VAR") CmmCode
mkUpdInfoLabel = CmmLabel rtsPackageId (fsLit "stg_upd_frame") CmmInfo mkUpdInfoLabel = CmmLabel rtsPackageId (fsLit "stg_upd_frame") CmmInfo
mkBHUpdInfoLabel = CmmLabel rtsPackageId (fsLit "stg_bh_upd_frame" ) CmmInfo
mkIndStaticInfoLabel = CmmLabel rtsPackageId (fsLit "stg_IND_STATIC") CmmInfo mkIndStaticInfoLabel = CmmLabel rtsPackageId (fsLit "stg_IND_STATIC") CmmInfo
mkMainCapabilityLabel = CmmLabel rtsPackageId (fsLit "MainCapability") CmmData mkMainCapabilityLabel = CmmLabel rtsPackageId (fsLit "MainCapability") CmmData
mkMAP_FROZEN_infoLabel = CmmLabel rtsPackageId (fsLit "stg_MUT_ARR_PTRS_FROZEN0") CmmInfo mkMAP_FROZEN_infoLabel = CmmLabel rtsPackageId (fsLit "stg_MUT_ARR_PTRS_FROZEN0") CmmInfo
......
...@@ -284,7 +284,6 @@ getSequelAmode ...@@ -284,7 +284,6 @@ getSequelAmode
OnStack -> do { sp_rel <- getSpRelOffset virt_sp OnStack -> do { sp_rel <- getSpRelOffset virt_sp
; returnFC (CmmLoad sp_rel bWord) } ; returnFC (CmmLoad sp_rel bWord) }
UpdateCode -> returnFC (CmmLit (CmmLabel mkUpdInfoLabel))
CaseAlts lbl _ _ -> returnFC (CmmLit (CmmLabel lbl)) CaseAlts lbl _ _ -> returnFC (CmmLit (CmmLabel lbl))
} }
......
...@@ -474,7 +474,12 @@ emitBlackHoleCode is_single_entry = do ...@@ -474,7 +474,12 @@ emitBlackHoleCode is_single_entry = do
then do then do
tickyBlackHole (not is_single_entry) tickyBlackHole (not is_single_entry)
let bh_info = CmmReg (CmmGlobal EagerBlackholeInfo) let bh_info = CmmReg (CmmGlobal EagerBlackholeInfo)
stmtC (CmmStore (CmmReg nodeReg) bh_info) stmtsC [
CmmStore (cmmOffsetW (CmmReg nodeReg) fixedHdrSize)
(CmmReg (CmmGlobal CurrentTSO)),
CmmCall (CmmPrim MO_WriteBarrier) [] [] CmmUnsafe CmmMayReturn,
CmmStore (CmmReg nodeReg) bh_info
]
else else
nopC nopC
\end{code} \end{code}
...@@ -489,17 +494,23 @@ setupUpdate closure_info code ...@@ -489,17 +494,23 @@ setupUpdate closure_info code
= code = code
| not (isStaticClosure closure_info) | not (isStaticClosure closure_info)
= if closureUpdReqd closure_info = do
then do { tickyPushUpdateFrame; pushUpdateFrame (CmmReg nodeReg) code } if not (closureUpdReqd closure_info)
else do { tickyUpdateFrameOmitted; code } then do tickyUpdateFrameOmitted; code
else do
tickyPushUpdateFrame
dflags <- getDynFlags
if not opt_SccProfilingOn && dopt Opt_EagerBlackHoling dflags
then pushBHUpdateFrame (CmmReg nodeReg) code
else pushUpdateFrame (CmmReg nodeReg) code
| otherwise -- A static closure | otherwise -- A static closure
= do { tickyUpdateBhCaf closure_info = do { tickyUpdateBhCaf closure_info
; if closureUpdReqd closure_info ; if closureUpdReqd closure_info
then do -- Blackhole the (updatable) CAF: then do -- Blackhole the (updatable) CAF:
{ upd_closure <- link_caf closure_info True { upd_closure <- link_caf closure_info True
; pushUpdateFrame upd_closure code } ; pushBHUpdateFrame upd_closure code }
else do else do
{ -- krc: removed some ticky-related code here. { -- krc: removed some ticky-related code here.
; tickyUpdateFrameOmitted ; tickyUpdateFrameOmitted
...@@ -553,7 +564,8 @@ link_caf cl_info _is_upd = do ...@@ -553,7 +564,8 @@ link_caf cl_info _is_upd = do
{ -- Alloc black hole specifying CC_HDR(Node) as the cost centre { -- Alloc black hole specifying CC_HDR(Node) as the cost centre
; let use_cc = costCentreFrom (CmmReg nodeReg) ; let use_cc = costCentreFrom (CmmReg nodeReg)
blame_cc = use_cc blame_cc = use_cc
; hp_offset <- allocDynClosure bh_cl_info use_cc blame_cc [] tso = CmmReg (CmmGlobal CurrentTSO)
; hp_offset <- allocDynClosure bh_cl_info use_cc blame_cc [(tso,fixedHdrSize)]
; hp_rel <- getHpRelOffset hp_offset ; hp_rel <- getHpRelOffset hp_offset
-- Call the RTS function newCAF to add the CAF to the CafList -- Call the RTS function newCAF to add the CAF to the CafList
......
...@@ -169,7 +169,6 @@ block. ...@@ -169,7 +169,6 @@ block.
\begin{code} \begin{code}
data Sequel data Sequel
= OnStack -- Continuation is on the stack = OnStack -- Continuation is on the stack
| UpdateCode -- Continuation is update
| CaseAlts | CaseAlts
CLabel -- Jump to this; if the continuation is for a vectored CLabel -- Jump to this; if the continuation is for a vectored
......
...@@ -17,7 +17,7 @@ module CgStackery ( ...@@ -17,7 +17,7 @@ module CgStackery (
setStackFrame, getStackFrame, setStackFrame, getStackFrame,
mkVirtStkOffsets, mkStkAmodes, mkVirtStkOffsets, mkStkAmodes,
freeStackSlots, freeStackSlots,
pushUpdateFrame, emitPushUpdateFrame, pushUpdateFrame, pushBHUpdateFrame, emitPushUpdateFrame,
) where ) where
#include "HsVersions.h" #include "HsVersions.h"
...@@ -265,6 +265,14 @@ to reflect the frame pushed. ...@@ -265,6 +265,14 @@ to reflect the frame pushed.
\begin{code} \begin{code}
pushUpdateFrame :: CmmExpr -> Code -> Code pushUpdateFrame :: CmmExpr -> Code -> Code
pushUpdateFrame updatee code pushUpdateFrame updatee code
= pushSpecUpdateFrame mkUpdInfoLabel updatee code
pushBHUpdateFrame :: CmmExpr -> Code -> Code
pushBHUpdateFrame updatee code
= pushSpecUpdateFrame mkBHUpdInfoLabel updatee code
pushSpecUpdateFrame :: CLabel -> CmmExpr -> Code -> Code
pushSpecUpdateFrame lbl updatee code
= do { = do {
when debugIsOn $ do when debugIsOn $ do
{ EndOfBlockInfo _ sequel <- getEndOfBlockInfo ; { EndOfBlockInfo _ sequel <- getEndOfBlockInfo ;
...@@ -277,15 +285,25 @@ pushUpdateFrame updatee code ...@@ -277,15 +285,25 @@ pushUpdateFrame updatee code
-- The location of the lowest-address -- The location of the lowest-address
-- word of the update frame itself -- word of the update frame itself
; setEndOfBlockInfo (EndOfBlockInfo vsp UpdateCode) $ -- NB. we used to set the Sequel to 'UpdateCode' so
do { emitPushUpdateFrame frame_addr updatee -- that we could jump directly to the update code if
-- we know that the next frame on the stack is an
-- update frame. However, the RTS can sometimes
-- change an update frame into something else (see
-- e.g. Note [upd-black-hole] in rts/sm/Scav.c), so we
-- no longer make this assumption.
; setEndOfBlockInfo (EndOfBlockInfo vsp OnStack) $
do { emitSpecPushUpdateFrame lbl frame_addr updatee
; code } ; code }
} }
emitPushUpdateFrame :: CmmExpr -> CmmExpr -> Code emitPushUpdateFrame :: CmmExpr -> CmmExpr -> Code
emitPushUpdateFrame frame_addr updatee = do emitPushUpdateFrame = emitSpecPushUpdateFrame mkUpdInfoLabel
emitSpecPushUpdateFrame :: CLabel -> CmmExpr -> CmmExpr -> Code
emitSpecPushUpdateFrame lbl frame_addr updatee = do
stmtsC [ -- Set the info word stmtsC [ -- Set the info word
CmmStore frame_addr (mkLblExpr mkUpdInfoLabel) CmmStore frame_addr (mkLblExpr lbl)
, -- And the updatee , -- And the updatee
CmmStore (cmmOffsetB frame_addr off_updatee) updatee ] CmmStore (cmmOffsetB frame_addr off_updatee) updatee ]
initUpdFrameProf frame_addr initUpdFrameProf frame_addr
......
...@@ -106,10 +106,18 @@ void _assertFail(const char *filename, unsigned int linenum) ...@@ -106,10 +106,18 @@ void _assertFail(const char *filename, unsigned int linenum)
else \ else \
_assertFail(__FILE__, __LINE__) _assertFail(__FILE__, __LINE__)
#define CHECKM(predicate, msg, ...) \
if (predicate) \
/*null*/; \
else \
barf(msg, ##__VA_ARGS__)
#ifndef DEBUG #ifndef DEBUG
#define ASSERT(predicate) /* nothing */ #define ASSERT(predicate) /* nothing */
#define ASSERTM(predicate,msg,...) /* nothing */
#else #else
#define ASSERT(predicate) CHECK(predicate) #define ASSERT(predicate) CHECK(predicate)
#define ASSERTM(predicate,msg,...) CHECKM(predicate,msg,##__VA_ARGS__)
#endif /* DEBUG */ #endif /* DEBUG */
/* /*
......
...@@ -291,6 +291,7 @@ main(int argc, char *argv[]) ...@@ -291,6 +291,7 @@ main(int argc, char *argv[])
closure_field(StgTSO, trec); closure_field(StgTSO, trec);
closure_field(StgTSO, flags); closure_field(StgTSO, flags);
closure_field(StgTSO, dirty); closure_field(StgTSO, dirty);
closure_field(StgTSO, bq);
closure_field_("StgTSO_CCCS", StgTSO, prof.CCCS); closure_field_("StgTSO_CCCS", StgTSO, prof.CCCS);
tso_field(StgTSO, sp); tso_field(StgTSO, sp);
tso_field_offset(StgTSO, stack); tso_field_offset(StgTSO, stack);
...@@ -382,6 +383,17 @@ main(int argc, char *argv[]) ...@@ -382,6 +383,17 @@ main(int argc, char *argv[])
closure_size(StgStableName); closure_size(StgStableName);
closure_field(StgStableName,sn); closure_field(StgStableName,sn);
closure_size(StgBlockingQueue);
closure_field(StgBlockingQueue, bh);
closure_field(StgBlockingQueue, owner);
closure_field(StgBlockingQueue, queue);
closure_field(StgBlockingQueue, link);
closure_size(MessageBlackHole);
closure_field(MessageBlackHole, link);
closure_field(MessageBlackHole, tso);
closure_field(MessageBlackHole, bh);
struct_field_("RtsFlags_ProfFlags_showCCSOnException", struct_field_("RtsFlags_ProfFlags_showCCSOnException",
RTS_FLAGS, ProfFlags.showCCSOnException); RTS_FLAGS, ProfFlags.showCCSOnException);
struct_field_("RtsFlags_DebugFlags_apply", struct_field_("RtsFlags_DebugFlags_apply",
......
...@@ -129,6 +129,12 @@ ...@@ -129,6 +129,12 @@
SET_HDR(c,info,costCentreStack); \ SET_HDR(c,info,costCentreStack); \
(c)->words = n_words; (c)->words = n_words;
// Use when changing a closure from one kind to another
#define OVERWRITE_INFO(c, new_info) \
LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC((StgClosure *)(c)); \
SET_INFO((c), (new_info)); \
LDV_RECORD_CREATE(c);
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
How to get hold of the static link field for a static closure. How to get hold of the static link field for a static closure.
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
...@@ -249,7 +255,7 @@ INLINE_HEADER StgOffset THUNK_SELECTOR_sizeW ( void ) ...@@ -249,7 +255,7 @@ INLINE_HEADER StgOffset THUNK_SELECTOR_sizeW ( void )
{ return sizeofW(StgSelector); } { return sizeofW(StgSelector); }
INLINE_HEADER StgOffset BLACKHOLE_sizeW ( void ) INLINE_HEADER StgOffset BLACKHOLE_sizeW ( void )
{ return sizeofW(StgHeader)+MIN_PAYLOAD_SIZE; } { return sizeofW(StgInd); } // a BLACKHOLE is a kind of indirection
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Sizes of closures Sizes of closures
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#define UPDATE_FRAME 38 #define UPDATE_FRAME 38
#define CATCH_FRAME 39 #define CATCH_FRAME 39
#define STOP_FRAME 40 #define STOP_FRAME 40
#define CAF_BLACKHOLE 41 #define BLOCKING_QUEUE 41
#define BLACKHOLE 42 #define BLACKHOLE 42
#define MVAR_CLEAN 43 #define MVAR_CLEAN 43
#define MVAR_DIRTY 44 #define MVAR_DIRTY 44
......
...@@ -127,6 +127,14 @@ typedef struct { ...@@ -127,6 +127,14 @@ typedef struct {
StgInfoTable *saved_info; StgInfoTable *saved_info;
} StgIndStatic; } StgIndStatic;
typedef struct StgBlockingQueue_ {
StgHeader header;
struct StgBlockingQueue_ *link; // here so it looks like an IND
StgClosure *bh; // the BLACKHOLE
StgTSO *owner;
struct MessageBlackHole_ *queue;
} StgBlockingQueue;
typedef struct { typedef struct {
StgHeader header; StgHeader header;
StgWord words; StgWord words;
...@@ -433,10 +441,17 @@ typedef struct MessageWakeup_ { ...@@ -433,10 +441,17 @@ typedef struct MessageWakeup_ {
typedef struct MessageThrowTo_ { typedef struct MessageThrowTo_ {
StgHeader header; StgHeader header;
Message *link; struct MessageThrowTo_ *link;
StgTSO *source; StgTSO *source;
StgTSO *target; StgTSO *target;
StgClosure *exception; StgClosure *exception;
} MessageThrowTo; } MessageThrowTo;
typedef struct MessageBlackHole_ {
StgHeader header;
struct MessageBlackHole_ *link;
StgTSO *tso;
StgClosure *bh;
} MessageBlackHole;
#endif /* RTS_STORAGE_CLOSURES_H */ #endif /* RTS_STORAGE_CLOSURES_H */
...@@ -46,6 +46,7 @@ typedef struct { ...@@ -46,6 +46,7 @@ typedef struct {
/* Reason for thread being blocked. See comment above struct StgTso_. */ /* Reason for thread being blocked. See comment above struct StgTso_. */
typedef union { typedef union {
StgClosure *closure; StgClosure *closure;
struct MessageBlackHole_ *bh;
struct MessageThrowTo_ *throwto; struct MessageThrowTo_ *throwto;
struct MessageWakeup_ *wakeup; struct MessageWakeup_ *wakeup;
StgInt fd; /* StgInt instead of int, so that it's the same size as the ptrs */ StgInt fd; /* StgInt instead of int, so that it's the same size as the ptrs */
...@@ -78,12 +79,17 @@ typedef struct StgTSO_ { ...@@ -78,12 +79,17 @@ typedef struct StgTSO_ {
*/ */
struct StgTSO_* _link; struct StgTSO_* _link;
/* /*
Currently used for linking TSOs on:
* cap->run_queue_{hd,tl}
* MVAR queue
* (non-THREADED_RTS); the blocked_queue
* and pointing to the relocated version of a ThreadRelocated
NOTE!!! do not modify _link directly, it is subject to NOTE!!! do not modify _link directly, it is subject to
a write barrier for generational GC. Instead use the a write barrier for generational GC. Instead use the
setTSOLink() function. Exceptions to this rule are: setTSOLink() function. Exceptions to this rule are:
* setting the link field to END_TSO_QUEUE * 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 * setting the link field of the currently running TSO, as it
will already be dirty. will already be dirty.
*/ */
...@@ -127,6 +133,12 @@ typedef struct StgTSO_ { ...@@ -127,6 +133,12 @@ typedef struct StgTSO_ {
*/ */
struct MessageThrowTo_ * blocked_exceptions; struct MessageThrowTo_ * blocked_exceptions;
/*
A list of StgBlockingQueue objects, representing threads blocked
on thunks that are under evaluation by this thread.
*/
struct StgBlockingQueue_ *bq;
#ifdef TICKY_TICKY #ifdef TICKY_TICKY
/* TICKY-specific stuff would go here. */ /* TICKY-specific stuff would go here. */
#endif #endif
...@@ -152,6 +164,18 @@ typedef struct StgTSO_ { ...@@ -152,6 +164,18 @@ typedef struct StgTSO_ {
void dirty_TSO (Capability *cap, StgTSO *tso); void dirty_TSO (Capability *cap, StgTSO *tso);
void setTSOLink (Capability *cap, StgTSO *tso, StgTSO *target); void setTSOLink (Capability *cap, StgTSO *tso, StgTSO *target);
// Apply to a TSO before looking at it if you are not sure whether it
// might be ThreadRelocated or not (basically, that's most of the time
// unless the TSO is the current TSO).
//
INLINE_HEADER StgTSO * deRefTSO(StgTSO *tso)
{
while (tso->what_next == ThreadRelocated) {
tso = tso->_link;
}
return tso;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Invariants: Invariants:
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
/* Stack frames */ /* Stack frames */
RTS_RET_INFO(stg_upd_frame_info); RTS_RET_INFO(stg_upd_frame_info);
RTS_RET_INFO(stg_bh_upd_frame_info);
RTS_RET_INFO(stg_marked_upd_frame_info); RTS_RET_INFO(stg_marked_upd_frame_info);
RTS_RET_INFO(stg_noupd_frame_info); RTS_RET_INFO(stg_noupd_frame_info);
RTS_RET_INFO(stg_catch_frame_info); RTS_RET_INFO(stg_catch_frame_info);
...@@ -54,6 +55,7 @@ RTS_RET_INFO(stg_catch_stm_frame_info); ...@@ -54,6 +55,7 @@ RTS_RET_INFO(stg_catch_stm_frame_info);
RTS_RET_INFO(stg_unblockAsyncExceptionszh_ret_info); RTS_RET_INFO(stg_unblockAsyncExceptionszh_ret_info);
RTS_ENTRY(stg_upd_frame_ret); RTS_ENTRY(stg_upd_frame_ret);
RTS_ENTRY(stg_bh_upd_frame_ret);
RTS_ENTRY(stg_marked_upd_frame_ret); RTS_ENTRY(stg_marked_upd_frame_ret);
// RTS_FUN(stg_interp_constr_entry); // RTS_FUN(stg_interp_constr_entry);
...@@ -90,12 +92,12 @@ RTS_INFO(stg_IND_STATIC_info); ...@@ -90,12 +92,12 @@ RTS_INFO(stg_IND_STATIC_info);
RTS_INFO(stg_IND_PERM_info); RTS_INFO(stg_IND_PERM_info);
RTS_INFO(stg_IND_OLDGEN_info); RTS_INFO(stg_IND_OLDGEN_info);
RTS_INFO(stg_IND_OLDGEN_PERM_info); RTS_INFO(stg_IND_OLDGEN_PERM_info);
RTS_INFO(stg_CAF_UNENTERED_info);
RTS_INFO(stg_CAF_ENTERED_info);
RTS_INFO(stg_WHITEHOLE_info);
RTS_INFO(stg_BLACKHOLE_info); RTS_INFO(stg_BLACKHOLE_info);
RTS_INFO(__stg_EAGER_BLACKHOLE_info);
RTS_INFO(stg_CAF_BLACKHOLE_info); RTS_INFO(stg_CAF_BLACKHOLE_info);
RTS_INFO(__stg_EAGER_BLACKHOLE_info);
RTS_INFO(stg_WHITEHOLE_info);
RTS_INFO(stg_BLOCKING_QUEUE_CLEAN_info);
RTS_INFO(stg_BLOCKING_QUEUE_DIRTY_info);
RTS_FUN_INFO(stg_BCO_info); RTS_FUN_INFO(stg_BCO_info);
RTS_INFO(stg_EVACUATED_info); RTS_INFO(stg_EVACUATED_info);
...@@ -115,7 +117,9 @@ RTS_INFO(stg_MUT_VAR_CLEAN_info); ...@@ -115,7 +117,9 @@ RTS_INFO(stg_MUT_VAR_CLEAN_info);
RTS_INFO(stg_MUT_VAR_DIRTY_info); RTS_INFO(stg_MUT_VAR_DIRTY_info);
RTS_INFO(stg_END_TSO_QUEUE_info); RTS_INFO(stg_END_TSO_QUEUE_info);
RTS_INFO(stg_MSG_WAKEUP_info); RTS_INFO(stg_MSG_WAKEUP_info);
RTS_INFO(stg_MSG_TRY_WAKEUP_info);
RTS_INFO(stg_MSG_THROWTO_info); RTS_INFO(stg_MSG_THROWTO_info);
RTS_INFO(stg_MSG_BLACKHOLE_info);
RTS_INFO(stg_MUT_CONS_info); RTS_INFO(stg_MUT_CONS_info);
RTS_INFO(stg_catch_info); RTS_INFO(stg_catch_info);
RTS_INFO(stg_PAP_info); RTS_INFO(stg_PAP_info);
...@@ -142,12 +146,10 @@ RTS_ENTRY(stg_IND_STATIC_entry); ...@@ -142,12 +146,10 @@ RTS_ENTRY(stg_IND_STATIC_entry);
RTS_ENTRY(stg_IND_PERM_entry); RTS_ENTRY(stg_IND_PERM_entry);
RTS_ENTRY(stg_IND_OLDGEN_entry); RTS_ENTRY(stg_IND_OLDGEN_entry);
RTS_ENTRY(stg_IND_OLDGEN_PERM_entry); RTS_ENTRY(stg_IND_OLDGEN_PERM_entry);
RTS_ENTRY(stg_CAF_UNENTERED_entry);
RTS_ENTRY(stg_CAF_ENTERED_entry);
RTS_ENTRY(stg_WHITEHOLE_entry); RTS_ENTRY(stg_WHITEHOLE_entry);
RTS_ENTRY(stg_BLACKHOLE_entry); RTS_ENTRY(stg_BLACKHOLE_entry);
RTS_ENTRY(__stg_EAGER_BLACKHOLE_entry);
RTS_ENTRY(stg_CAF_BLACKHOLE_entry); RTS_ENTRY(stg_CAF_BLACKHOLE_entry);
RTS_ENTRY(__stg_EAGER_BLACKHOLE_entry);
RTS_ENTRY(stg_BCO_entry); RTS_ENTRY(stg_BCO_entry);
RTS_ENTRY(stg_EVACUATED_entry); RTS_ENTRY(stg_EVACUATED_entry);
RTS_ENTRY(stg_WEAK_entry); RTS_ENTRY(stg_WEAK_entry);
...@@ -166,7 +168,9 @@ RTS_ENTRY(stg_MUT_VAR_CLEAN_entry); ...@@ -166,7 +168,9 @@ RTS_ENTRY(stg_MUT_VAR_CLEAN_entry);
RTS_ENTRY(stg_MUT_VAR_DIRTY_entry); RTS_ENTRY(stg_MUT_VAR_DIRTY_entry);
RTS_ENTRY(stg_END_TSO_QUEUE_entry); RTS_ENTRY(stg_END_TSO_QUEUE_entry);
RTS_ENTRY(stg_MSG_WAKEUP_entry); RTS_ENTRY(stg_MSG_WAKEUP_entry);
RTS_ENTRY(stg_MSG_TRY_WAKEUP_entry);
RTS_ENTRY(stg_MSG_THROWTO_entry); RTS_ENTRY(stg_MSG_THROWTO_entry);
RTS_ENTRY(stg_MSG_BLACKHOLE_entry);
RTS_ENTRY(stg_MUT_CONS_entry); RTS_ENTRY(stg_MUT_CONS_entry);
RTS_ENTRY(stg_catch_entry); RTS_ENTRY(stg_catch_entry);
RTS_ENTRY(stg_PAP_entry); RTS_ENTRY(stg_PAP_entry);
...@@ -404,6 +408,8 @@ RTS_FUN(stg_PAP_apply); ...@@ -404,6 +408,8 @@ RTS_FUN(stg_PAP_apply);
RTS_RET_INFO(stg_enter_info); RTS_RET_INFO(stg_enter_info);
RTS_ENTRY(stg_enter_ret); RTS_ENTRY(stg_enter_ret);
RTS_RET_INFO(stg_enter_checkbh_info);
RTS_ENTRY(stg_enter_checkbh_ret);
RTS_RET_INFO(stg_gc_void_info); RTS_RET_INFO(stg_gc_void_info);
RTS_ENTRY(stg_gc_void_ret); RTS_ENTRY(stg_gc_void_ret);
......
...@@ -62,9 +62,8 @@ Capability * rts_unsafeGetMyCapability (void) ...@@ -62,9 +62,8 @@ Capability * rts_unsafeGetMyCapability (void)
STATIC_INLINE rtsBool STATIC_INLINE rtsBool
globalWorkToDo (void) globalWorkToDo (void)
{ {
return blackholes_need_checking return sched_state >= SCHED_INTERRUPTING
|| sched_state >= SCHED_INTERRUPTING || recent_activity == ACTIVITY_INACTIVE; // need to check for deadlock
;
} }
#endif #endif
...@@ -636,43 +635,6 @@ yieldCapability (Capability** pCap, Task *task) ...@@ -636,43 +635,6 @@ yieldCapability (Capability** pCap, Task *task)
return; return;
} }
/* ----------------------------------------------------------------------------
* Wake up a thread on a Capability.
*
* This is used when the current Task is running on a Capability and
* wishes to wake up a thread on a different Capability.
* ------------------------------------------------------------------------- */
void
wakeupThreadOnCapability (Capability *cap,
Capability *other_cap,
StgTSO *tso)
{
MessageWakeup *msg;
// ASSUMES: cap->lock is held (asserted in wakeupThreadOnCapability)
if (tso->bound) {
ASSERT(tso->bound->task->cap == tso->cap);
tso->bound->task->cap = other_cap;
}
tso->cap = other_cap;
ASSERT(tso->why_blocked != BlockedOnMsgWakeup ||
tso->block_info.closure->header.info == &stg_IND_info);
ASSERT(tso->block_info.closure->header.info != &stg_MSG_WAKEUP_info);
msg = (MessageWakeup*) allocate(cap, sizeofW(MessageWakeup));
msg->header.info = &stg_MSG_WAKEUP_info;
msg->tso = tso;
tso->block_info.closure = (StgClosure *)msg;
dirty_TSO(cap, tso);
write_barrier();
tso->why_blocked = BlockedOnMsgWakeup;
sendMessage(other_cap, (Message*)msg);
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* prodCapability * prodCapability
* *
...@@ -906,24 +868,3 @@ markCapabilities (evac_fn evac, void *user) ...@@ -906,24 +868,3 @@ markCapabilities (evac_fn evac, void *user)
Messages Messages
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
#ifdef THREADED_RTS
void sendMessage(Capability *cap, Message *msg)
{
ACQUIRE_LOCK(&cap->lock);
msg->link = cap->inbox;
cap->inbox = msg;
if (cap->running_task == NULL) {
cap->running_task = myTask();
// precond for releaseCapability_()
releaseCapability_(cap,rtsFalse);
} else {
contextSwitchCapability(cap);
}
RELEASE_LOCK(&cap->lock);
}
#endif // THREADED_RTS
...@@ -201,6 +201,8 @@ void waitForReturnCapability (Capability **cap/*in/out*/, Task *task); ...@@ -201,6 +201,8 @@ void waitForReturnCapability (Capability **cap/*in/out*/, Task *task);
INLINE_HEADER void recordMutableCap (StgClosure *p, Capability *cap, nat gen); INLINE_HEADER void recordMutableCap (StgClosure *p, Capability *cap, nat gen);
INLINE_HEADER void recordClosureMutated (Capability *cap, StgClosure *p);
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
// Gives up the current capability IFF there is a higher-priority // Gives up the current capability IFF there is a higher-priority
...@@ -222,12 +224,6 @@ void yieldCapability (Capability** pCap, Task *task); ...@@ -222,12 +224,6 @@ void yieldCapability (Capability** pCap, Task *task);
// //
void waitForCapability (Task *task, Mutex *mutex, Capability **pCap); void waitForCapability (Task *task, Mutex *mutex, Capability **pCap);
// Wakes up a thread on a Capability (probably a different Capability
// from the one held by the current Task).
//
void wakeupThreadOnCapability (Capability *my_cap, Capability *other_cap,
StgTSO *tso);
// Wakes up a worker thread on just one Capability, used when we // Wakes up a worker thread on just one Capability, used when we
// need to service some global event. // need to service some global event.
// //
...@@ -289,8 +285,6 @@ void traverseSparkQueues (evac_fn evac, void *user); ...@@ -289,8 +285,6 @@ void traverseSparkQueues (evac_fn evac, void *user);
INLINE_HEADER rtsBool emptyInbox(Capability *cap);; INLINE_HEADER rtsBool emptyInbox(Capability *cap);;
void sendMessage (Capability *cap, Message *msg);
#endif // THREADED_RTS #endif // THREADED_RTS
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
...@@ -316,6 +310,15 @@ recordMutableCap (StgClosure *p, Capability *cap, nat gen) ...@@ -316,6 +310,15 @@ recordMutableCap (StgClosure *p, Capability *cap, nat gen)
*bd->free++ = (StgWord)p; *bd->free++ = (StgWord)p;
} }
INLINE_HEADER void
recordClosureMutated (Capability *cap, StgClosure *p)
{
bdescr *bd;
bd = Bdescr((StgPtr)p);
if (bd->gen_no != 0) recordMutableCap(p,cap,bd->gen_no);
}
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
INLINE_HEADER rtsBool INLINE_HEADER rtsBool
emptySparkPoolCap (Capability *cap) emptySparkPoolCap (Capability *cap)
......
...@@ -62,8 +62,8 @@ StgWord16 closure_flags[] = { ...@@ -62,8 +62,8 @@ StgWord16 closure_flags[] = {
[UPDATE_FRAME] = ( _BTM ), [UPDATE_FRAME] = ( _BTM ),
[CATCH_FRAME] = ( _BTM ), [CATCH_FRAME] = ( _BTM ),
[STOP_FRAME] = ( _BTM ), [STOP_FRAME] = ( _BTM ),
[CAF_BLACKHOLE] = ( _BTM|_NS| _UPT ),
[BLACKHOLE] = ( _NS| _UPT ), [BLACKHOLE] = ( _NS| _UPT ),
[BLOCKING_QUEUE] = ( _NS| _MUT|_UPT ),
[MVAR_CLEAN] = (_HNF| _NS| _MUT|_UPT ), [MVAR_CLEAN] = (_HNF| _NS| _MUT|_UPT ),
[MVAR_DIRTY] = (_HNF| _NS| _MUT|_UPT ), [MVAR_DIRTY] = (_HNF| _NS| _MUT|_UPT ),
[ARR_WORDS] = (_HNF| _NS| _UPT ), [ARR_WORDS] = (_HNF| _NS| _UPT ),
......
...@@ -662,8 +662,6 @@ residencyCensus( void ) ...@@ -662,8 +662,6 @@ residencyCensus( void )
type = Thunk; type = Thunk;
break; break;