summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2023-04-25 09:35:16 +0300
committerIvan Maidanski <ivmai@mail.ru>2023-04-25 09:36:04 +0300
commit4bdf9b9c327673b71344a63e368d8b2386bae6af (patch)
tree32451d0a3b368b8c78db67fa34c794ac91bcff04
parent2e5646ba3d954da3f45985630281aadfc686f55b (diff)
downloadbdwgc-4bdf9b9c327673b71344a63e368d8b2386bae6af.tar.gz
Do incremental mark some in GC_collect_a_little even if GC is disabled
Previous behavior was not documented but this API function did nothing in this case. That might cause a deadlock in the client code if the incremental collection was ongoing and the client called GC_collect_a_little() repeatedly (while the result is true). The new behavior, for the cause of disabled garbage collection, is to perform some amount of marking if the incremental collection is ongoing (but not stopping the world and, thus, not causing the memory reclaim to start), returning true if there is something more to mark. * alloc.c (GC_try_to_collect_inner): Change a loop to do-while one. * alloc.c (GC_collect_a_little): Do not check GC_dont_gc (i.e. call GC_collect_a_little_inner() unconditionally); add comment. * include/gc/gc.h (GC_collect_a_little): Update comment (describe the case when GC is disabled). * tests/gctest.c (check_heap_stats): Do not call GC_is_disabled(); add comment.
-rw-r--r--alloc.c14
-rw-r--r--include/gc/gc.h4
-rw-r--r--tests/gctest.c3
3 files changed, 11 insertions, 10 deletions
diff --git a/alloc.c b/alloc.c
index 15749ca9..b9e1b933 100644
--- a/alloc.c
+++ b/alloc.c
@@ -553,7 +553,7 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
GC_COND_LOG_PRINTF(
"GC_try_to_collect_inner: finishing collection in progress\n");
/* Just finish collection already in progress. */
- while(GC_collection_in_progress()) {
+ do {
if ((*stop_func)()) {
/* TODO: Notify GC_EVENT_ABANDON */
return FALSE;
@@ -561,7 +561,7 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
ENTER_GC();
GC_collect_a_little_inner(1);
EXIT_GC();
- }
+ } while (GC_collection_in_progress());
}
GC_notify_full_gc();
# ifndef NO_CLOCK
@@ -747,11 +747,11 @@ GC_API int GC_CALL GC_collect_a_little(void)
if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
LOCK();
- if (!GC_dont_gc) {
- ENTER_GC();
- GC_collect_a_little_inner(1);
- EXIT_GC();
- }
+ ENTER_GC();
+ /* Note: if the collection is in progress, this may do marking (not */
+ /* stopping the world) even in case of disabled GC. */
+ GC_collect_a_little_inner(1);
+ EXIT_GC();
result = (int)GC_collection_in_progress();
UNLOCK();
if (!result && GC_debugging_started) GC_print_all_smashed();
diff --git a/include/gc/gc.h b/include/gc/gc.h
index 3f0d0cc0..06048c6e 100644
--- a/include/gc/gc.h
+++ b/include/gc/gc.h
@@ -957,7 +957,9 @@ GC_API void GC_CALL GC_start_incremental_collection(void);
/* to marking from one page. May do more work if further */
/* progress requires it, e.g. if incremental collection is */
/* disabled. It is reasonable to call this in a wait loop */
-/* until it returns 0. */
+/* until it returns 0. If GC is disabled but the incremental */
+/* collection is already ongoing, then perform marking anyway */
+/* but not stopping the world (and without the reclaim phase). */
GC_API int GC_CALL GC_collect_a_little(void);
/* Allocate an object of size lb bytes. The client guarantees that as */
diff --git a/tests/gctest.c b/tests/gctest.c
index d50a9f61..9c5fe9d2 100644
--- a/tests/gctest.c
+++ b/tests/gctest.c
@@ -1972,8 +1972,7 @@ void check_heap_stats(void)
# endif
/* Garbage collect repeatedly so that all inaccessible objects */
/* can be finalized. */
- if (!GC_is_disabled())
- while (GC_collect_a_little()) { }
+ while (GC_collect_a_little()) { } /* should work even if disabled GC */
for (i = 0; i < 16; i++) {
GC_gcollect();
# ifndef GC_NO_FINALIZATION