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.
parent 386a2b8a
...@@ -408,7 +408,13 @@ MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg); ...@@ -408,7 +408,13 @@ MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg);
MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv); MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv);
MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c); MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c);
/* mrb_gc_protect() leaves the object in the arena */
MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj); MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj);
/* mrb_gc_register() keeps the object from GC. */
MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj);
/* mrb_gc_unregister() removes the object from GC root. */
MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj);
MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val);
#define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val)) #define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val))
MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t);
......
...@@ -385,6 +385,7 @@ gc_protect(mrb_state *mrb, struct RBasic *p) ...@@ -385,6 +385,7 @@ gc_protect(mrb_state *mrb, struct RBasic *p)
mrb->arena[mrb->arena_idx++] = p; mrb->arena[mrb->arena_idx++] = p;
} }
/* mrb_gc_protect() leaves the object in the arena */
MRB_API void MRB_API void
mrb_gc_protect(mrb_state *mrb, mrb_value obj) mrb_gc_protect(mrb_state *mrb, mrb_value obj)
{ {
...@@ -392,6 +393,53 @@ 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)); 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; i<a->len; i++) {
if (!mrb_obj_eq(mrb, a->ptr[i], obj)) {
a->ptr[j++] = a->ptr[i];
}
}
a->len = j;
}
MRB_API struct RBasic* MRB_API struct RBasic*
mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment