diff options
author | Ben Gamari <ben@smart-cactus.org> | 2019-10-01 22:23:03 +0000 |
---|---|---|
committer | Moritz Angermann <moritz.angermann@gmail.com> | 2020-09-18 08:10:15 +0000 |
commit | 7692aba38100226c23ec3c1d98cbd2115489de70 (patch) | |
tree | dad5915a47f2aa2d9537cce0cebadd69b2ecf443 | |
parent | aebdcdb8aa18c0fd122716d221abc2f1c776fc06 (diff) | |
download | haskell-7692aba38100226c23ec3c1d98cbd2115489de70.tar.gz |
rts: Pause timer while changing capability count
This avoids #17289.
-rw-r--r-- | rts/Schedule.c | 8 | ||||
-rw-r--r-- | rts/Timer.c | 24 |
2 files changed, 21 insertions, 11 deletions
diff --git a/rts/Schedule.c b/rts/Schedule.c index c5618f9af8..f95247e703 100644 --- a/rts/Schedule.c +++ b/rts/Schedule.c @@ -2189,6 +2189,12 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS) cap = rts_lock(); task = cap->running_task; + + // N.B. We must stop the interval timer while we are changing the + // capabilities array lest handle_tick may try to context switch + // an old capability. See #17289. + stopTimer(); + stopAllCapabilities(&cap, task); if (new_n_capabilities < enabled_capabilities) @@ -2271,6 +2277,8 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS) // Notify IO manager that the number of capabilities has changed. rts_evalIO(&cap, ioManagerCapabilitiesChanged_closure, NULL); + startTimer(); + rts_unlock(cap); #endif // THREADED_RTS diff --git a/rts/Timer.c b/rts/Timer.c index fac387673d..7403b63d8c 100644 --- a/rts/Timer.c +++ b/rts/Timer.c @@ -25,6 +25,15 @@ #include "Capability.h" #include "RtsSignals.h" +// This global counter is used to allow multiple threads to stop the +// timer temporarily with a stopTimer()/startTimer() pair. If +// timer_enabled == 0 timer is enabled +// timer_disabled == N, N > 0 timer is disabled by N threads +// When timer_enabled makes a transition to 0, we enable the timer, +// and when it makes a transition to non-0 we disable it. + +static StgWord timer_disabled; + /* ticks left before next pre-emptive context switch */ static int ticks_to_ctxt_switch = 0; @@ -92,7 +101,9 @@ void handle_tick(int unused STG_UNUSED) { handleProfTick(); - if (RtsFlags.ConcFlags.ctxtSwitchTicks > 0) { + if (RtsFlags.ConcFlags.ctxtSwitchTicks > 0 + && RELAXED_LOAD(&timer_disabled) == 0) + { ticks_to_ctxt_switch--; if (ticks_to_ctxt_switch <= 0) { ticks_to_ctxt_switch = RtsFlags.ConcFlags.ctxtSwitchTicks; @@ -148,15 +159,6 @@ handle_tick(int unused STG_UNUSED) } } -// This global counter is used to allow multiple threads to stop the -// timer temporarily with a stopTimer()/startTimer() pair. If -// timer_enabled == 0 timer is enabled -// timer_disabled == N, N > 0 timer is disabled by N threads -// When timer_enabled makes a transition to 0, we enable the timer, -// and when it makes a transition to non-0 we disable it. - -static StgWord timer_disabled; - void initTimer(void) { @@ -164,7 +166,7 @@ initTimer(void) if (RtsFlags.MiscFlags.tickInterval != 0) { initTicker(RtsFlags.MiscFlags.tickInterval, handle_tick); } - timer_disabled = 1; + RELAXED_STORE(&timer_disabled, 1); } void |