ext/pycall/gc.c in pycall-1.4.0 vs ext/pycall/gc.c in pycall-1.4.1

- old
+ new

@@ -1,7 +1,76 @@ #include "pycall_internal.h" +struct gcguard { + st_table *guarded_objects; +}; + +static int +gcguard_mark_i(st_data_t key, st_data_t val, st_data_t arg) +{ + VALUE obj = (VALUE)val; + rb_gc_mark(obj); + return ST_CONTINUE; +} + +static void +gcguard_mark(void* ptr) +{ + struct gcguard *gg = (struct gcguard *)ptr; + st_foreach(gg->guarded_objects, gcguard_mark_i, 0); +} + +static void +gcguard_free(void* ptr) +{ + struct gcguard *gg = (struct gcguard *)ptr; + st_free_table(gg->guarded_objects); +} + +static size_t +gcguard_memsize(const void* ptr) +{ + const struct gcguard *gg = (const struct gcguard *)ptr; + return st_memsize(gg->guarded_objects); +} + +static rb_data_type_t gcguard_data_type = { + "PyCall::gcguard", + { + gcguard_mark, + gcguard_free, + gcguard_memsize, + }, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY +#endif +}; + +static void +gcguard_aset(VALUE gcguard, PyObject *pyptr, VALUE rbobj) +{ + struct gcguard *gg; + TypedData_Get_Struct(gcguard, struct gcguard, &gcguard_data_type, gg); + + st_insert(gg->guarded_objects, (st_data_t)pyptr, (st_data_t)rbobj); +} + +static void +gcguard_delete(VALUE gcguard, PyObject *pyptr) +{ + if (rb_typeddata_is_kind_of(gcguard, &gcguard_data_type)) { + /* This check is necessary to avoid error on the process finalization phase */ + struct gcguard *gg; + st_data_t key, val; + + TypedData_Get_Struct(gcguard, struct gcguard, &gcguard_data_type, gg); + + key = (st_data_t)pyptr; + st_delete(gg->guarded_objects, &key, &val); + } +} + static ID id_gcguard_table; static PyObject *weakref_callback_pyobj; static PyObject *gcguard_weakref_destroyed(PyObject *self, PyObject *weakref); PyMethodDef gcguard_weakref_callback_def = { @@ -19,19 +88,19 @@ } void pycall_gcguard_aset(PyObject *pyobj, VALUE rbobj) { - VALUE table = rb_ivar_get(mPyCall, id_gcguard_table); - rb_hash_aset(table, PTR2NUM(pyobj), rbobj); + VALUE gcguard = rb_ivar_get(mPyCall, id_gcguard_table); + gcguard_aset(gcguard, pyobj, rbobj); } void pycall_gcguard_delete(PyObject *pyobj) { - VALUE table = rb_ivar_get(mPyCall, id_gcguard_table); - rb_hash_delete(table, PTR2NUM(pyobj)); + VALUE gcguard = rb_ivar_get(mPyCall, id_gcguard_table); + gcguard_delete(gcguard, pyobj); } void pycall_gcguard_register_pyrubyobj(PyObject *pyobj) { @@ -62,13 +131,23 @@ wref = Py_API(PyWeakref_NewRef)(pyobj, weakref_callback_pyobj); pycall_gcguard_aset(wref, obj); } +static VALUE +gcguard_new(void) +{ + struct gcguard *gg; + VALUE obj = TypedData_Make_Struct(0, struct gcguard, &gcguard_data_type, gg); + gg->guarded_objects = st_init_numtable(); + + return obj; +} + void pycall_init_gcguard(void) { id_gcguard_table = rb_intern("gcguard_table"); - rb_ivar_set(mPyCall, id_gcguard_table, rb_hash_new()); + rb_ivar_set(mPyCall, id_gcguard_table, gcguard_new()); weakref_callback_pyobj = Py_API(PyCFunction_NewEx)(&gcguard_weakref_callback_def, NULL, NULL); }