Skip to content

Commit 6ebb716

Browse files
authored
Merge pull request #147 from mrkn/gcguard_numtable
Use st_table insterad of a Hash for GC guard table
2 parents 6412d21 + 6fd780b commit 6ebb716

File tree

4 files changed

+92
-8
lines changed

4 files changed

+92
-8
lines changed

ext/pycall/gc.c

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,74 @@
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+
372
static ID id_gcguard_table;
473
static PyObject *weakref_callback_pyobj;
574
static PyObject *gcguard_weakref_destroyed(PyObject *self, PyObject *weakref);
@@ -21,15 +90,15 @@ gcguard_weakref_destroyed(PyObject *self, PyObject *weakref)
2190
void
2291
pycall_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

2897
void
2998
pycall_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

35104
void
@@ -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+
67146
void
68147
pycall_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
}

lib/pycall/wrapper_object_cache.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ class WrapperObjectCache
66
rescue
77
WMAP_SUPPORT_INT_KEY = false
88
else
9-
WMAP_SUPPORT_INT_KEY = true
9+
case RUBY_PLATFORM
10+
when /cygwin/, /mingw/, /mswin/
11+
WMAP_SUPPORT_INT_KEY = false
12+
else
13+
WMAP_SUPPORT_INT_KEY = true
14+
end
1015
end
1116

1217
if WMAP_SUPPORT_INT_KEY

spec/pycall/libpython/api_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module LibPython
1010
it 'returns the different instance but the same address' do
1111
other = API.builtins_module_ptr
1212
expect(subject).not_to equal(other)
13-
expect(subject.__address__).to equal(other.__address__)
13+
expect(subject.__address__).to eq(other.__address__)
1414
end
1515
end
1616
end

spec/pycall_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@
125125
it 'returns a Module that wraps a Python object' do
126126
expect(subject).to be_a(Module)
127127
expect(subject).to be_a(PyCall::PyObjectWrapper)
128-
expect(subject.__pyptr__.__address__).to equal(PyCall::LibPython::API.builtins_module_ptr.__address__)
128+
expect(subject.__pyptr__.__address__).to eq(PyCall::LibPython::API.builtins_module_ptr.__address__)
129129
end
130130

131131
it 'returns the first-created wrapper module when called twice' do

0 commit comments

Comments
 (0)