diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-04-25 17:25:48 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-04-25 17:25:48 +0900 |
| commit | aa8e490fd54bc7c62e591edc349c0dcb5cc572a9 (patch) | |
| tree | 250e4922c47bc2b110af3a2cbb7e10943a8beb32 | |
| parent | 88cd807379152ea3fec5f534e5f4d6ebebd53982 (diff) | |
| download | mruby-aa8e490fd54bc7c62e591edc349c0dcb5cc572a9.tar.gz mruby-aa8e490fd54bc7c62e591edc349c0dcb5cc572a9.zip | |
Prevent GC during `each_object`; fix #3616
| -rw-r--r-- | include/mruby/gc.h | 1 | ||||
| -rw-r--r-- | src/gc.c | 32 |
2 files changed, 30 insertions, 3 deletions
diff --git a/include/mruby/gc.h b/include/mruby/gc.h index dd161efa1..ce214aa56 100644 --- a/include/mruby/gc.h +++ b/include/mruby/gc.h @@ -64,6 +64,7 @@ typedef struct mrb_gc { size_t threshold; int interval_ratio; int step_ratio; + mrb_bool iterating :1; mrb_bool disabled :1; mrb_bool full :1; mrb_bool generational :1; @@ -17,6 +17,7 @@ #include <mruby/variable.h> #include <mruby/gc.h> #include <mruby/error.h> +#include <mruby/throw.h> /* = Tri-color Incremental Garbage Collection @@ -1162,7 +1163,7 @@ mrb_incremental_gc(mrb_state *mrb) { mrb_gc *gc = &mrb->gc; - if (gc->disabled) return; + if (gc->disabled || gc->iterating) return; GC_INVOKE_TIME_REPORT("mrb_incremental_gc()"); GC_TIME_START; @@ -1202,7 +1203,7 @@ mrb_full_gc(mrb_state *mrb) { mrb_gc *gc = &mrb->gc; - if (gc->disabled) return; + if (gc->disabled || gc->iterating) return; GC_INVOKE_TIME_REPORT("mrb_full_gc()"); GC_TIME_START; @@ -1508,7 +1509,32 @@ gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data) { - gc_each_objects(mrb, &mrb->gc, callback, data); + mrb_bool iterating = mrb->gc.iterating; + + mrb_full_gc(mrb); + mrb->gc.iterating = TRUE; + if (iterating) { + gc_each_objects(mrb, &mrb->gc, callback, data); + } + else { + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + gc_each_objects(mrb, &mrb->gc, callback, data); + mrb->jmp = prev_jmp; + mrb->gc.iterating = iterating; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + mrb->gc.iterating = iterating; + if (mrb->exc) { + mrb_value exc = mrb_obj_value(mrb->exc); + mrb->exc = NULL; + mrb_exc_raise(mrb, exc); + } + } MRB_END_EXC(&c_jmp); + } } #ifdef GC_TEST |
