diff options
-rw-r--r-- | gc.c | 25 | ||||
-rw-r--r-- | gc.h | 2 | ||||
-rw-r--r-- | signal.c | 2 |
3 files changed, 28 insertions, 1 deletions
@@ -82,6 +82,7 @@ static alloc_bytes_t prev_malloc_bytes; alloc_bytes_t opt_gc_delta = DFL_MALLOC_DELTA_THRESH; int gc_enabled = 1; +static int inprogress; static struct fin_reg { struct fin_reg *next; @@ -690,6 +691,9 @@ void gc(void) assert (gc_enabled); + if (inprogress++) + assert(0 && "gc re-entered"); + #if CONFIG_GEN_GC if (malloc_bytes - prev_malloc_bytes >= opt_gc_delta) full_gc = 1; @@ -730,6 +734,8 @@ void gc(void) call_finals(); gc_enabled = 1; prev_malloc_bytes = malloc_bytes; + + inprogress--; } int gc_state(int enabled) @@ -739,6 +745,11 @@ int gc_state(int enabled) return old; } +int gc_inprogress(void) +{ + return inprogress; +} + void gc_init(val *stack_bottom) { gc_stack_bottom = stack_bottom; @@ -910,11 +921,23 @@ void unmark(void) block < end; block++) { - block->t.type = convert(type_t, block->t.type & ~(FREE | REACHABLE)); + block->t.type = convert(type_t, block->t.type & ~REACHABLE); } } } +void gc_cancel(void) +{ + unmark(); +#if CONFIG_GEN_GC + checkobj_idx = 0; + mutobj_idx = 0; + freshobj_idx = 0; + full_gc = 1; +#endif + inprogress = 0; +} + void dheap(heap_t *heap, int start, int end); void dheap(heap_t *heap, int start, int end) @@ -32,6 +32,7 @@ void protect(val *, ...); val make_obj(void); void gc(void); int gc_state(int); +int gc_inprogress(void); void gc_mark(val); void gc_conservative_mark(val); void gc_mark_mem(val *low, val *high); @@ -47,6 +48,7 @@ extern int full_gc; #endif void unmark(void); +void gc_cancel(void); void gc_hint_func(val *); void gc_report_copies(val *pvar); void gc_free_all(void); @@ -94,6 +94,8 @@ static void sig_handler(int sig) if (!in_interrupt && async_sig_enabled) { uw_simple_catch_begin; async_sig_enabled = 0; + if (gc_inprogress()) + gc_cancel(); if (funcall2(lambda, num_fast(sig), t)) sig_deferred |= (1UL << sig); uw_unwind { |