Commit a23661d2 authored by Ben Gamari's avatar Ben Gamari Committed by Simon Marlow

STM: Only wake up once

Previously, threads blocked on an STM retry would be sent a wakeup
message each time an unpark was requested. This could result in the
accumulation of a large number of wake-up messages, which would slow
wake-up once the sleeping thread is finally scheduled.

Here, we introduce a new closure type, STM_AWOKEN, which marks a TSO
which has been sent a wake-up message, allowing us to send only one
wakeup.
parent 658817bf
......@@ -744,6 +744,7 @@
#define NO_TREC stg_NO_TREC_closure
#define END_TSO_QUEUE stg_END_TSO_QUEUE_closure
#define STM_AWOKEN stg_STM_AWOKEN_closure
#define END_INVARIANT_CHECK_QUEUE stg_END_INVARIANT_CHECK_QUEUE_closure
#define recordMutableCap(p, gen) \
......
......@@ -218,7 +218,8 @@ void dirty_STACK (Capability *cap, StgStack *stack);
BlockedOnMVar the MVAR the MVAR's queue
BlockedOnSTM END_TSO_QUEUE STM wait queue(s)
BlockedOnSTM END_TSO_QUEUE STM wait queue(s)
BlockedOnSTM STM_AWOKEN run queue
BlockedOnMsgThrowTo MessageThrowTo * TSO->blocked_exception
......@@ -252,5 +253,6 @@ void dirty_STACK (Capability *cap, StgStack *stack);
/* this is the NIL ptr for a TSO queue (e.g. runnable queue) */
#define END_TSO_QUEUE ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure)
#define STM_AWOKEN ((StgTSO *)(void*)&stg_STM_AWOKEN_closure)
#endif /* RTS_STORAGE_TSO_H */
......@@ -114,6 +114,7 @@ RTS_ENTRY(stg_MUT_ARR_PTRS_FROZEN0);
RTS_ENTRY(stg_MUT_VAR_CLEAN);
RTS_ENTRY(stg_MUT_VAR_DIRTY);
RTS_ENTRY(stg_END_TSO_QUEUE);
RTS_ENTRY(stg_STM_AWOKEN);
RTS_ENTRY(stg_MSG_TRY_WAKEUP);
RTS_ENTRY(stg_MSG_THROWTO);
RTS_ENTRY(stg_MSG_BLACKHOLE);
......@@ -142,6 +143,7 @@ RTS_ENTRY(stg_NO_TREC);
/* closures */
RTS_CLOSURE(stg_END_TSO_QUEUE_closure);
RTS_CLOSURE(stg_STM_AWOKEN_closure);
RTS_CLOSURE(stg_NO_FINALIZER_closure);
RTS_CLOSURE(stg_dummy_ret_closure);
RTS_CLOSURE(stg_forceIO_closure);
......
......@@ -380,13 +380,19 @@ static void unpark_tso(Capability *cap, StgTSO *tso) {
// Unblocking a TSO from BlockedOnSTM is done under the TSO lock,
// to avoid multiple CPUs unblocking the same TSO, and also to
// synchronise with throwTo().
// synchronise with throwTo(). The first time the TSO is unblocked
// we mark this fact by setting block_info.closure == STM_AWOKEN.
// This way we can avoid sending further wakeup messages in the
// future.
lockTSO(tso);
if (tso -> why_blocked == BlockedOnSTM) {
TRACE("unpark_tso on tso=%p", tso);
tryWakeupThread(cap,tso);
if (tso->why_blocked == BlockedOnSTM && tso->block_info.closure == STM_AWOKEN) {
TRACE("unpark_tso already woken up tso=%p", tso);
} else if (tso -> why_blocked == BlockedOnSTM) {
TRACE("unpark_tso on tso=%p", tso);
tso->block_info.closure = STM_AWOKEN;
tryWakeupThread(cap,tso);
} else {
TRACE("spurious unpark_tso on tso=%p", tso);
TRACE("spurious unpark_tso on tso=%p", tso);
}
unlockTSO(tso);
}
......
......@@ -546,6 +546,18 @@ INFO_TABLE_CONSTR(stg_END_TSO_QUEUE,0,0,0,CONSTR_NOCAF_STATIC,"END_TSO_QUEUE","E
CLOSURE(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE);
/* ----------------------------------------------------------------------------
STM_AWOKEN
This is a static nullary constructor (like []) that we use to mark a
thread waiting on an STM wakeup
------------------------------------------------------------------------- */
INFO_TABLE_CONSTR(stg_STM_AWOKEN,0,0,0,CONSTR_NOCAF_STATIC,"STM_AWOKEN","STM_AWOKEN")
{ foreign "C" barf("STM_AWOKEN object entered!") never returns; }
CLOSURE(stg_STM_AWOKEN_closure,stg_STM_AWOKEN);
/* ----------------------------------------------------------------------------
Arrays
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment