From 4f0c5f1273cb756b886f3a63930e8aa8698aa5c2 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 12 Dec 2016 06:58:49 -0800 Subject: Cancel in-progress gc if handling async signal. If a signal goes off in the middle of gc that is routed to an async lambda handler, we should cancel gc, so the handler finds the heap in a good state. Of course, the handler must not return in this case, or else the interrupted gc will try to resume. * gc.c (inprogress): New static flag. (gc): Increment and decrement inprogress variable. Abort if re-entered. (gc_inprogress): New function. (unmark): Do not clear FREE flags, only REACHABLE. (gc_cancel): New function. * gc.h (gc_inprogress, gc_cancel): Declared. * signal.c (sig_handler): In the async lambda case, check for an in-progress gc and cancel it. --- gc.c | 25 ++++++++++++++++++++++++- gc.h | 2 ++ signal.c | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 2bffb65f..048163fb 100644 --- a/gc.c +++ b/gc.c @@ -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) diff --git a/gc.h b/gc.h index 2d6c5cde..ba065903 100644 --- a/gc.h +++ b/gc.h @@ -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); diff --git a/signal.c b/signal.c index ef64c64e..2bab8ad8 100644 --- a/signal.c +++ b/signal.c @@ -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 { -- cgit v1.2.3