[Git][ghc/ghc][master] 6 commits: testsuite/cloneStackLib: Fix incorrect format specifiers

Marge Bot (@marge-bot) gitlab at gitlab.haskell.org
Thu Aug 17 19:17:44 UTC 2023



Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC


Commits:
664468c0 by Ben Gamari at 2023-08-17T15:17:17-04:00
testsuite/cloneStackLib: Fix incorrect format specifiers

- - - - -
eaa835bb by Ben Gamari at 2023-08-17T15:17:17-04:00
rts/ipe: Fix const-correctness of IpeBufferListNode

Both info tables and the string table should be `const`

- - - - -
78f6f6fd by Ben Gamari at 2023-08-17T15:17:17-04:00
nonmoving: Drop dead debugging utilities

These are largely superceded by support in the ghc-utils GDB extension.

- - - - -
3f6e8f42 by Ben Gamari at 2023-08-17T15:17:17-04:00
nonmoving: Refactor management of mark thread

Here we refactor that treatment of the worker thread used by the
nonmoving GC for concurrent marking, avoiding creating a new thread with
every major GC cycle. As well, the new scheme is considerably easier to
reason about, consolidating all state in one place, accessed via a small
set of accessors with clear semantics.

- - - - -
88c32b7d by Ben Gamari at 2023-08-17T15:17:17-04:00
testsuite: Skip T23221 in nonmoving GC ways

This test is very dependent upon GC behavior.

- - - - -
381cfaed by Ben Gamari at 2023-08-17T15:17:17-04:00
ghc-heap: Don't expose stack dirty and marking fields

These are GC metadata and are not relevant to the end-user. Moreover,
they are unstable which makes ghc-heap harder to test than necessary.

- - - - -


15 changed files:

- libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
- libraries/ghc-heap/GHC/Exts/Stack/Decode.hs
- libraries/ghc-heap/cbits/Stack.cmm
- libraries/ghc-heap/tests/stack_misc_closures.hs
- rts/IPE.c
- rts/IPE.h
- rts/RtsAPI.c
- rts/Schedule.c
- rts/include/rts/IPE.h
- rts/sm/GC.c
- rts/sm/NonMoving.c
- rts/sm/NonMoving.h
- rts/sm/Sanity.c
- testsuite/tests/rts/all.T
- testsuite/tests/rts/cloneStackLib.c


Changes:

=====================================
libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
=====================================
@@ -387,8 +387,6 @@ type StgStackClosure = GenStgStackClosure Box
 data GenStgStackClosure b = GenStgStackClosure
       { ssc_info            :: !StgInfoTable
       , ssc_stack_size      :: !Word32 -- ^ stack size in *words*
-      , ssc_stack_dirty     :: !Word8 -- ^ non-zero => dirty
-      , ssc_stack_marking   :: !Word8
       , ssc_stack           :: ![GenStackFrame b]
       }
   deriving (Foldable, Functor, Generic, Show, Traversable)


=====================================
libraries/ghc-heap/GHC/Exts/Stack/Decode.hs
=====================================
@@ -170,13 +170,12 @@ foreign import prim "getStackClosurezh"
 
 foreign import prim "getStackFieldszh"
   getStackFields# ::
-    StackSnapshot# -> (# Word32#, Word8#, Word8# #)
+    StackSnapshot# -> Word32#
 
-getStackFields :: StackSnapshot# -> (Word32, Word8, Word8)
+getStackFields :: StackSnapshot# -> Word32
 getStackFields stackSnapshot# =
   case getStackFields# stackSnapshot# of
-    (# sSize#, sDirty#, sMarking# #) ->
-      (W32# sSize#, W8# sDirty#, W8# sMarking#)
+    sSize# -> W32# sSize#
 
 -- | `StackFrameLocation` of the top-most stack frame
 stackHead :: StackSnapshot# -> StackFrameLocation
@@ -409,15 +408,13 @@ decodeStack (StackSnapshot stack#) = do
   info <- getInfoTableForStack stack#
   case tipe info of
     STACK -> do
-      let (stack_size', stack_dirty', stack_marking') = getStackFields stack#
+      let stack_size' = getStackFields stack#
           sfls = stackFrameLocations stack#
       stack' <- mapM unpackStackFrame sfls
       pure $
         GenStgStackClosure
           { ssc_info = info,
             ssc_stack_size = stack_size',
-            ssc_stack_dirty = stack_dirty',
-            ssc_stack_marking = stack_marking',
             ssc_stack = stack'
           }
     _ -> error $ "Expected STACK closure, got " ++ show info


=====================================
libraries/ghc-heap/cbits/Stack.cmm
=====================================
@@ -173,15 +173,10 @@ getStackClosurezh(P_ stack, W_ offsetWords) {
   return (closure);
 }
 
-// (bits32, bits8, bits8) getStackFieldszh(StgStack* stack)
+// (bits32) getStackFieldszh(StgStack* stack)
 getStackFieldszh(P_ stack){
   bits32 size;
-  bits8 dirty, marking;
-
   size = StgStack_stack_size(stack);
-  dirty = StgStack_dirty(stack);
-  marking = StgStack_marking(stack);
-
-  return (size, dirty, marking);
+  return (size);
 }
 #endif


=====================================
libraries/ghc-heap/tests/stack_misc_closures.hs
=====================================
@@ -308,8 +308,6 @@ main = do
         assertEqual (tipe info_tbl) UNDERFLOW_FRAME
         assertEqual (tipe (ssc_info nextChunk)) STACK
         assertEqual (ssc_stack_size nextChunk) 27
-        assertEqual (ssc_stack_dirty nextChunk) 0
-        assertEqual (ssc_stack_marking nextChunk) 0
         assertEqual (length (ssc_stack nextChunk)) 2
         case head (ssc_stack nextChunk) of
           RetSmall {..} ->


=====================================
rts/IPE.c
=====================================
@@ -114,7 +114,7 @@ void dumpIPEToEventLog(void) {
     IpeBufferListNode *cursor = RELAXED_LOAD(&ipeBufferList);
     while (cursor != NULL) {
         IpeBufferEntry *entries;
-        char *strings;
+        const char *strings;
 
         // Decompress if compressed
         decompressIPEBufferListNodeIfCompressed(cursor, &entries, &strings);
@@ -190,7 +190,7 @@ void updateIpeMap(void) {
     while (pending != NULL) {
         IpeBufferListNode *current_node = pending;
         IpeBufferEntry *entries;
-        char *strings;
+        const char *strings;
 
         // Decompress if compressed
         decompressIPEBufferListNodeIfCompressed(current_node, &entries, &strings);
@@ -220,7 +220,7 @@ referenced by the 'entries_dst' and 'string_table_dst' parameters will point at
 the decompressed IPE data and string table for the given node, respectively,
 upon return from this function.
 */
-void decompressIPEBufferListNodeIfCompressed(IpeBufferListNode *node, IpeBufferEntry **entries_dst, char **string_table_dst) {
+void decompressIPEBufferListNodeIfCompressed(IpeBufferListNode *node, IpeBufferEntry **entries_dst, const char **string_table_dst) {
     if (node->compressed == 1) {
         // The IPE list buffer node indicates that the strings table and
         // entries list has been compressed. If zstd is not available, fail.


=====================================
rts/IPE.h
=====================================
@@ -17,6 +17,6 @@ void dumpIPEToEventLog(void);
 void updateIpeMap(void);
 void initIpe(void);
 void exitIpe(void);
-void decompressIPEBufferListNodeIfCompressed(IpeBufferListNode*, IpeBufferEntry**, char**);
+void decompressIPEBufferListNodeIfCompressed(IpeBufferListNode*, IpeBufferEntry**, const char**);
 
 #include "EndPrivate.h"


=====================================
rts/RtsAPI.c
=====================================
@@ -716,7 +716,7 @@ PauseToken *rts_pause (void)
     // so pausing the mutator while a collection is ongoing might lead to deadlock or
     // capabilities being prematurely re-awoken.
     if (RtsFlags.GcFlags.useNonmoving) {
-      ACQUIRE_LOCK(&nonmoving_collection_mutex);
+        nonmovingBlockConcurrentMark(true);
     }
 
 
@@ -784,7 +784,7 @@ void rts_resume (PauseToken *pauseToken)
     stgFree(pauseToken);
 
     if (RtsFlags.GcFlags.useNonmoving) {
-      RELEASE_LOCK(&nonmoving_collection_mutex);
+        nonmovingUnblockConcurrentMark();
     }
 }
 


=====================================
rts/Schedule.c
=====================================
@@ -2786,7 +2786,6 @@ exitScheduler (bool wait_foreign USED_IF_THREADS)
     // If we haven't killed all the threads yet, do it now.
     if (getSchedState() < SCHED_SHUTTING_DOWN) {
         setSchedState(SCHED_INTERRUPTING);
-        nonmovingStop();
         Capability *cap = task->cap;
         waitForCapability(&cap,task);
         scheduleDoGC(&cap,task,true,false,false,true);


=====================================
rts/include/rts/IPE.h
=====================================
@@ -76,12 +76,12 @@ typedef struct IpeBufferListNode_ {
 
     // When TNTC is enabled, these will point to the entry code
     // not the info table itself.
-    StgInfoTable **tables;
+    const StgInfoTable **tables;
 
     IpeBufferEntry *entries;
     StgWord entries_size; // decompressed size
 
-    char *string_table;
+    const char *string_table;
     StgWord string_table_size; // decompressed size
 } IpeBufferListNode;
 


=====================================
rts/sm/GC.c
=====================================
@@ -354,7 +354,7 @@ GarbageCollect (struct GcConfig config,
   deadlock_detect_gc = config.deadlock_detect;
 
 #if defined(THREADED_RTS)
-  if (major_gc && RtsFlags.GcFlags.useNonmoving && RELAXED_LOAD(&concurrent_coll_running)) {
+  if (major_gc && RtsFlags.GcFlags.useNonmoving && nonmovingConcurrentMarkIsRunning()) {
       /* If there is already a concurrent major collection running then
        * there is no benefit to starting another.
        * TODO: Catch heap-size runaway.


=====================================
rts/sm/NonMoving.c
=====================================
@@ -38,18 +38,6 @@ static void nonmovingBumpEpoch(void) {
     nonmovingMarkEpoch = nonmovingMarkEpoch == 1 ? 2 : 1;
 }
 
-#if defined(THREADED_RTS)
-/*
- * This mutex ensures that only one non-moving collection is active at a time.
- */
-Mutex nonmoving_collection_mutex;
-
-OSThreadId mark_thread;
-bool concurrent_coll_running = false;
-Condition concurrent_coll_finished;
-Mutex concurrent_coll_finished_lock;
-#endif
-
 /*
  * Note [Non-moving garbage collector]
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -546,11 +534,12 @@ memcount nonmoving_segment_live_words = 0;
 // See Note [Sync phase marking budget].
 MarkBudget sync_phase_marking_budget = 200000;
 
-#if defined(THREADED_RTS)
-static void* nonmovingConcurrentMark(void *mark_queue);
-#endif
 static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO **resurrected_threads, bool concurrent);
 
+static void nonmovingInitConcurrentWorker(void);
+static void nonmovingStartConcurrentMark(MarkQueue *roots);
+static void nonmovingExitConcurrentWorker(void);
+
 // Add a segment to the free list.
 void nonmovingPushFreeSegment(struct NonmovingSegment *seg)
 {
@@ -594,44 +583,14 @@ unsigned int nonmovingBlockCountFromSize(uint8_t log_block_size)
 void nonmovingInit(void)
 {
     if (! RtsFlags.GcFlags.useNonmoving) return;
-#if defined(THREADED_RTS)
-    initMutex(&nonmoving_collection_mutex);
-    initCondition(&concurrent_coll_finished);
-    initMutex(&concurrent_coll_finished_lock);
-#endif
+    nonmovingInitConcurrentWorker();
     nonmovingMarkInit();
 }
 
-// Stop any nonmoving collection in preparation for RTS shutdown.
-void nonmovingStop(void)
-{
-    if (! RtsFlags.GcFlags.useNonmoving) return;
-#if defined(THREADED_RTS)
-    if (RELAXED_LOAD(&mark_thread)) {
-        debugTrace(DEBUG_nonmoving_gc,
-                   "waiting for nonmoving collector thread to terminate");
-        ACQUIRE_LOCK(&concurrent_coll_finished_lock);
-        waitCondition(&concurrent_coll_finished, &concurrent_coll_finished_lock);
-        RELEASE_LOCK(&concurrent_coll_finished_lock);
-    }
-#endif
-}
-
 void nonmovingExit(void)
 {
     if (! RtsFlags.GcFlags.useNonmoving) return;
-
-    // First make sure collector is stopped before we tear things down.
-    nonmovingStop();
-
-#if defined(THREADED_RTS)
-    ACQUIRE_LOCK(&nonmoving_collection_mutex);
-    RELEASE_LOCK(&nonmoving_collection_mutex);
-
-    closeMutex(&concurrent_coll_finished_lock);
-    closeCondition(&concurrent_coll_finished);
-    closeMutex(&nonmoving_collection_mutex);
-#endif
+    nonmovingExitConcurrentWorker();
 }
 
 /* Prepare the heap bitmaps and snapshot metadata for a mark */
@@ -715,14 +674,19 @@ static void nonmovingPrepareMark(void)
 #endif
 }
 
-void nonmovingCollect(StgWeak **dead_weaks, StgTSO **resurrected_threads, bool concurrent STG_UNUSED)
+void nonmovingCollect(StgWeak **dead_weaks, StgTSO **resurrected_threads, bool concurrent)
 {
 #if defined(THREADED_RTS)
-    // We can't start a new collection until the old one has finished
+    // We can't start a new collection until the old one has finished.
     // We also don't run in final GC
-    if (RELAXED_LOAD(&concurrent_coll_running) || getSchedState() > SCHED_RUNNING) {
+    if (nonmovingConcurrentMarkIsRunning()) {
+        trace(TRACE_nonmoving_gc, "Aborted nonmoving collection due to on-going collection");
+    } else if (getSchedState() > SCHED_RUNNING) {
+        trace(TRACE_nonmoving_gc, "Aborted nonmoving collection due to on-going shutdown");
         return;
     }
+#else
+    concurrent = false;
 #endif
 
     trace(TRACE_nonmoving_gc, "Starting nonmoving GC preparation");
@@ -819,28 +783,15 @@ void nonmovingCollect(StgWeak **dead_weaks, StgTSO **resurrected_threads, bool c
         concurrent = false;
     }
 
-#if defined(THREADED_RTS)
     if (concurrent) {
-        RELAXED_STORE(&concurrent_coll_running, true);
-        nonmoving_write_barrier_enabled = true;
-        debugTrace(DEBUG_nonmoving_gc, "Starting concurrent mark thread");
-        OSThreadId thread;
-        if (createOSThread(&thread, "nonmoving-mark",
-                           nonmovingConcurrentMark, mark_queue) != 0) {
-            barf("nonmovingCollect: failed to spawn mark thread: %s", strerror(errno));
-        }
-        RELAXED_STORE(&mark_thread, thread);
-        return;
+        nonmovingStartConcurrentMark(mark_queue);
     } else {
         RELEASE_SM_LOCK;
-    }
-#endif
 
-    // Use the weak and thread lists from the preparation for any new weaks and
-    // threads found to be dead in mark.
-    nonmovingMark_(mark_queue, dead_weaks, resurrected_threads, false);
+        // Use the weak and thread lists from the preparation for any new weaks and
+        // threads found to be dead in mark.
+        nonmovingMark_(mark_queue, dead_weaks, resurrected_threads, false);
 
-    if (!concurrent) {
         ACQUIRE_SM_LOCK;
     }
 }
@@ -868,14 +819,155 @@ static bool nonmovingMarkThreadsWeaks(MarkBudget *budget, MarkQueue *mark_queue)
     }
 }
 
-#if defined(THREADED_RTS)
-static void* nonmovingConcurrentMark(void *data)
+#if !defined(THREADED_RTS)
+
+static void nonmovingInitConcurrentWorker(void) {}
+static void nonmovingExitConcurrentWorker(void) {}
+
+static void STG_NORETURN nonmovingStartConcurrentMark(MarkQueue *roots STG_UNUSED)
+{
+    barf("nonmovingStartConcurrentMark: Not supported in non-threaded RTS");
+}
+
+bool nonmovingConcurrentMarkIsRunning(void)
+{
+    return false;
+}
+
+bool nonmovingBlockConcurrentMark(bool wait STG_UNUSED) { return true; }
+void nonmovingUnblockConcurrentMark(void) {}
+
+#else
+
+enum ConcurrentWorkerState {
+    CONCURRENT_WORKER_IDLE,
+    CONCURRENT_WORKER_RUNNING,
+    CONCURRENT_WORKER_STOPPED,
+};
+
+Mutex concurrent_coll_lock;
+MarkQueue *concurrent_mark_roots;
+Condition start_concurrent_mark_cond;
+Condition concurrent_coll_finished_cond;
+enum ConcurrentWorkerState concurrent_worker_state;
+bool stop_concurrent_worker;
+OSThreadId concurrent_worker_thread;
+
+static void* nonmovingConcurrentMarkWorker(void *data STG_UNUSED)
 {
-    MarkQueue *mark_queue = (MarkQueue*)data;
-    StgWeak *dead_weaks = NULL;
-    StgTSO *resurrected_threads = (StgTSO*)&stg_END_TSO_QUEUE_closure;
-    nonmovingMark_(mark_queue, &dead_weaks, &resurrected_threads, true);
-    return NULL;
+    newBoundTask();
+
+    ACQUIRE_LOCK(&concurrent_coll_lock);
+    while (true) {
+        concurrent_worker_state = CONCURRENT_WORKER_IDLE;
+        waitCondition(&start_concurrent_mark_cond, &concurrent_coll_lock);
+        if (stop_concurrent_worker) {
+            concurrent_worker_state = CONCURRENT_WORKER_STOPPED;
+            concurrent_worker_thread = 0;
+            broadcastCondition(&concurrent_coll_finished_cond);
+            RELEASE_LOCK(&concurrent_coll_lock);
+            return NULL;
+        }
+
+        CHECK(concurrent_worker_state == CONCURRENT_WORKER_RUNNING);
+        MarkQueue *mark_queue = concurrent_mark_roots;
+        concurrent_mark_roots = NULL;
+        RELEASE_LOCK(&concurrent_coll_lock);
+
+        StgWeak *dead_weaks = NULL;
+        StgTSO *resurrected_threads = (StgTSO*)&stg_END_TSO_QUEUE_closure;
+        nonmovingMark_(mark_queue, &dead_weaks, &resurrected_threads, true);
+
+        ACQUIRE_LOCK(&concurrent_coll_lock);
+        broadcastCondition(&concurrent_coll_finished_cond);
+    }
+}
+
+static void nonmovingInitConcurrentWorker(void)
+{
+    debugTrace(DEBUG_nonmoving_gc, "Starting concurrent mark thread");
+    initMutex(&concurrent_coll_lock);
+    ACQUIRE_LOCK(&concurrent_coll_lock);
+    initCondition(&start_concurrent_mark_cond);
+    initCondition(&concurrent_coll_finished_cond);
+    stop_concurrent_worker = false;
+    concurrent_worker_state = CONCURRENT_WORKER_IDLE;
+    concurrent_mark_roots = NULL;
+
+    if (createOSThread(&concurrent_worker_thread, "nonmoving-mark",
+                       nonmovingConcurrentMarkWorker, NULL) != 0) {
+        barf("nonmovingInitConcurrentWorker: failed to spawn mark thread: %s", strerror(errno));
+    }
+    RELEASE_LOCK(&concurrent_coll_lock);
+}
+
+static void nonmovingExitConcurrentWorker(void)
+{
+    debugTrace(DEBUG_nonmoving_gc,
+               "waiting for nonmoving collector thread to terminate");
+    ACQUIRE_LOCK(&concurrent_coll_lock);
+    while (concurrent_worker_state != CONCURRENT_WORKER_STOPPED) {
+        stop_concurrent_worker = true;
+        signalCondition(&start_concurrent_mark_cond);
+        waitCondition(&concurrent_coll_finished_cond, &concurrent_coll_lock);
+    }
+    RELEASE_LOCK(&concurrent_coll_lock);
+
+    closeMutex(&concurrent_coll_lock);
+    closeCondition(&start_concurrent_mark_cond);
+    closeCondition(&concurrent_coll_finished_cond);
+}
+
+static void nonmovingStartConcurrentMark(MarkQueue *roots)
+{
+    ACQUIRE_LOCK(&concurrent_coll_lock);
+    CHECK(concurrent_worker_state != CONCURRENT_WORKER_RUNNING);
+    concurrent_worker_state = CONCURRENT_WORKER_RUNNING;
+    concurrent_mark_roots = roots;
+    RELAXED_STORE(&nonmoving_write_barrier_enabled, true);
+    signalCondition(&start_concurrent_mark_cond);
+    RELEASE_LOCK(&concurrent_coll_lock);
+}
+
+bool nonmovingConcurrentMarkIsRunning(void)
+{
+    ACQUIRE_LOCK(&concurrent_coll_lock);
+    bool running = concurrent_worker_state == CONCURRENT_WORKER_RUNNING;
+    RELEASE_LOCK(&concurrent_coll_lock);
+    return running;
+}
+
+// Prevent the initiation of concurrent marking. Used by the sanity checker to
+// avoid racing with the concurrent mark thread.
+// If `wait` then wait until on-going marking has finished.
+// Returns true if successfully blocked, false if mark is running.
+bool nonmovingBlockConcurrentMark(bool wait)
+{
+    if (!RtsFlags.GcFlags.useNonmoving) {
+        return true;
+    }
+    ACQUIRE_LOCK(&concurrent_coll_lock);
+    if (wait) {
+        while (concurrent_worker_state == CONCURRENT_WORKER_RUNNING) {
+            waitCondition(&concurrent_coll_finished_cond, &concurrent_coll_lock);
+        }
+    }
+    bool running = concurrent_worker_state == CONCURRENT_WORKER_RUNNING;
+    // N.B. We don't release concurrent_coll_lock to block marking.
+    if (running) {
+        RELEASE_LOCK(&concurrent_coll_lock);
+        return false;
+    } else {
+        return true;
+    }
+}
+
+void nonmovingUnblockConcurrentMark(void)
+{
+    if (!RtsFlags.GcFlags.useNonmoving) {
+        return;
+    }
+    RELEASE_LOCK(&concurrent_coll_lock);
 }
 
 // Append w2 to the end of w1.
@@ -893,7 +985,6 @@ static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO *
 #if !defined(THREADED_RTS)
     ASSERT(!concurrent);
 #endif
-    ACQUIRE_LOCK(&nonmoving_collection_mutex);
     debugTrace(DEBUG_nonmoving_gc, "Starting mark...");
     stat_startNonmovingGc();
 
@@ -933,10 +1024,7 @@ concurrent_marking:
     }
 
 #if defined(THREADED_RTS)
-    Task *task = NULL;
     if (concurrent) {
-        task = newBoundTask();
-
         // If at this point if we've decided to exit then just return
         if (getSchedState() > SCHED_RUNNING) {
             // Note that we break our invariants here and leave segments in
@@ -952,7 +1040,7 @@ concurrent_marking:
         }
 
         // We're still running, request a sync
-        nonmovingBeginFlush(task);
+        nonmovingBeginFlush(myTask());
 
         bool all_caps_syncd;
         MarkBudget sync_marking_budget = sync_phase_marking_budget;
@@ -963,7 +1051,7 @@ concurrent_marking:
                 // See Note [Sync phase marking budget].
                 traceConcSyncEnd();
                 stat_endNonmovingGcSync();
-                releaseAllCapabilities(n_capabilities, NULL, task);
+                releaseAllCapabilities(n_capabilities, NULL, myTask());
                 goto concurrent_marking;
             }
         } while (!all_caps_syncd);
@@ -1045,7 +1133,7 @@ concurrent_marking:
 #if !defined(NONCONCURRENT_SWEEP)
     if (concurrent) {
         nonmoving_write_barrier_enabled = false;
-        nonmovingFinishFlush(task);
+        nonmovingFinishFlush(myTask());
     }
 #endif
 #endif
@@ -1097,24 +1185,10 @@ concurrent_marking:
     }
 #endif
 
-    // TODO: Remainder of things done by GarbageCollect (update stats)
-
 #if defined(THREADED_RTS)
 finish:
-    if (concurrent) {
-        exitMyTask();
-
-        // We are done...
-        RELAXED_STORE(&mark_thread, 0);
-        stat_endNonmovingGc();
-    }
-
-    // Signal that the concurrent collection is finished, allowing the next
-    // non-moving collection to proceed
-    RELAXED_STORE(&concurrent_coll_running, false);
-    signalCondition(&concurrent_coll_finished);
-    RELEASE_LOCK(&nonmoving_collection_mutex);
 #endif
+    stat_endNonmovingGc();
 }
 
 #if defined(DEBUG)
@@ -1207,131 +1281,6 @@ void nonmovingPrintSegment(struct NonmovingSegment *seg)
     debugBelch("End of segment\n\n");
 }
 
-void locate_object(P_ obj)
-{
-    // Search allocators
-    for (int alloca_idx = 0; alloca_idx < NONMOVING_ALLOCA_CNT; ++alloca_idx) {
-        struct NonmovingAllocator *alloca = &nonmovingHeap.allocators[alloca_idx];
-        for (uint32_t cap_n = 0; cap_n < getNumCapabilities(); ++cap_n) {
-            Capability *cap = getCapability(cap_n);
-            struct NonmovingSegment *seg = cap->current_segments[alloca_idx];
-            if (obj >= (P_)seg && obj < (((P_)seg) + NONMOVING_SEGMENT_SIZE_W)) {
-                debugBelch("%p is in current segment of capability %d of allocator %d at %p\n", obj, cap_n, alloca_idx, (void*)seg);
-                return;
-            }
-        }
-        int seg_idx = 0;
-        struct NonmovingSegment *seg = alloca->active;
-        while (seg) {
-            if (obj >= (P_)seg && obj < (((P_)seg) + NONMOVING_SEGMENT_SIZE_W)) {
-                debugBelch("%p is in active segment %d of allocator %d at %p\n", obj, seg_idx, alloca_idx, (void*)seg);
-                return;
-            }
-            seg_idx++;
-            seg = seg->link;
-        }
-
-        seg_idx = 0;
-        seg = alloca->filled;
-        while (seg) {
-            if (obj >= (P_)seg && obj < (((P_)seg) + NONMOVING_SEGMENT_SIZE_W)) {
-                debugBelch("%p is in filled segment %d of allocator %d at %p\n", obj, seg_idx, alloca_idx, (void*)seg);
-                return;
-            }
-            seg_idx++;
-            seg = seg->link;
-        }
-    }
-
-    struct NonmovingSegment *seg = nonmovingHeap.free;
-    int seg_idx = 0;
-    while (seg) {
-        if (obj >= (P_)seg && obj < (((P_)seg) + NONMOVING_SEGMENT_SIZE_W)) {
-            debugBelch("%p is in free segment %d at %p\n", obj, seg_idx, (void*)seg);
-            return;
-        }
-        seg_idx++;
-        seg = seg->link;
-    }
-
-    // Search nurseries
-    for (uint32_t nursery_idx = 0; nursery_idx < n_nurseries; ++nursery_idx) {
-        for (bdescr* nursery_block = nurseries[nursery_idx].blocks; nursery_block; nursery_block = nursery_block->link) {
-            if (obj >= nursery_block->start && obj <= nursery_block->start + nursery_block->blocks*BLOCK_SIZE_W) {
-                debugBelch("%p is in nursery %d\n", obj, nursery_idx);
-                return;
-            }
-        }
-    }
-
-    // Search generations
-    for (uint32_t g = 0; g < RtsFlags.GcFlags.generations - 1; ++g) {
-        generation *gen = &generations[g];
-        for (bdescr *blk = gen->blocks; blk; blk = blk->link) {
-            if (obj >= blk->start && obj < blk->free) {
-                debugBelch("%p is in generation %" FMT_Word32 " blocks\n", obj, g);
-                return;
-            }
-        }
-        for (bdescr *blk = gen->old_blocks; blk; blk = blk->link) {
-            if (obj >= blk->start && obj < blk->free) {
-                debugBelch("%p is in generation %" FMT_Word32 " old blocks\n", obj, g);
-                return;
-            }
-        }
-    }
-
-    // Search large objects
-    for (uint32_t g = 0; g < RtsFlags.GcFlags.generations - 1; ++g) {
-        generation *gen = &generations[g];
-        for (bdescr *large_block = gen->large_objects; large_block; large_block = large_block->link) {
-            if ((P_)large_block->start == obj) {
-                debugBelch("%p is in large blocks of generation %d\n", obj, g);
-                return;
-            }
-        }
-    }
-
-    for (bdescr *large_block = nonmoving_large_objects; large_block; large_block = large_block->link) {
-        if ((P_)large_block->start == obj) {
-            debugBelch("%p is in nonmoving_large_objects\n", obj);
-            return;
-        }
-    }
-
-    for (bdescr *large_block = nonmoving_marked_large_objects; large_block; large_block = large_block->link) {
-        if ((P_)large_block->start == obj) {
-            debugBelch("%p is in nonmoving_marked_large_objects\n", obj);
-            return;
-        }
-    }
-
-    // Search workspaces FIXME only works in non-threaded runtime
-#if !defined(THREADED_RTS)
-    for (uint32_t g = 0; g < RtsFlags.GcFlags.generations - 1; ++ g) {
-        gen_workspace *ws = &gct->gens[g];
-        for (bdescr *blk = ws->todo_bd; blk; blk = blk->link) {
-            if (obj >= blk->start && obj < blk->free) {
-                debugBelch("%p is in generation %" FMT_Word32 " todo bds\n", obj, g);
-                return;
-            }
-        }
-        for (bdescr *blk = ws->scavd_list; blk; blk = blk->link) {
-            if (obj >= blk->start && obj < blk->free) {
-                debugBelch("%p is in generation %" FMT_Word32 " scavd bds\n", obj, g);
-                return;
-            }
-        }
-        for (bdescr *blk = ws->todo_large_objects; blk; blk = blk->link) {
-            if (obj >= blk->start && obj < blk->free) {
-                debugBelch("%p is in generation %" FMT_Word32 " todo large bds\n", obj, g);
-                return;
-            }
-        }
-    }
-#endif
-}
-
 void nonmovingPrintSweepList(void)
 {
     debugBelch("==== SWEEP LIST =====\n");
@@ -1342,37 +1291,4 @@ void nonmovingPrintSweepList(void)
     debugBelch("= END OF SWEEP LIST =\n");
 }
 
-void check_in_mut_list(StgClosure *p)
-{
-    for (uint32_t cap_n = 0; cap_n < getNumCapabilities(); ++cap_n) {
-        for (bdescr *bd = getCapability(cap_n)->mut_lists[oldest_gen->no]; bd; bd = bd->link) {
-            for (StgPtr q = bd->start; q < bd->free; ++q) {
-                if (*((StgPtr**)q) == (StgPtr*)p) {
-                    debugBelch("Object is in mut list of cap %d: %p\n", cap_n, getCapability(cap_n)->mut_lists[oldest_gen->no]);
-                    return;
-                }
-            }
-        }
-    }
-
-    debugBelch("Object is not in a mut list\n");
-}
-
-void print_block_list(bdescr* bd)
-{
-    while (bd) {
-        debugBelch("%p, ", (void*)bd);
-        bd = bd->link;
-    }
-    debugBelch("\n");
-}
-
-void print_thread_list(StgTSO* tso)
-{
-    while (tso != END_TSO_QUEUE) {
-        printClosure((StgClosure*)tso);
-        tso = tso->global_link;
-    }
-}
-
 #endif


=====================================
rts/sm/NonMoving.h
=====================================
@@ -124,15 +124,12 @@ extern struct NonmovingHeap nonmovingHeap;
 
 extern memcount nonmoving_segment_live_words;
 
-#if defined(THREADED_RTS)
-extern bool concurrent_coll_running;
-extern Mutex nonmoving_collection_mutex;
-#endif
-
 void nonmovingInit(void);
-void nonmovingStop(void);
 void nonmovingExit(void);
+bool nonmovingConcurrentMarkIsRunning(void);
 
+bool nonmovingBlockConcurrentMark(bool wait);
+void nonmovingUnblockConcurrentMark(void);
 
 // dead_weaks and resurrected_threads lists are used for two things:
 //


=====================================
rts/sm/Sanity.c
=====================================
@@ -1255,8 +1255,7 @@ memInventory (bool show)
 #if defined(THREADED_RTS)
   // We need to be careful not to race with the nonmoving collector.
   // If a nonmoving collection is on-going we simply abort the inventory.
-  if (RtsFlags.GcFlags.useNonmoving){
-    if(TRY_ACQUIRE_LOCK(&nonmoving_collection_mutex))
+  if (RtsFlags.GcFlags.useNonmoving && !nonmovingBlockConcurrentMark(false)) {
       return;
   }
 #endif
@@ -1363,12 +1362,7 @@ memInventory (bool show)
   ASSERT(n_alloc_blocks == live_blocks);
   ASSERT(!leak);
 
-#if defined(THREADED_RTS)
-  if (RtsFlags.GcFlags.useNonmoving){
-    RELEASE_LOCK(&nonmoving_collection_mutex);
-  }
-#endif
-
+  nonmovingUnblockConcurrentMark();
 }
 
 #endif /* DEBUG */


=====================================
testsuite/tests/rts/all.T
=====================================
@@ -589,7 +589,16 @@ test('T22795c', [only_ways(['normal']), js_skip], compile_and_run, ['-threaded -
 
 test('T17574', [js_skip], compile_and_run, ['-with-rtsopts -T'])
 
-test('T23221', [js_skip, high_memory_usage, extra_run_opts('1500000'), unless(wordsize(64), skip), omit_ghci], compile_and_run, ['-O -with-rtsopts -T'])
+test('T23221',
+     [js_skip,
+      # This test is highly dependent upon GC behavior
+      omit_ways(['nonmoving', 'nonmoving_thr', 'nonmoving_thr_sanity', 'nonmoving_thr_ghc']),
+      high_memory_usage,
+      extra_run_opts('1500000'),
+      unless(wordsize(64), skip),
+      omit_ghci],
+     compile_and_run,
+     ['-O -with-rtsopts -T'])
 
 test('T23142', [unless(debug_rts(), skip), req_interp], makefile_test, ['T23142'])
 


=====================================
testsuite/tests/rts/cloneStackLib.c
=====================================
@@ -27,14 +27,14 @@ void expectStacksToBeEqual(StgStack *clonedStack, StgTSO *tso) {
 
     for(StgWord i = liveStack->stack_size - 1; (liveStack->stack + i) >= liveStack->sp; i--){
         if(liveStack->stack[i] != clonedStack->stack[i]){
-            barf("Expected stack word %lu to be equal on both stacks.", i);
+            barf("Expected stack word %" FMT_Word " to be equal on both stacks.", i);
         }
     }
 }
 
 void expectStackToBeNotDirty(StgStack *stack) {
     if(stack->dirty != 0) {
-        barf("Expected stack to be not dirty. But dirty flag was set to %u", stack->dirty);
+        barf("Expected stack to be not dirty. But dirty flag was set to %" FMT_Word, (StgWord) stack->dirty);
     }
 }
 
@@ -50,7 +50,8 @@ void expectClosureTypes(StgStack *stack, unsigned int types[], size_t typesSize)
         }
 
         if(info->type != types[i]) {
-            barf("Wrong closure type on stack! Expected %u but got %u in position %lu", types[i], info->type, i);
+            barf("Wrong closure type on stack! Expected %" FMT_Word " but got %" FMT_Word " in position %" FMT_Word,
+                 (StgWord) types[i], (StgWord) info->type, i);
         }
     }
 }



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/88bbf8c5af345deb88fb51f0a50169759ff28296...381cfaed98742508ef9919ec76f5b7b610514f86

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/88bbf8c5af345deb88fb51f0a50169759ff28296...381cfaed98742508ef9919ec76f5b7b610514f86
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/20230817/a168f442/attachment-0001.html>


More information about the ghc-commits mailing list