wingo pushed a commit to branch wip-whippet
in repository guile.

commit 675d8d649a0538dbe73d30fe70607b74e4ae560f
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Thu May 15 11:26:27 2025 +0200

    Rework gc_call_without_gc to allow reentrancy
    
    Rename to gc_deactivate_for_call / gc_reactivate_for_call
---
 api/gc-api.h            |  8 ++++++--
 benchmarks/ephemerons.c |  4 ++--
 benchmarks/finalizers.c |  4 ++--
 benchmarks/mt-gcbench.c |  4 ++--
 src/bdw.c               | 27 +++++++++++++++++++++++----
 src/mmc.c               | 25 +++++++++++++++++++++++--
 src/pcc.c               | 28 ++++++++++++++++++++++++----
 src/semi.c              | 14 +++++++++++---
 8 files changed, 93 insertions(+), 21 deletions(-)

diff --git a/api/gc-api.h b/api/gc-api.h
index 502a6abe2..01ad113a8 100644
--- a/api/gc-api.h
+++ b/api/gc-api.h
@@ -53,8 +53,12 @@ GC_API_ void gc_heap_set_extern_space(struct gc_heap *heap,
 GC_API_ struct gc_mutator* gc_init_for_thread(struct gc_stack_addr base,
                                               struct gc_heap *heap);
 GC_API_ void gc_finish_for_thread(struct gc_mutator *mut);
-GC_API_ void* gc_call_without_gc(struct gc_mutator *mut, void* (*f)(void*),
-                                 void *data) GC_NEVER_INLINE;
+GC_API_ void* gc_deactivate_for_call(struct gc_mutator *mut,
+                                     void* (*f)(struct gc_mutator*, void*),
+                                     void *data) GC_NEVER_INLINE;
+GC_API_ void* gc_reactivate_for_call(struct gc_mutator *mut,
+                                     void* (*f)(struct gc_mutator*, void*),
+                                     void *data) GC_NEVER_INLINE;
 
 GC_API_ void gc_collect(struct gc_mutator *mut,
                         enum gc_collection_kind requested_kind);
diff --git a/benchmarks/ephemerons.c b/benchmarks/ephemerons.c
index c74db9d43..f0459dab4 100644
--- a/benchmarks/ephemerons.c
+++ b/benchmarks/ephemerons.c
@@ -183,7 +183,7 @@ static void* run_one_test_in_thread(void *arg) {
 }
 
 struct join_data { int status; pthread_t thread; };
-static void *join_thread(void *data) {
+static void *join_thread(struct gc_mutator *unused, void *data) {
   struct join_data *join_data = data;
   void *ret;
   join_data->status = pthread_join(join_data->thread, &ret);
@@ -256,7 +256,7 @@ int main(int argc, char *argv[]) {
   run_one_test(&main_thread);
   for (size_t i = 1; i < nthreads; i++) {
     struct join_data data = { 0, threads[i] };
-    gc_call_without_gc(mut, join_thread, &data);
+    gc_deactivate_for_call(mut, join_thread, &data);
     if (data.status) {
       errno = data.status;
       perror("Failed to join thread");
diff --git a/benchmarks/finalizers.c b/benchmarks/finalizers.c
index 79a2660c3..8d4b5c25a 100644
--- a/benchmarks/finalizers.c
+++ b/benchmarks/finalizers.c
@@ -190,7 +190,7 @@ static void* run_one_test_in_thread(void *arg) {
 }
 
 struct join_data { int status; pthread_t thread; };
-static void *join_thread(void *data) {
+static void *join_thread(struct gc_mutator *unused, void *data) {
   struct join_data *join_data = data;
   void *ret;
   join_data->status = pthread_join(join_data->thread, &ret);
@@ -263,7 +263,7 @@ int main(int argc, char *argv[]) {
   ssize_t outstanding = (size_t)run_one_test(&main_thread);
   for (size_t i = 1; i < nthreads; i++) {
     struct join_data data = { 0, threads[i] };
-    void *ret = gc_call_without_gc(mut, join_thread, &data);
+    void *ret = gc_deactivate_for_call(mut, join_thread, &data);
     if (data.status) {
       errno = data.status;
       perror("Failed to join thread");
diff --git a/benchmarks/mt-gcbench.c b/benchmarks/mt-gcbench.c
index 62fdc7154..e705702bb 100644
--- a/benchmarks/mt-gcbench.c
+++ b/benchmarks/mt-gcbench.c
@@ -319,7 +319,7 @@ static void* run_one_test_in_thread(void *arg) {
 }
 
 struct join_data { int status; pthread_t thread; };
-static void *join_thread(void *data) {
+static void *join_thread(struct gc_mutator *unused, void *data) {
   struct join_data *join_data = data;
   void *ret;
   join_data->status = pthread_join(join_data->thread, &ret);
@@ -389,7 +389,7 @@ int main(int argc, char *argv[]) {
   run_one_test(&main_thread);
   for (size_t i = 1; i < nthreads; i++) {
     struct join_data data = { 0, threads[i] };
-    gc_call_without_gc(mut, join_thread, &data);
+    gc_deactivate_for_call(mut, join_thread, &data);
     if (data.status) {
       errno = data.status;
       perror("Failed to join thread");
diff --git a/src/bdw.c b/src/bdw.c
index e9268ef81..c6e2b4341 100644
--- a/src/bdw.c
+++ b/src/bdw.c
@@ -657,10 +657,29 @@ void gc_finish_for_thread(struct gc_mutator *mut) {
   GC_unregister_my_thread();
 }
 
-void* gc_call_without_gc(struct gc_mutator *mut,
-                         void* (*f)(void*),
-                         void *data) {
-  return GC_do_blocking(f, data);
+struct call_with_mutator_data {
+  void* (*proc) (struct gc_mutator*, void*);
+  struct gc_mutator *mutator;
+  void *data;
+};
+
+static void* call_with_mutator (void *p) {
+  struct call_with_mutator_data *data = p;
+  return data->proc(data->mutator, data->data);
+}
+
+void* gc_deactivate_for_call(struct gc_mutator *mut,
+                             void* (*f)(struct gc_mutator *, void*),
+                             void *data) {
+  struct call_with_mutator_data d = { f, mut, data };
+  return GC_do_blocking(call_with_mutator, &d);
+}
+
+void* gc_reactivate_for_call(struct gc_mutator *mut,
+                             void* (*f)(struct gc_mutator *, void*),
+                             void *data) {
+  struct call_with_mutator_data d = { f, mut, data };
+  return GC_call_with_gc_active(call_with_mutator, &d);
 }
 
 void gc_mutator_set_roots(struct gc_mutator *mut,
diff --git a/src/mmc.c b/src/mmc.c
index f67621b93..a1329e239 100644
--- a/src/mmc.c
+++ b/src/mmc.c
@@ -88,6 +88,7 @@ struct gc_mutator {
   void *event_listener_data;
   struct gc_mutator *next;
   struct gc_mutator *prev;
+  int active;
 };
 
 struct gc_trace_worker_data {
@@ -216,6 +217,7 @@ add_mutator(struct gc_heap *heap, struct gc_mutator *mut) {
   while (mutators_are_stopping(heap))
     pthread_cond_wait(&heap->mutator_cond, &heap->lock);
   mut->next = mut->prev = NULL;
+  mut->active = 1;
   struct gc_mutator *tail = heap->mutators;
   if (tail) {
     mut->next = tail;
@@ -235,6 +237,7 @@ remove_mutator(struct gc_heap *heap, struct gc_mutator 
*mut) {
   mut->heap = NULL;
   heap_lock(heap);
   heap->mutator_count--;
+  mut->active = 0;
   if (mut->next)
     mut->next->prev = mut->prev;
   if (mut->prev)
@@ -1277,6 +1280,7 @@ deactivate_mutator(struct gc_heap *heap, struct 
gc_mutator *mut) {
     gc_field_set_writer_release_buffer(&mut->logger);
   heap_lock(heap);
   heap->inactive_mutator_count++;
+  mut->active = 0;
   gc_stack_capture_hot(&mut->stack);
   if (all_mutators_stopped(heap))
     pthread_cond_signal(&heap->collector_cond);
@@ -1288,15 +1292,32 @@ reactivate_mutator(struct gc_heap *heap, struct 
gc_mutator *mut) {
   heap_lock(heap);
   while (mutators_are_stopping(heap))
     pthread_cond_wait(&heap->mutator_cond, &heap->lock);
+  mut->active = 1;
   heap->inactive_mutator_count--;
   heap_unlock(heap);
 }
 
 void*
-gc_call_without_gc(struct gc_mutator *mut, void* (*f)(void*), void *data) {
+gc_deactivate_for_call(struct gc_mutator *mut,
+                       void* (*f)(struct gc_mutator*, void*),
+                       void *data) {
   struct gc_heap *heap = mutator_heap(mut);
   deactivate_mutator(heap, mut);
-  void *ret = f(data);
+  void *ret = f(mut, data);
   reactivate_mutator(heap, mut);
   return ret;
 }
+
+void*
+gc_reactivate_for_call(struct gc_mutator *mut,
+                       void* (*f)(struct gc_mutator*, void*),
+                       void *data) {
+  struct gc_heap *heap = mutator_heap(mut);
+  int reactivate = !mut->active;
+  if (reactivate)
+    reactivate_mutator(heap, mut);
+  void *ret = f(mut, data);
+  if (reactivate)
+    deactivate_mutator(heap, mut);
+  return ret;
+}
diff --git a/src/pcc.c b/src/pcc.c
index bda42730b..609160a15 100644
--- a/src/pcc.c
+++ b/src/pcc.c
@@ -96,6 +96,7 @@ struct gc_mutator {
   void *event_listener_data;
   struct gc_mutator *next;
   struct gc_mutator *prev;
+  int active;
 };
 
 struct gc_trace_worker_data {
@@ -501,6 +502,7 @@ static void add_mutator(struct gc_heap *heap, struct 
gc_mutator *mut) {
   while (mutators_are_stopping(heap))
     pthread_cond_wait(&heap->mutator_cond, &heap->lock);
   mut->next = mut->prev = NULL;
+  mut->active = 1;
   struct gc_mutator *tail = heap->mutators;
   if (tail) {
     mut->next = tail;
@@ -520,6 +522,7 @@ static void remove_mutator(struct gc_heap *heap, struct 
gc_mutator *mut) {
   mut->heap = NULL;
   heap_lock(heap);
   heap->mutator_count--;
+  mut->active = 0;
   if (mut->next)
     mut->next->prev = mut->prev;
   if (mut->prev)
@@ -1357,31 +1360,48 @@ void gc_finish_for_thread(struct gc_mutator *mut) {
 
 static void deactivate_mutator(struct gc_heap *heap, struct gc_mutator *mut) {
   GC_ASSERT(mut->next == NULL);
+  GC_ASSERT(mut->active);
   copy_space_allocator_finish(&mut->allocator, heap_allocation_space(heap));
   if (GC_GENERATIONAL)
     gc_field_set_writer_release_buffer(mutator_field_logger(mut));
   heap_lock(heap);
   heap->inactive_mutator_count++;
+  mut->active = 0;
   if (all_mutators_stopped(heap))
     pthread_cond_signal(&heap->collector_cond);
   heap_unlock(heap);
 }
 
 static void reactivate_mutator(struct gc_heap *heap, struct gc_mutator *mut) {
+  GC_ASSERT(!mut->active);
   heap_lock(heap);
   while (mutators_are_stopping(heap))
     pthread_cond_wait(&heap->mutator_cond, &heap->lock);
+  mut->active = 1;
   heap->inactive_mutator_count--;
   maybe_increase_max_active_mutator_count(heap);
   heap_unlock(heap);
 }
 
-void* gc_call_without_gc(struct gc_mutator *mut,
-                         void* (*f)(void*),
-                         void *data) {
+void* gc_deactivate_for_call(struct gc_mutator *mut,
+                             void* (*f)(struct gc_mutator*, void*),
+                             void *data) {
   struct gc_heap *heap = mutator_heap(mut);
   deactivate_mutator(heap, mut);
-  void *ret = f(data);
+  void *ret = f(mut, data);
   reactivate_mutator(heap, mut);
   return ret;
 }
+
+void* gc_reactivate_for_call(struct gc_mutator *mut,
+                             void* (*f)(struct gc_mutator*, void*),
+                             void *data) {
+  struct gc_heap *heap = mutator_heap(mut);
+  int reactivate = !mut->active;
+  if (reactivate)
+    reactivate_mutator(heap, mut);
+  void *ret = f(mut, data);
+  if (reactivate)
+    deactivate_mutator(heap, mut);
+  return ret;
+}
diff --git a/src/semi.c b/src/semi.c
index 41c78a178..913c983c1 100644
--- a/src/semi.c
+++ b/src/semi.c
@@ -763,8 +763,16 @@ struct gc_mutator* gc_init_for_thread(struct gc_stack_addr 
base,
 void gc_finish_for_thread(struct gc_mutator *space) {
 }
 
-void* gc_call_without_gc(struct gc_mutator *mut, void* (*f)(void*),
-                         void *data) {
+void* gc_deactivate_for_call(struct gc_mutator *mut,
+                             void* (*f)(struct gc_mutator *, void*),
+                             void *data) {
   // Can't be threads, then there won't be collection.
-  return f(data);
+  return f(mut, data);
+}
+
+void* gc_reactivate_for_call(struct gc_mutator *mut,
+                             void* (*f)(struct gc_mutator *mut, void*),
+                             void *data) {
+  // Can't be threads, then there won't be collection.
+  return f(mut, data);
 }

Reply via email to