11#include "pycall_internal.h"
22
3+ struct gcguard {
4+ st_table * guarded_objects ;
5+ };
6+
7+ static int
8+ gcguard_mark_i (st_data_t key , st_data_t val , st_data_t arg )
9+ {
10+ VALUE obj = (VALUE )val ;
11+ rb_gc_mark (obj );
12+ return ST_CONTINUE ;
13+ }
14+
15+ static void
16+ gcguard_mark (void * ptr )
17+ {
18+ struct gcguard * gg = (struct gcguard * )ptr ;
19+ st_foreach (gg -> guarded_objects , gcguard_mark_i , 0 );
20+ }
21+
22+ static void
23+ gcguard_free (void * ptr )
24+ {
25+ struct gcguard * gg = (struct gcguard * )ptr ;
26+ st_free_table (gg -> guarded_objects );
27+ }
28+
29+ static size_t
30+ gcguard_memsize (const void * ptr )
31+ {
32+ const struct gcguard * gg = (const struct gcguard * )ptr ;
33+ return st_memsize (gg -> guarded_objects );
34+ }
35+
36+ static rb_data_type_t gcguard_data_type = {
37+ "PyCall::gcguard" ,
38+ {
39+ gcguard_mark ,
40+ gcguard_free ,
41+ gcguard_memsize ,
42+ },
43+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
44+ 0 , 0 , RUBY_TYPED_FREE_IMMEDIATELY
45+ #endif
46+ };
47+
48+ static void
49+ gcguard_aset (VALUE gcguard , PyObject * pyptr , VALUE rbobj )
50+ {
51+ struct gcguard * gg ;
52+ TypedData_Get_Struct (gcguard , struct gcguard , & gcguard_data_type , gg );
53+
54+ st_insert (gg -> guarded_objects , (st_data_t )pyptr , (st_data_t )rbobj );
55+ }
56+
57+ static void
58+ gcguard_delete (VALUE gcguard , PyObject * pyptr )
59+ {
60+ if (rb_typeddata_is_kind_of (gcguard , & gcguard_data_type )) {
61+ /* This check is necessary to avoid error on the process finalization phase */
62+ struct gcguard * gg ;
63+ st_data_t key , val ;
64+
65+ TypedData_Get_Struct (gcguard , struct gcguard , & gcguard_data_type , gg );
66+
67+ key = (st_data_t )pyptr ;
68+ st_delete (gg -> guarded_objects , & key , & val );
69+ }
70+ }
71+
372static ID id_gcguard_table ;
473static PyObject * weakref_callback_pyobj ;
574static PyObject * gcguard_weakref_destroyed (PyObject * self , PyObject * weakref );
@@ -21,15 +90,15 @@ gcguard_weakref_destroyed(PyObject *self, PyObject *weakref)
2190void
2291pycall_gcguard_aset (PyObject * pyobj , VALUE rbobj )
2392{
24- VALUE table = rb_ivar_get (mPyCall , id_gcguard_table );
25- rb_hash_aset ( table , PTR2NUM ( pyobj ) , rbobj );
93+ VALUE gcguard = rb_ivar_get (mPyCall , id_gcguard_table );
94+ gcguard_aset ( gcguard , pyobj , rbobj );
2695}
2796
2897void
2998pycall_gcguard_delete (PyObject * pyobj )
3099{
31- VALUE table = rb_ivar_get (mPyCall , id_gcguard_table );
32- rb_hash_delete ( table , PTR2NUM ( pyobj ) );
100+ VALUE gcguard = rb_ivar_get (mPyCall , id_gcguard_table );
101+ gcguard_delete ( gcguard , pyobj );
33102}
34103
35104void
@@ -64,11 +133,21 @@ pycall_gcguard_register(PyObject *pyobj, VALUE obj)
64133 pycall_gcguard_aset (wref , obj );
65134}
66135
136+ static VALUE
137+ gcguard_new (void )
138+ {
139+ struct gcguard * gg ;
140+ VALUE obj = TypedData_Make_Struct (0 , struct gcguard , & gcguard_data_type , gg );
141+ gg -> guarded_objects = st_init_numtable ();
142+
143+ return obj ;
144+ }
145+
67146void
68147pycall_init_gcguard (void )
69148{
70149 id_gcguard_table = rb_intern ("gcguard_table" );
71- rb_ivar_set (mPyCall , id_gcguard_table , rb_hash_new ());
150+ rb_ivar_set (mPyCall , id_gcguard_table , gcguard_new ());
72151
73152 weakref_callback_pyobj = Py_API (PyCFunction_NewEx )(& gcguard_weakref_callback_def , NULL , NULL );
74153}
0 commit comments