From 73dc32c670f4fcaed0f33477b6fe5d602edcece1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 22 Sep 2015 00:15:29 +0900 Subject: add new functions mrb_gc_register/unregister; close #1411 some routines need to refer mruby objects (e.g. callbacks), in that case you have to protect your objects from garbage collection. the new functions mrb_gc_register() keeps those objects from GC. you have to remove your objects using mrb_gc_unregister() when your C routines use mruby objects any longer, otherwise objects will leak. --- src/gc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 15e1bd423..885368f37 100644 --- a/src/gc.c +++ b/src/gc.c @@ -385,6 +385,7 @@ gc_protect(mrb_state *mrb, struct RBasic *p) mrb->arena[mrb->arena_idx++] = p; } +/* mrb_gc_protect() leaves the object in the arena */ MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj) { @@ -392,6 +393,53 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj) gc_protect(mrb, mrb_basic_ptr(obj)); } +#define GC_ROOT_NAME "_gc_root_" + +/* mrb_gc_register() keeps the object from GC. + + Register your object when it's exported to C world, + without reference from Ruby world, e.g. callback + arguments. Don't forget to remove the obejct using + mrb_gc_unregister, otherwise your object will leak. +*/ + +MRB_API void +mrb_gc_register(mrb_state *mrb, mrb_value obj) +{ + mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); + mrb_value table = mrb_gv_get(mrb, root); + + if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { + table = mrb_ary_new(mrb); + mrb_gv_set(mrb, root, table); + } + mrb_ary_push(mrb, table, obj); +} + +/* mrb_gc_unregister() removes the object from GC root. */ +MRB_API void +mrb_gc_unregister(mrb_state *mrb, mrb_value obj) +{ + mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); + mrb_value table = mrb_gv_get(mrb, root); + struct RArray *a; + mrb_int i, j; + + if (mrb_nil_p(table)) return; + if (mrb_type(table) != MRB_TT_ARRAY) { + mrb_gv_set(mrb, root, mrb_nil_value()); + return; + } + a = mrb_ary_ptr(table); + mrb_ary_modify(mrb, a); + for (i=j=0; ilen; i++) { + if (!mrb_obj_eq(mrb, a->ptr[i], obj)) { + a->ptr[j++] = a->ptr[i]; + } + } + a->len = j; +} + MRB_API struct RBasic* mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) { -- cgit v1.2.3