[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