diff options
author | Jonathan Chambers <joncham@gmail.com> | 2021-09-14 01:28:53 +0300 |
---|---|---|
committer | Jonathan Chambers <joncham@gmail.com> | 2021-09-28 01:59:13 +0300 |
commit | 1a65adc46c3a71065de2cf056d1e2edfbbd84c86 (patch) | |
tree | 1959cf176e325a0f2a74633ec01b3c421a74e631 | |
parent | a27eddb837d613cb4cf436405c23ce39ed16a86d (diff) |
Add callback to support ephemeron marking in Mono.
-rw-r--r-- | include/gc_mark.h | 7 | ||||
-rw-r--r-- | mark.c | 20 | ||||
-rw-r--r-- | os_dep.c | 12 |
3 files changed, 37 insertions, 2 deletions
diff --git a/include/gc_mark.h b/include/gc_mark.h index 108794de..2e468850 100644 --- a/include/gc_mark.h +++ b/include/gc_mark.h @@ -310,6 +310,13 @@ GC_API int GC_CALL GC_is_tmp_root(void *); GC_API void GC_CALL GC_print_trace(GC_word /* gc_no */); GC_API void GC_CALL GC_print_trace_inner(GC_word /* gc_no */); +/* Set the client for when mark stack is empty. A client can use */ +/* this callback to process (un)marked objects and push additional */ +/* work onto the stack. Useful for implementing ephemerons. */ +typedef void (GC_CALLBACK* GC_mark_stack_empty_proc)(void); +GC_API void GC_CALL GC_set_mark_stack_empty (GC_mark_stack_empty_proc); +GC_API GC_mark_stack_empty_proc GC_CALL GC_get_mark_stack_empty (void); + #ifdef __cplusplus } /* extern "C" */ #endif @@ -116,6 +116,7 @@ GC_INNER size_t GC_mark_stack_size = 0; GC_INNER mark_state_t GC_mark_state = MS_NONE; GC_INNER GC_bool GC_mark_stack_too_small = FALSE; +GC_INNER GC_bool GC_mark_stack_empty_called = FALSE; static struct hblk * scan_ptr; @@ -400,11 +401,26 @@ static void alloc_mark_stack(size_t); MARK_FROM_MARK_STACK(); break; } else { - GC_mark_state = MS_NONE; if (GC_mark_stack_too_small) { + GC_mark_state = MS_NONE; alloc_mark_stack(2*GC_mark_stack_size); + return(TRUE); + } else { + GC_mark_stack_empty_proc mark_stack_empty_proc = GC_get_mark_stack_empty(); + if (GC_mark_stack_empty_called || !mark_stack_empty_proc) { + GC_mark_state = MS_NONE; + GC_mark_stack_empty_called = FALSE; + return(TRUE); + } else { + if (mark_stack_empty_proc != 0) + mark_stack_empty_proc(); + + /* break below here loops us around the mark phase once again */ + /* to process any items push by the callback */ + GC_mark_stack_empty_called = TRUE; + } } - return(TRUE); + break; } case MS_INVALID: @@ -2798,6 +2798,18 @@ void GC_reset_default_push_other_roots(void) #endif } +GC_push_other_roots_proc GC_on_mark_stack_empty; + +GC_API void GC_CALL GC_set_mark_stack_empty (GC_mark_stack_empty_proc fn) +{ + GC_on_mark_stack_empty = fn; +} + +GC_API GC_mark_stack_empty_proc GC_CALL GC_get_mark_stack_empty (void) +{ + return GC_on_mark_stack_empty; +} + /* * Routines for accessing dirty bits on virtual pages. * There are six ways to maintain this information: |