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);
}