[Git][ghc/ghc][wip/tsan/fixes] 9 commits: rts: Encapsulate sched_state
Ben Gamari (@bgamari)
gitlab at gitlab.haskell.org
Tue Dec 6 03:48:03 UTC 2022
Ben Gamari pushed to branch wip/tsan/fixes at Glasgow Haskell Compiler / GHC
Commits:
e07d269d by Ben Gamari at 2022-12-05T22:47:53-05:00
rts: Encapsulate sched_state
- - - - -
36f40b3e by Ben Gamari at 2022-12-05T22:47:53-05:00
PrimOps: Fix benign MutVar race
Relaxed ordering is fine here since the later CAS implies a release.
- - - - -
e3aef00c by Ben Gamari at 2022-12-05T22:47:53-05:00
rts: Style fix
- - - - -
82d87c8d by Ben Gamari at 2022-12-05T22:47:53-05:00
compiler: Use release store in eager blackholing
- - - - -
db034924 by Ben Gamari at 2022-12-05T22:47:53-05:00
rts: Fix ordering of makeStableName
- - - - -
658e4f4c by Ben Gamari at 2022-12-05T22:47:53-05:00
rts: Use ordered accesses instead of explicit barriers
- - - - -
a809de0c by Ben Gamari at 2022-12-05T22:47:53-05:00
rts: Statically allocate capabilities
This is a rather simplistic way of solving #17289.
- - - - -
bc22d7c6 by Ben Gamari at 2022-12-05T22:47:53-05:00
rts: Ensure that all accesses to pending_sync are atomic
- - - - -
246bdfa9 by Ben Gamari at 2022-12-05T22:47:53-05:00
rts: Note race with wakeBlockingQueue
- - - - -
17 changed files:
- compiler/GHC/StgToCmm/Bind.hs
- rts/Capability.c
- rts/Capability.h
- rts/PrimOps.cmm
- rts/Schedule.c
- rts/Schedule.h
- rts/StgMiscClosures.cmm
- rts/eventlog/EventLog.c
- rts/include/Cmm.h
- rts/include/rts/Config.h
- rts/posix/Select.c
- rts/posix/Signals.c
- rts/sm/GC.c
- rts/sm/NonMoving.c
- rts/win32/AsyncMIO.c
- rts/win32/AwaitEvent.c
- rts/win32/ConsoleHandler.c
Changes:
=====================================
compiler/GHC/StgToCmm/Bind.hs
=====================================
@@ -703,8 +703,8 @@ emitBlackHoleCode node = do
whenUpdRemSetEnabled $ emitUpdRemSetPushThunk node
emitStore (cmmOffsetW platform node (fixedHdrSizeW profile)) currentTSOExpr
-- See Note [Heap memory barriers] in SMP.h.
- emitPrimCall [] MO_WriteBarrier []
- emitStore node (CmmReg (CmmGlobal EagerBlackholeInfo))
+ let w = wordWidth platform
+ emitPrimCall [] (MO_AtomicWrite w MemOrderRelease) [node, CmmReg (CmmGlobal EagerBlackholeInfo)]
setupUpdate :: ClosureInfo -> LocalReg -> FCode () -> FCode ()
-- Nota Bene: this function does not change Node (even if it's a CAF),
=====================================
rts/Capability.c
=====================================
@@ -45,7 +45,7 @@ uint32_t enabled_capabilities = 0;
// Capabilities, because there may be pointers to them in use
// (e.g. threads in waitForCapability(), see #8209), so this is
// an array of Capability* rather than an array of Capability.
-Capability **capabilities = NULL;
+Capability *capabilities[MAX_N_CAPABILITIES];
// Holds the Capability which last became free. This is used so that
// an in-call has a chance of quickly finding a free Capability.
@@ -82,7 +82,7 @@ Capability * rts_unsafeGetMyCapability (void)
STATIC_INLINE bool
globalWorkToDo (void)
{
- return RELAXED_LOAD(&sched_state) >= SCHED_INTERRUPTING
+ return getSchedState() >= SCHED_INTERRUPTING
|| getRecentActivity() == ACTIVITY_INACTIVE; // need to check for deadlock
}
#endif
@@ -387,6 +387,12 @@ void initCapabilities (void)
}
#endif
+ if (RtsFlags.ParFlags.nCapabilities > MAX_N_CAPABILITIES) {
+ errorBelch("warning: this GHC runtime system only supports up to %d capabilities",
+ MAX_N_CAPABILITIES);
+ RtsFlags.ParFlags.nCapabilities = MAX_N_CAPABILITIES;
+ }
+
n_capabilities = 0;
moreCapabilities(0, RtsFlags.ParFlags.nCapabilities);
n_capabilities = RtsFlags.ParFlags.nCapabilities;
@@ -394,7 +400,6 @@ void initCapabilities (void)
#else /* !THREADED_RTS */
n_capabilities = 1;
- capabilities = stgMallocBytes(sizeof(Capability*), "initCapabilities");
capabilities[0] = &MainCapability;
initCapability(&MainCapability, 0);
@@ -415,8 +420,6 @@ void
moreCapabilities (uint32_t from USED_IF_THREADS, uint32_t to USED_IF_THREADS)
{
#if defined(THREADED_RTS)
- Capability **new_capabilities = stgMallocBytes(to * sizeof(Capability*), "moreCapabilities");
-
// We must disable the timer while we do this since the tick handler may
// call contextSwitchAllCapabilities, which may see the capabilities array
// as we free it. The alternative would be to protect the capabilities
@@ -428,30 +431,22 @@ moreCapabilities (uint32_t from USED_IF_THREADS, uint32_t to USED_IF_THREADS)
// THREADED_RTS must work on builds that don't have a mutable
// BaseReg (eg. unregisterised), so in this case
// capabilities[0] must coincide with &MainCapability.
- new_capabilities[0] = &MainCapability;
+ capabilities[0] = &MainCapability;
initCapability(&MainCapability, 0);
}
else
{
for (uint32_t i = 0; i < to; i++) {
- if (i < from) {
- new_capabilities[i] = capabilities[i];
- } else {
- new_capabilities[i] = stgMallocBytes(sizeof(Capability),
+ if (i >= from) {
+ capabilities[i] = stgMallocBytes(sizeof(Capability),
"moreCapabilities");
- initCapability(new_capabilities[i], i);
+ initCapability(capabilities[i], i);
}
}
}
debugTrace(DEBUG_sched, "allocated %d more capabilities", to - from);
- Capability **old_capabilities = ACQUIRE_LOAD(&capabilities);
- RELEASE_STORE(&capabilities, new_capabilities);
- if (old_capabilities != NULL) {
- stgFree(old_capabilities);
- }
-
startTimer();
#endif
}
@@ -581,7 +576,7 @@ releaseCapability_ (Capability* cap,
// is interrupted, we only create a worker task if there
// are threads that need to be completed. If the system is
// shutting down, we never create a new worker.
- if (RELAXED_LOAD(&sched_state) < SCHED_SHUTTING_DOWN || !emptyRunQueue(cap)) {
+ if (getSchedState() < SCHED_SHUTTING_DOWN || !emptyRunQueue(cap)) {
debugTrace(DEBUG_sched,
"starting new worker on capability %d", cap->no);
startWorkerTask(cap);
@@ -1153,7 +1148,7 @@ shutdownCapability (Capability *cap USED_IF_THREADS,
// isn't safe, for one thing).
for (i = 0; /* i < 50 */; i++) {
- ASSERT(sched_state == SCHED_SHUTTING_DOWN);
+ ASSERT(getSchedState() == SCHED_SHUTTING_DOWN);
debugTrace(DEBUG_sched,
"shutting down capability %d, attempt %d", cap->no, i);
@@ -1285,7 +1280,6 @@ freeCapabilities (void)
#else
freeCapability(&MainCapability);
#endif
- stgFree(capabilities);
traceCapsetDelete(CAPSET_OSPROCESS_DEFAULT);
traceCapsetDelete(CAPSET_CLOCKDOMAIN_DEFAULT);
}
=====================================
rts/Capability.h
=====================================
@@ -261,11 +261,11 @@ INLINE_HEADER void releaseCapability_ (Capability* cap STG_UNUSED,
// extern uint32_t enabled_capabilities;
// Array of all the capabilities
-extern Capability **capabilities;
+extern Capability *capabilities[MAX_N_CAPABILITIES];
INLINE_HEADER Capability *getCapability(uint32_t i)
{
- return RELAXED_LOAD(&capabilities)[i];
+ return RELAXED_LOAD(&capabilities[i]);
}
//
=====================================
rts/PrimOps.cmm
=====================================
@@ -776,7 +776,7 @@ stg_atomicModifyMutVar2zh ( gcptr mv, gcptr f )
StgThunk_payload(y,0) = z;
retry:
- x = StgMutVar_var(mv);
+ x = %relaxed StgMutVar_var(mv);
StgThunk_payload(z,1) = x;
#if defined(THREADED_RTS)
(h) = prim %cmpxchgW(mv + SIZEOF_StgHeader + OFFSET_StgMutVar_var, x, y);
@@ -829,7 +829,7 @@ stg_atomicModifyMutVarzuzh ( gcptr mv, gcptr f )
StgThunk_payload(z,0) = f;
retry:
- x = StgMutVar_var(mv);
+ x = %relaxed StgMutVar_var(mv);
StgThunk_payload(z,1) = x;
#if defined(THREADED_RTS)
(h) = prim %cmpxchgW(mv + SIZEOF_StgHeader + OFFSET_StgMutVar_var, x, z);
@@ -1728,7 +1728,7 @@ stg_takeMVarzh ( P_ mvar /* :: MVar a */ )
// Write barrier before we make the new MVAR_TSO_QUEUE
// visible to other cores.
// See Note [Heap memory barriers]
- prim_write_barrier;
+ RELEASE_FENCE;
if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
StgMVar_head(mvar) = q;
@@ -1895,7 +1895,7 @@ stg_putMVarzh ( P_ mvar, /* :: MVar a */
SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
// See Note [Heap memory barriers]
- prim_write_barrier;
+ RELEASE_FENCE;
if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
StgMVar_head(mvar) = q;
@@ -2104,7 +2104,7 @@ stg_readMVarzh ( P_ mvar, /* :: MVar a */ )
SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
// See Note [Heap memory barriers]
- prim_write_barrier;
+ RELEASE_FENCE;
StgTSO__link(CurrentTSO) = q;
StgTSO_block_info(CurrentTSO) = mvar;
@@ -2237,7 +2237,7 @@ stg_readIOPortzh ( P_ ioport /* :: IOPort a */ )
SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
// See Note [Heap memory barriers]
- prim_write_barrier;
+ RELEASE_FENCE;
StgMVar_head(ioport) = q;
StgTSO__link(CurrentTSO) = q;
@@ -2389,7 +2389,8 @@ stg_makeStableNamezh ( P_ obj )
/* Is there already a StableName for this heap object?
* stable_name_table is a pointer to an array of snEntry structs.
*/
- if ( snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry) == NULL ) {
+ sn_obj = %acquire snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry);
+ if (sn_obj == NULL) {
// At this point we have a snEntry, but it doesn't look as used to the
// GC yet because we don't have a StableName object for the sn_obj field
// (remember that sn_obj == NULL means the entry is free). So if we call
@@ -2406,10 +2407,7 @@ stg_makeStableNamezh ( P_ obj )
// This will make the StableName# object visible to other threads;
// be sure that its completely visible to other cores.
// See Note [Heap memory barriers] in SMP.h.
- prim_write_barrier;
- snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry) = sn_obj;
- } else {
- sn_obj = snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry);
+ %release snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry) = sn_obj;
}
return (sn_obj);
=====================================
rts/Schedule.c
=====================================
@@ -91,7 +91,7 @@ StgWord recent_activity = ACTIVITY_YES;
/* if this flag is set as well, give up execution
* LOCK: none (changes monotonically)
*/
-volatile StgWord sched_state = SCHED_RUNNING;
+StgWord sched_state = SCHED_RUNNING;
/*
* This mutex protects most of the global scheduler data in
@@ -166,7 +166,6 @@ static void deleteAllThreads (void);
static void deleteThread_(StgTSO *tso);
#endif
-
/* ---------------------------------------------------------------------------
Main scheduling loop.
@@ -254,7 +253,7 @@ schedule (Capability *initialCapability, Task *task)
// * We might be left with threads blocked in foreign calls,
// we should really attempt to kill these somehow (TODO).
- switch (RELAXED_LOAD(&sched_state)) {
+ switch (getSchedState()) {
case SCHED_RUNNING:
break;
case SCHED_INTERRUPTING:
@@ -266,7 +265,7 @@ schedule (Capability *initialCapability, Task *task)
// other Capability did the final GC, or we did it above,
// either way we can fall through to the SCHED_SHUTTING_DOWN
// case now.
- ASSERT(RELAXED_LOAD(&sched_state) == SCHED_SHUTTING_DOWN);
+ ASSERT(getSchedState() == SCHED_SHUTTING_DOWN);
// fall through
case SCHED_SHUTTING_DOWN:
@@ -321,7 +320,7 @@ schedule (Capability *initialCapability, Task *task)
*/
awaitEvent (cap, emptyRunQueue(cap));
#else
- ASSERT(sched_state >= SCHED_INTERRUPTING);
+ ASSERT(getSchedState() >= SCHED_INTERRUPTING);
#endif
}
#endif
@@ -371,7 +370,7 @@ schedule (Capability *initialCapability, Task *task)
// killed, kill it now. This sometimes happens when a finalizer
// thread is created by the final GC, or a thread previously
// in a foreign call returns.
- if (RELAXED_LOAD(&sched_state) >= SCHED_INTERRUPTING &&
+ if (getSchedState() >= SCHED_INTERRUPTING &&
!(t->what_next == ThreadComplete || t->what_next == ThreadKilled)) {
deleteThread(t);
}
@@ -688,7 +687,7 @@ scheduleYield (Capability **pcap, Task *task)
if (!shouldYieldCapability(cap,task,false) &&
(!emptyRunQueue(cap) ||
!emptyInbox(cap) ||
- RELAXED_LOAD(&sched_state) >= SCHED_INTERRUPTING)) {
+ getSchedState() >= SCHED_INTERRUPTING)) {
return;
}
@@ -991,7 +990,7 @@ scheduleDetectDeadlock (Capability **pcap, Task *task)
}
// either we have threads to run, or we were interrupted:
- ASSERT(!emptyRunQueue(cap) || sched_state >= SCHED_INTERRUPTING);
+ ASSERT(!emptyRunQueue(cap) || getSchedState() >= SCHED_INTERRUPTING);
return;
}
@@ -1343,7 +1342,7 @@ scheduleHandleThreadFinished (Capability *cap, Task *task, StgTSO *t)
if (task->incall->ret) {
*(task->incall->ret) = NULL;
}
- if (RELAXED_LOAD(&sched_state) >= SCHED_INTERRUPTING) {
+ if (getSchedState() >= SCHED_INTERRUPTING) {
if (heap_overflow) {
task->incall->rstat = HeapExhausted;
} else {
@@ -1431,7 +1430,7 @@ void stopAllCapabilitiesWith (Capability **pCap, Task *task, SyncType sync_type)
acquireAllCapabilities(pCap ? *pCap : NULL, task);
- pending_sync = 0;
+ RELAXED_STORE(&pending_sync, 0);
signalCondition(&sync_finished_cond);
}
#endif
@@ -1603,7 +1602,7 @@ scheduleDoGC (Capability **pcap, Task *task USED_IF_THREADS,
// cycle.
#endif
- if (RELAXED_LOAD(&sched_state) == SCHED_SHUTTING_DOWN) {
+ if (getSchedState() == SCHED_SHUTTING_DOWN) {
// The final GC has already been done, and the system is
// shutting down. We'll probably deadlock if we try to GC
// now.
@@ -1622,7 +1621,7 @@ scheduleDoGC (Capability **pcap, Task *task USED_IF_THREADS,
major_gc = (collect_gen == RtsFlags.GcFlags.generations-1);
#if defined(THREADED_RTS)
- if (RELAXED_LOAD(&sched_state) < SCHED_INTERRUPTING
+ if (getSchedState() < SCHED_INTERRUPTING
&& RtsFlags.ParFlags.parGcEnabled
&& collect_gen >= RtsFlags.ParFlags.parGcGen
&& ! oldest_gen->mark)
@@ -1715,7 +1714,7 @@ scheduleDoGC (Capability **pcap, Task *task USED_IF_THREADS,
}
if (was_syncing &&
(prev_sync == SYNC_GC_SEQ || prev_sync == SYNC_GC_PAR) &&
- !(RELAXED_LOAD(&sched_state) == SCHED_INTERRUPTING && force_major)) {
+ !(getSchedState() == SCHED_INTERRUPTING && force_major)) {
// someone else had a pending sync request for a GC, so
// let's assume GC has been done and we don't need to GC
// again.
@@ -1723,7 +1722,7 @@ scheduleDoGC (Capability **pcap, Task *task USED_IF_THREADS,
// need to do the final GC.
return;
}
- if (RELAXED_LOAD(&sched_state) == SCHED_SHUTTING_DOWN) {
+ if (getSchedState() == SCHED_SHUTTING_DOWN) {
// The scheduler might now be shutting down. We tested
// this above, but it might have become true since then as
// we yielded the capability in requestSync().
@@ -1826,7 +1825,7 @@ delete_threads_and_gc:
* threads in the system.
* Checking for major_gc ensures that the last GC is major.
*/
- if (RELAXED_LOAD(&sched_state) == SCHED_INTERRUPTING && major_gc) {
+ if (getSchedState() == SCHED_INTERRUPTING && major_gc) {
deleteAllThreads();
#if defined(THREADED_RTS)
// Discard all the sparks from every Capability. Why?
@@ -1840,7 +1839,7 @@ delete_threads_and_gc:
discardSparksCap(getCapability(i));
}
#endif
- RELAXED_STORE(&sched_state, SCHED_SHUTTING_DOWN);
+ setSchedState(SCHED_SHUTTING_DOWN);
}
/*
@@ -1877,7 +1876,7 @@ delete_threads_and_gc:
#if defined(THREADED_RTS)
// reset pending_sync *before* GC, so that when the GC threads
// emerge they don't immediately re-enter the GC.
- pending_sync = 0;
+ RELAXED_STORE(&pending_sync, 0);
signalCondition(&sync_finished_cond);
GarbageCollect(collect_gen, heap_census, is_overflow_gc, deadlock_detect, gc_type, cap, idle_cap);
#else
@@ -1885,7 +1884,7 @@ delete_threads_and_gc:
#endif
// If we're shutting down, don't leave any idle GC work to do.
- if (RELAXED_LOAD(&sched_state) == SCHED_SHUTTING_DOWN) {
+ if (getSchedState() == SCHED_SHUTTING_DOWN) {
doIdleGCWork(cap, true /* all of it */);
}
@@ -1962,7 +1961,7 @@ delete_threads_and_gc:
releaseGCThreads(cap, idle_cap);
}
#endif
- if (heap_overflow && RELAXED_LOAD(&sched_state) == SCHED_RUNNING) {
+ if (heap_overflow && getSchedState() == SCHED_RUNNING) {
// GC set the heap_overflow flag. We should throw an exception if we
// can, or shut down otherwise.
@@ -1974,7 +1973,7 @@ delete_threads_and_gc:
// shutdown now. Ultimately we want the main thread to return to
// its caller with HeapExhausted, at which point the caller should
// call hs_exit(). The first step is to delete all the threads.
- RELAXED_STORE(&sched_state, SCHED_INTERRUPTING);
+ setSchedState(SCHED_INTERRUPTING);
goto delete_threads_and_gc;
}
@@ -2720,7 +2719,7 @@ startWorkerTasks (uint32_t from USED_IF_THREADS, uint32_t to USED_IF_THREADS)
void
initScheduler(void)
{
- sched_state = SCHED_RUNNING;
+ setSchedState(SCHED_RUNNING);
setRecentActivity(ACTIVITY_YES);
@@ -2763,8 +2762,8 @@ exitScheduler (bool wait_foreign USED_IF_THREADS)
Task *task = newBoundTask();
// If we haven't killed all the threads yet, do it now.
- if (RELAXED_LOAD(&sched_state) < SCHED_SHUTTING_DOWN) {
- RELAXED_STORE(&sched_state, SCHED_INTERRUPTING);
+ if (getSchedState() < SCHED_SHUTTING_DOWN) {
+ setSchedState(SCHED_INTERRUPTING);
nonmovingStop();
Capability *cap = task->cap;
waitForCapability(&cap,task);
@@ -2772,7 +2771,7 @@ exitScheduler (bool wait_foreign USED_IF_THREADS)
ASSERT(task->incall->tso == NULL);
releaseCapability(cap);
}
- ASSERT(sched_state == SCHED_SHUTTING_DOWN);
+ ASSERT(getSchedState() == SCHED_SHUTTING_DOWN);
shutdownCapabilities(task, wait_foreign);
@@ -2851,8 +2850,8 @@ performMajorGC(void)
void
interruptStgRts(void)
{
- ASSERT(sched_state != SCHED_SHUTTING_DOWN);
- sched_state = SCHED_INTERRUPTING;
+ ASSERT(getSchedState() != SCHED_SHUTTING_DOWN);
+ setSchedState(SCHED_INTERRUPTING);
interruptAllCapabilities();
#if defined(THREADED_RTS)
wakeUpRts();
=====================================
rts/Schedule.h
=====================================
@@ -64,11 +64,23 @@ void releaseAllCapabilities(uint32_t n, Capability *keep_cap, Task *task);
/* The state of the scheduler. This is used to control the sequence
* of events during shutdown. See Note [shutdown] in Schedule.c.
*/
-#define SCHED_RUNNING 0 /* running as normal */
-#define SCHED_INTERRUPTING 1 /* before threads are deleted */
-#define SCHED_SHUTTING_DOWN 2 /* final shutdown */
+enum SchedState {
+ SCHED_RUNNING = 0, /* running as normal */
+ SCHED_INTERRUPTING = 1, /* before threads are deleted */
+ SCHED_SHUTTING_DOWN = 2, /* final shutdown */
+};
+
+extern StgWord sched_state;
-extern volatile StgWord sched_state;
+INLINE_HEADER void setSchedState(enum SchedState ss)
+{
+ SEQ_CST_STORE_ALWAYS(&sched_state, (StgWord) ss);
+}
+
+INLINE_HEADER enum SchedState getSchedState(void)
+{
+ return (enum SchedState) SEQ_CST_LOAD_ALWAYS(&sched_state);
+}
/*
* flag that tracks whether we have done any execution in this time
=====================================
rts/StgMiscClosures.cmm
=====================================
@@ -540,7 +540,8 @@ retry:
return (p);
}
- info = GET_INFO(p);
+ // May race with OVERWRITE_INFO in wakeBlockingQueue()
+ info = %relaxed GET_INFO(p);
if (info == stg_IND_info) {
// This could happen, if e.g. we got a BLOCKING_QUEUE that has
// just been replaced with an IND by another thread in
=====================================
rts/eventlog/EventLog.c
=====================================
@@ -478,7 +478,7 @@ endEventLogging(void)
//
// N.B. Don't flush if shutting down: this was done in
// finishCapEventLogging and the capabilities have already been freed.
- if (sched_state != SCHED_SHUTTING_DOWN) {
+ if (getSchedState() != SCHED_SHUTTING_DOWN) {
flushEventLog(NULL);
}
=====================================
rts/include/Cmm.h
=====================================
@@ -278,8 +278,7 @@
// "used".
#define LOAD_INFO_ACQUIRE(ret,x) \
- info = %INFO_PTR(UNTAG(x)); \
- prim_read_barrier;
+ info = %acquire StgHeader_info(UNTAG(x));
#define UNTAG_IF_PROF(x) UNTAG(x)
@@ -289,8 +288,7 @@
if (GETTAG(x) != 0) { \
ret(x); \
} \
- info = %INFO_PTR(x); \
- prim_read_barrier;
+ info = %acquire StgHeader_info(x);
#define UNTAG_IF_PROF(x) (x) /* already untagged */
=====================================
rts/include/rts/Config.h
=====================================
@@ -76,3 +76,9 @@ code.
#if defined(DEBUG)
#define PROF_SPIN
#endif
+
+#if defined(THREADED_RTS)
+#define MAX_N_CAPABILITIES 256
+#else
+#define MAX_N_CAPABILITIES 1
+#endif
=====================================
rts/posix/Select.c
=====================================
@@ -362,7 +362,7 @@ awaitEvent(Capability *cap, bool wait)
/* we were interrupted, return to the scheduler immediately.
*/
- if (sched_state >= SCHED_INTERRUPTING) {
+ if (getSchedState() >= SCHED_INTERRUPTING) {
return; /* still hold the lock */
}
@@ -459,7 +459,7 @@ awaitEvent(Capability *cap, bool wait)
}
}
- } while (wait && sched_state == SCHED_RUNNING
+ } while (wait && getSchedState() == SCHED_RUNNING
&& emptyRunQueue(cap));
}
=====================================
rts/posix/Signals.c
=====================================
@@ -350,7 +350,7 @@ anyUserHandlers(void)
void
awaitUserSignals(void)
{
- while (!signals_pending() && sched_state == SCHED_RUNNING) {
+ while (!signals_pending() && getSchedState() == SCHED_RUNNING) {
pause();
}
}
@@ -521,7 +521,7 @@ shutdown_handler(int sig STG_UNUSED)
// If we're already trying to interrupt the RTS, terminate with
// extreme prejudice. So the first ^C tries to exit the program
// cleanly, and the second one just kills it.
- if (sched_state >= SCHED_INTERRUPTING) {
+ if (getSchedState() >= SCHED_INTERRUPTING) {
stg_exit(EXIT_INTERRUPTED);
} else {
interruptStgRts();
=====================================
rts/sm/GC.c
=====================================
@@ -833,12 +833,9 @@ GarbageCollect (uint32_t collect_gen,
live_blocks += genLiveBlocks(gen);
// add in the partial blocks in the gen_workspaces
- {
- uint32_t i;
- for (i = 0; i < getNumCapabilities(); i++) {
- live_words += gcThreadLiveWords(i, gen->no);
- live_blocks += gcThreadLiveBlocks(i, gen->no);
- }
+ for (uint32_t i = 0; i < getNumCapabilities(); i++) {
+ live_words += gcThreadLiveWords(i, gen->no);
+ live_blocks += gcThreadLiveBlocks(i, gen->no);
}
} // for all generations
=====================================
rts/sm/NonMoving.c
=====================================
@@ -921,7 +921,7 @@ void nonmovingCollect(StgWeak **dead_weaks, StgTSO **resurrected_threads)
#if defined(THREADED_RTS)
// We can't start a new collection until the old one has finished
// We also don't run in final GC
- if (concurrent_coll_running || sched_state > SCHED_RUNNING) {
+ if (concurrent_coll_running || getSchedState() > SCHED_RUNNING) {
return;
}
#endif
@@ -994,7 +994,7 @@ void nonmovingCollect(StgWeak **dead_weaks, StgTSO **resurrected_threads)
// again for the sync if we let it go, because it'll immediately start doing
// a major GC, because that's what we do when exiting scheduler (see
// exitScheduler()).
- if (sched_state == SCHED_RUNNING) {
+ if (getSchedState() == SCHED_RUNNING) {
concurrent_coll_running = true;
nonmoving_write_barrier_enabled = true;
debugTrace(DEBUG_nonmoving_gc, "Starting concurrent mark thread");
@@ -1086,7 +1086,7 @@ static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO *
Task *task = newBoundTask();
// If at this point if we've decided to exit then just return
- if (sched_state > SCHED_RUNNING) {
+ if (getSchedState() > SCHED_RUNNING) {
// Note that we break our invariants here and leave segments in
// nonmovingHeap.sweep_list, don't free nonmoving_large_objects etc.
// However because we won't be running mark-sweep in the final GC this
=====================================
rts/win32/AsyncMIO.c
=====================================
@@ -247,7 +247,7 @@ start:
if (completed_hw == 0) {
// empty table, drop lock and wait
OS_RELEASE_LOCK(&queue_lock);
- if ( wait && sched_state == SCHED_RUNNING ) {
+ if ( wait && getSchedState() == SCHED_RUNNING ) {
DWORD dwRes = WaitForMultipleObjects(2, wait_handles,
FALSE, INFINITE);
switch (dwRes) {
=====================================
rts/win32/AwaitEvent.c
=====================================
@@ -56,7 +56,7 @@ awaitEvent(Capability *cap, bool wait)
// - the run-queue is now non- empty
} while (wait
- && sched_state == SCHED_RUNNING
+ && getSchedState() == SCHED_RUNNING
&& emptyRunQueue(cap)
);
}
=====================================
rts/win32/ConsoleHandler.c
=====================================
@@ -91,7 +91,7 @@ static BOOL WINAPI shutdown_handler(DWORD dwCtrlType)
// If we're already trying to interrupt the RTS, terminate with
// extreme prejudice. So the first ^C tries to exit the program
// cleanly, and the second one just kills it.
- if (sched_state >= SCHED_INTERRUPTING) {
+ if (getSchedState() >= SCHED_INTERRUPTING) {
stg_exit(EXIT_INTERRUPTED);
} else {
interruptStgRts();
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2cddf0c78ddfa1c19918b7c315c3158b9282de6d...246bdfa9cb8c91b875139cb6bb26b62a70a2a29c
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2cddf0c78ddfa1c19918b7c315c3158b9282de6d...246bdfa9cb8c91b875139cb6bb26b62a70a2a29c
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20221205/86850deb/attachment-0001.html>
More information about the ghc-commits
mailing list