pycall 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/pycall/pycall.c CHANGED
@@ -10,28 +10,58 @@ VALUE mLibPython;
10
10
  VALUE mAPI;
11
11
  VALUE mHelpers;
12
12
  VALUE mConversion;
13
- VALUE mPyObjectWrapper;
14
- VALUE mPyTypeObjectWrapper;
15
13
  VALUE mGCGuard;
16
14
 
17
15
  VALUE pycall_cPyPtr;
18
16
  VALUE cPyTypePtr;
19
- VALUE cTuple;
20
- VALUE cPyError;
21
17
 
22
- VALUE pycall_eError;
23
-
24
- static VALUE pycall_libpython_handle;
25
18
  static VALUE python_description;
26
19
  static VALUE python_version_string;
27
20
  static Py_ssize_t python_hexversion;
28
21
  static int python_major_version;
29
22
  static int python_has_stackless_extension;
30
23
  static PyObject *python_builtins_module;
31
- static VALUE python_type_mapping;
32
- static VALUE python_type_mapping;
33
24
  static ID id_python_type_mapping;
34
25
 
26
+ /* Don't keep Ruby objects that aren't pinned in C global variables.
27
+ * They may be moved by GC compaction. */
28
+
29
+ static inline VALUE
30
+ libpython_handle(void)
31
+ {
32
+ return rb_funcall(mLibPython, rb_intern("handle"), 0);
33
+ }
34
+
35
+ static inline VALUE
36
+ pyobject_wrapper_module(void)
37
+ {
38
+ return rb_const_get_at(mPyCall, rb_intern("PyObjectWrapper"));
39
+ }
40
+
41
+ static inline VALUE
42
+ pytypeobject_wrapper_module(void)
43
+ {
44
+ return rb_const_get_at(mPyCall, rb_intern("PyTypeObjectWrapper"));
45
+ }
46
+
47
+ static inline VALUE
48
+ error_class(void)
49
+ {
50
+ return rb_const_get_at(mPyCall, rb_intern("Error"));
51
+ }
52
+
53
+ static inline VALUE
54
+ pyerror_class(void)
55
+ {
56
+ return rb_const_get_at(mPyCall, rb_intern("PyError"));
57
+ }
58
+
59
+ static inline VALUE
60
+ python_type_mapping(void)
61
+ {
62
+ return rb_ivar_get(mConversion, id_python_type_mapping);
63
+ }
64
+
35
65
  int
36
66
  pycall_python_major_version(void)
37
67
  {
@@ -122,6 +152,58 @@ pycall_m_without_gvl(VALUE mod)
122
152
 
123
153
  /* ==== PyCall::PyPtr ==== */
124
154
 
155
+ struct pending_decref_list {
156
+ rb_nativethread_lock_t lock;
157
+ PyObject **pyptrs;
158
+ size_t count;
159
+ size_t capacity;
160
+ };
161
+
162
+ static struct pending_decref_list pending_decrefs;
163
+
164
+ static void
165
+ pycall_pending_decref_add(PyObject *pyobj)
166
+ {
167
+ rb_nativethread_lock_lock(&pending_decrefs.lock);
168
+ if (pending_decrefs.count == pending_decrefs.capacity) {
169
+ size_t new_capacity = pending_decrefs.capacity ? 2 * pending_decrefs.capacity : 64;
170
+ /* Not ruby_xrealloc: this function runs during GC, where xmalloc/xrealloc
171
+ * are prohibited (rb_bug "Cannot realloc during GC" since Ruby 3.3). */
172
+ PyObject **new_pyptrs = realloc(pending_decrefs.pyptrs, new_capacity * sizeof(PyObject *));
173
+ if (new_pyptrs == NULL) {
174
+ /* Leaking the object is preferable to blocking or crashing inside GC */
175
+ rb_nativethread_lock_unlock(&pending_decrefs.lock);
176
+ return;
177
+ }
178
+ pending_decrefs.pyptrs = new_pyptrs;
179
+ pending_decrefs.capacity = new_capacity;
180
+ }
181
+ pending_decrefs.pyptrs[pending_decrefs.count++] = pyobj;
182
+ rb_nativethread_lock_unlock(&pending_decrefs.lock);
183
+ }
184
+
185
+ static void
186
+ pycall_drain_pending_decrefs(void)
187
+ {
188
+ PyObject **pyptrs;
189
+ size_t i, count;
190
+
191
+ if (pending_decrefs.count == 0) return;
192
+
193
+ rb_nativethread_lock_lock(&pending_decrefs.lock);
194
+ pyptrs = pending_decrefs.pyptrs;
195
+ count = pending_decrefs.count;
196
+ pending_decrefs.pyptrs = NULL;
197
+ pending_decrefs.count = 0;
198
+ pending_decrefs.capacity = 0;
199
+ rb_nativethread_lock_unlock(&pending_decrefs.lock);
200
+
201
+ for (i = 0; i < count; ++i) {
202
+ pycall_Py_DecRef(pyptrs[i]);
203
+ }
204
+ free(pyptrs);
205
+ }
206
+
125
207
  const rb_data_type_t pycall_pyptr_data_type = {
126
208
  "PyCall::PyPtr",
127
209
  { 0, pycall_pyptr_free, pycall_pyptr_memsize, },
@@ -130,6 +212,11 @@ const rb_data_type_t pycall_pyptr_data_type = {
130
212
  #endif
131
213
  };
132
214
 
215
+ /* pycall_pyptr_free may be called by the GC sweeper on a thread that does
216
+ * not hold the GIL. PyCall keeps the GIL held by the thread that
217
+ * initialized Python for the entire lifetime of the process, so waiting
218
+ * for the GIL there (PyGILState_Ensure) blocks forever while the sweeper
219
+ * holds the GVL, freezing every Ruby thread in the process. */
133
220
  void
134
221
  pycall_pyptr_free(void *ptr)
135
222
  {
@@ -144,9 +231,9 @@ pycall_pyptr_free(void *ptr)
144
231
  pycall_Py_DecRef(pyobj);
145
232
  }
146
233
  else {
147
- PyGILState_STATE gstate = Py_API(PyGILState_Ensure)();
148
- pycall_Py_DecRef(pyobj);
149
- Py_API(PyGILState_Release)(gstate);
234
+ /* Instead of taking the GIL here, enqueue the pointer; the list is
235
+ * drained on the next Python call. */
236
+ pycall_pending_decref_add(pyobj);
150
237
  }
151
238
  }
152
239
 
@@ -628,6 +715,8 @@ pycall_libpython_api_PyObject_Dir(VALUE mod, VALUE pyptr)
628
715
  PyObject *dir;
629
716
  PyObject *pyobj;
630
717
 
718
+ pycall_drain_pending_decrefs();
719
+
631
720
  if (!is_pycall_pyptr(pyptr)) {
632
721
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
633
722
  }
@@ -647,6 +736,8 @@ pycall_libpython_api_PyList_Size(VALUE mod, VALUE pyptr)
647
736
  PyObject *pyobj;
648
737
  Py_ssize_t size;
649
738
 
739
+ pycall_drain_pending_decrefs();
740
+
650
741
  if (!is_pycall_pyptr(pyptr)) {
651
742
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
652
743
  }
@@ -667,6 +758,8 @@ pycall_libpython_api_PyList_GetItem(VALUE mod, VALUE pyptr, VALUE idx)
667
758
  PyObject *pyobj_item;
668
759
  Py_ssize_t i;
669
760
 
761
+ pycall_drain_pending_decrefs();
762
+
670
763
  if (!is_pycall_pyptr(pyptr)) {
671
764
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
672
765
  }
@@ -732,6 +825,8 @@ pycall_libpython_helpers_m_import_module(int argc, VALUE *argv, VALUE mod)
732
825
  VALUE name, globals, locals, fromlist, level;
733
826
  char const *name_cstr;
734
827
 
828
+ pycall_drain_pending_decrefs();
829
+
735
830
  rb_scan_args(argc, argv, "14", &name, &globals, &locals, &fromlist, &level);
736
831
 
737
832
  if (RB_TYPE_P(name, T_SYMBOL)) {
@@ -784,6 +879,8 @@ pycall_libpython_helpers_m_compare(VALUE mod, VALUE op, VALUE pyptr_a, VALUE pyp
784
879
  PyObject *pyobj_a, *pyobj_b, *res;
785
880
  int opid;
786
881
 
882
+ pycall_drain_pending_decrefs();
883
+
787
884
  opid = pycall_rich_compare_opid(op);
788
885
 
789
886
  if (!is_pycall_pyptr(pyptr_a)) {
@@ -838,6 +935,8 @@ pycall_libpython_helpers_m_getattr(int argc, VALUE *argv, VALUE mod)
838
935
  {
839
936
  VALUE pyptr, name, default_value;
840
937
 
938
+ pycall_drain_pending_decrefs();
939
+
841
940
  if (rb_scan_args(argc, argv, "21", &pyptr, &name, &default_value) == 2) {
842
941
  default_value = Qundef;
843
942
  }
@@ -859,6 +958,8 @@ pycall_libpython_helpers_m_hasattr_p(VALUE mod, VALUE pyptr, VALUE name)
859
958
  PyObject *pyobj;
860
959
  int res;
861
960
 
961
+ pycall_drain_pending_decrefs();
962
+
862
963
  if (!is_pycall_pyptr(pyptr)) {
863
964
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
864
965
  }
@@ -878,6 +979,8 @@ pycall_libpython_helpers_m_setattr(VALUE mod, VALUE pyptr, VALUE name, VALUE val
878
979
  {
879
980
  PyObject *pyobj, *pyval;
880
981
 
982
+ pycall_drain_pending_decrefs();
983
+
881
984
  if (!is_pycall_pyptr(pyptr)) {
882
985
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
883
986
  }
@@ -901,6 +1004,8 @@ pycall_libpython_helpers_m_delattr(VALUE mod, VALUE pyptr, VALUE name)
901
1004
  {
902
1005
  PyObject *pyobj;
903
1006
 
1007
+ pycall_drain_pending_decrefs();
1008
+
904
1009
  if (!is_pycall_pyptr(pyptr)) {
905
1010
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
906
1011
  }
@@ -924,6 +1029,8 @@ pycall_libpython_helpers_m_callable_p(VALUE mod, VALUE pyptr)
924
1029
  PyObject *pyobj;
925
1030
  int res;
926
1031
 
1032
+ pycall_drain_pending_decrefs();
1033
+
927
1034
  if (!is_pycall_pyptr(pyptr)) {
928
1035
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
929
1036
  }
@@ -940,6 +1047,8 @@ pycall_libpython_helpers_m_call_object(int argc, VALUE *argv, VALUE mod)
940
1047
  VALUE pyptr;
941
1048
  PyObject *pyobj;
942
1049
 
1050
+ pycall_drain_pending_decrefs();
1051
+
943
1052
  if (argc < 1) {
944
1053
  rb_raise(rb_eArgError, "too few arguments (%d for >=1)", argc);
945
1054
  }
@@ -1089,6 +1198,8 @@ pycall_pyobject_wrapper_wrapper_method(int argc, VALUE *argv, VALUE wrapper)
1089
1198
  char *name_cstr;
1090
1199
  PyObject *pyobj, *attr;
1091
1200
 
1201
+ pycall_drain_pending_decrefs();
1202
+
1092
1203
  pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
1093
1204
  if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
1094
1205
  rb_raise(rb_eTypeError, "Wrong wrapper object is given");
@@ -1144,6 +1255,8 @@ pycall_libpython_helpers_m_define_wrapper_method(VALUE mod, VALUE wrapper, VALUE
1144
1255
  PyObject *pyobj, *attr;
1145
1256
  char *name_cstr;
1146
1257
 
1258
+ pycall_drain_pending_decrefs();
1259
+
1147
1260
  pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
1148
1261
  if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
1149
1262
  rb_raise(rb_eTypeError, "Wrong wrapper object is given");
@@ -1191,10 +1304,10 @@ pycall_convert_index(VALUE index)
1191
1304
  }
1192
1305
  }
1193
1306
  else if (rb_obj_is_kind_of(index, rb_cRange)) {
1194
- pyobj = pycall_pyslice_from_ruby(index); /* New refrence */
1307
+ pyobj = pycall_pyslice_from_ruby(index); /* New reference */
1195
1308
  }
1196
1309
  else if (pycall_obj_is_step_range(index)) {
1197
- pyobj = pycall_pyslice_from_ruby(index); /* New refrence */
1310
+ pyobj = pycall_pyslice_from_ruby(index); /* New reference */
1198
1311
  }
1199
1312
  else {
1200
1313
  pyobj = pycall_pyobject_from_ruby(index); /* New reference */
@@ -1209,6 +1322,8 @@ pycall_libpython_helpers_m_getitem(VALUE mod, VALUE pyptr, VALUE key)
1209
1322
  PyObject *pyobj, *pyobj_key, *pyobj_v;
1210
1323
  VALUE obj;
1211
1324
 
1325
+ pycall_drain_pending_decrefs();
1326
+
1212
1327
  if (!is_pycall_pyptr(pyptr)) {
1213
1328
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
1214
1329
  }
@@ -1234,6 +1349,8 @@ pycall_libpython_helpers_m_setitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1234
1349
  PyObject *pyobj, *pyobj_key, *pyobj_value;
1235
1350
  int res;
1236
1351
 
1352
+ pycall_drain_pending_decrefs();
1353
+
1237
1354
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1238
1355
  pyobj_key = pycall_convert_index(key);
1239
1356
  pyobj_value = pycall_pyobject_from_ruby(v);
@@ -1254,6 +1371,8 @@ pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key)
1254
1371
  PyObject *pyobj, *pyobj_key;
1255
1372
  int res;
1256
1373
 
1374
+ pycall_drain_pending_decrefs();
1375
+
1257
1376
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1258
1377
  pyobj_key = pycall_convert_index(key);
1259
1378
 
@@ -1271,6 +1390,8 @@ pycall_libpython_helpers_m_str(VALUE mod, VALUE pyptr)
1271
1390
  {
1272
1391
  PyObject *pyobj, *pyobj_str;
1273
1392
 
1393
+ pycall_drain_pending_decrefs();
1394
+
1274
1395
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1275
1396
 
1276
1397
  pyobj_str = Py_API(PyObject_Str)(pyobj);
@@ -1289,6 +1410,8 @@ pycall_libpython_helpers_m_dict_contains(VALUE mod, VALUE pyptr, VALUE key)
1289
1410
  PyObject *pyobj, *pyobj_key;
1290
1411
  int res;
1291
1412
 
1413
+ pycall_drain_pending_decrefs();
1414
+
1292
1415
  pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
1293
1416
  pyobj_key = pycall_pyobject_from_ruby(key);
1294
1417
  res = Py_API(PyDict_Contains)(pyobj, pyobj_key);
@@ -1306,6 +1429,8 @@ pycall_libpython_helpers_m_dict_each(VALUE mod, VALUE pyptr)
1306
1429
  PyObject *pyobj, *pyobj_key, *pyobj_value;
1307
1430
  Py_ssize_t pos;
1308
1431
 
1432
+ pycall_drain_pending_decrefs();
1433
+
1309
1434
  pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
1310
1435
 
1311
1436
  pos = 0;
@@ -1325,6 +1450,8 @@ pycall_libpython_helpers_m_sequence_contains(VALUE mod, VALUE pyptr, VALUE key)
1325
1450
  PyObject *pyobj, *pyobj_key;
1326
1451
  int res;
1327
1452
 
1453
+ pycall_drain_pending_decrefs();
1454
+
1328
1455
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1329
1456
  if (!Py_API(PySequence_Check)(pyobj))
1330
1457
  rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
@@ -1344,6 +1471,8 @@ pycall_libpython_helpers_m_sequence_each(VALUE mod, VALUE pyptr)
1344
1471
  {
1345
1472
  PyObject *pyobj, *pyobj_iter, *pyobj_item;
1346
1473
 
1474
+ pycall_drain_pending_decrefs();
1475
+
1347
1476
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1348
1477
  if (!Py_API(PySequence_Check)(pyobj))
1349
1478
  rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
@@ -1372,7 +1501,7 @@ pycall_libpython_helpers_m_sequence_each(VALUE mod, VALUE pyptr)
1372
1501
  static int
1373
1502
  is_pyobject_wrapper(VALUE obj)
1374
1503
  {
1375
- return RTEST(rb_obj_is_kind_of(obj, mPyObjectWrapper));
1504
+ return RTEST(rb_obj_is_kind_of(obj, pyobject_wrapper_module()));
1376
1505
  }
1377
1506
 
1378
1507
  static VALUE
@@ -1425,7 +1554,7 @@ pycall_python_type_mapping_get_mapped_ancestor_class(VALUE pytypeptr)
1425
1554
  args[0] = pytypeptr;
1426
1555
  args[1] = Qnil;
1427
1556
 
1428
- rb_hash_foreach(python_type_mapping, get_mapped_ancestor_class_iter, (VALUE)args);
1557
+ rb_hash_foreach(python_type_mapping(), get_mapped_ancestor_class_iter, (VALUE)args);
1429
1558
 
1430
1559
  return args[1];
1431
1560
  }
@@ -1435,7 +1564,7 @@ pycall_python_type_mapping_get_mapped_class(VALUE pytypeptr)
1435
1564
  {
1436
1565
  VALUE mapped;
1437
1566
  (void)check_get_pytypeobj_ptr(pytypeptr);
1438
- mapped = rb_hash_lookup(python_type_mapping, pytypeptr);
1567
+ mapped = rb_hash_lookup(python_type_mapping(), pytypeptr);
1439
1568
  if (NIL_P(mapped)) {
1440
1569
  mapped = pycall_python_type_mapping_get_mapped_ancestor_class(pytypeptr);
1441
1570
  }
@@ -1446,16 +1575,16 @@ static int
1446
1575
  pycall_python_type_mapping_register(VALUE pytypeptr, VALUE rbcls)
1447
1576
  {
1448
1577
  (void)check_get_pytypeobj_ptr(pytypeptr);
1449
- if (rb_hash_lookup2(python_type_mapping, pytypeptr, Qundef) != Qundef)
1578
+ if (rb_hash_lookup2(python_type_mapping(), pytypeptr, Qundef) != Qundef)
1450
1579
  return 0;
1451
1580
 
1452
1581
  Check_Type(rbcls, T_CLASS);
1453
- if (!rb_obj_is_kind_of(rbcls, mPyTypeObjectWrapper)) {
1582
+ if (!rb_obj_is_kind_of(rbcls, pytypeobject_wrapper_module())) {
1454
1583
  rb_raise(rb_eTypeError, "ruby class must be extended by PyCall::PyTypeObjectWrapper");
1455
1584
  }
1456
1585
 
1457
1586
  /* TODO: Shouldn't have to use weak reference? */
1458
- rb_hash_aset(python_type_mapping, pytypeptr, rbcls);
1587
+ rb_hash_aset(python_type_mapping(), pytypeptr, rbcls);
1459
1588
 
1460
1589
  return 1;
1461
1590
  }
@@ -1464,10 +1593,10 @@ static int
1464
1593
  pycall_python_type_mapping_unregister(VALUE pytypeptr)
1465
1594
  {
1466
1595
  (void)check_get_pytypeobj_ptr(pytypeptr);
1467
- if (rb_hash_lookup2(python_type_mapping, pytypeptr, Qundef) == Qundef)
1596
+ if (rb_hash_lookup2(python_type_mapping(), pytypeptr, Qundef) == Qundef)
1468
1597
  return 0;
1469
1598
 
1470
- rb_hash_delete(python_type_mapping, pytypeptr);
1599
+ rb_hash_delete(python_type_mapping(), pytypeptr);
1471
1600
  return 1;
1472
1601
  }
1473
1602
 
@@ -1478,7 +1607,7 @@ pycall_pyobject_wrapper_object_new(VALUE klass, PyObject *pyobj)
1478
1607
 
1479
1608
  obj = rb_obj_alloc(klass);
1480
1609
  rb_ivar_set(obj, rb_intern("@__pyptr__"), pycall_pyptr_new(pyobj));
1481
- rb_extend_object(obj, mPyObjectWrapper);
1610
+ rb_extend_object(obj, pyobject_wrapper_module());
1482
1611
 
1483
1612
  return obj;
1484
1613
  }
@@ -1528,7 +1657,7 @@ pycall_pyobject_to_ruby(PyObject *pyobj)
1528
1657
  Py_API(Py_IncRef)((PyObject *)pyobj->ob_type);
1529
1658
  cls = pycall_python_type_mapping_get_mapped_class(pycall_pytypeptr_new((PyObject *)pyobj->ob_type));
1530
1659
  if (NIL_P(cls)) {
1531
- rb_warning("Currentry do not support to convert %s to Ruby object", Py_TYPE(pyobj)->tp_name);
1660
+ rb_warning("Currently do not support to convert %s to Ruby object", Py_TYPE(pyobj)->tp_name);
1532
1661
  return pycall_pyobject_wrapper_object_new(rb_cObject, pyobj);
1533
1662
  }
1534
1663
 
@@ -1663,7 +1792,7 @@ pycall_pylong_to_ruby(PyObject *pyobj)
1663
1792
  }
1664
1793
  #endif
1665
1794
 
1666
- rb_warning("Currentry do not support to convert multi-precision PyLong number to Ruby object");
1795
+ rb_warning("Currently do not support to convert multi-precision PyLong number to Ruby object");
1667
1796
 
1668
1797
  return Qnil;
1669
1798
  }
@@ -1787,7 +1916,11 @@ pycall_conv_m_unregister_python_type_mapping(VALUE mod, VALUE pytypeptr)
1787
1916
  static VALUE
1788
1917
  pycall_conv_m_from_ruby(VALUE mod, VALUE obj)
1789
1918
  {
1790
- PyObject *pyobj = pycall_pyobject_from_ruby(obj);
1919
+ PyObject *pyobj;
1920
+
1921
+ pycall_drain_pending_decrefs();
1922
+
1923
+ pyobj = pycall_pyobject_from_ruby(obj);
1791
1924
  if (PyType_Check(pyobj) || PyClass_Check(pyobj))
1792
1925
  return pycall_pytypeptr_new(pyobj);
1793
1926
  if (PyRuby_Check(pyobj))
@@ -1799,7 +1932,11 @@ static VALUE
1799
1932
  pycall_conv_m_to_ruby(VALUE mod, VALUE pyptr)
1800
1933
  {
1801
1934
  VALUE obj, obj_pyptr;
1802
- PyObject *pyobj = check_get_pyobj_ptr(pyptr, NULL);
1935
+ PyObject *pyobj;
1936
+
1937
+ pycall_drain_pending_decrefs();
1938
+
1939
+ pyobj = check_get_pyobj_ptr(pyptr, NULL);
1803
1940
  obj = obj_pyptr = pycall_pyobject_to_ruby(pyobj);
1804
1941
  if (is_pyobject_wrapper(obj)) {
1805
1942
  obj_pyptr = pycall_pyobject_wrapper_get_pyptr(obj);
@@ -2060,7 +2197,7 @@ pycall_pyerror_new(PyObject *type, PyObject *value, PyObject *traceback)
2060
2197
  init_args[1] = value ? pycall_pyobject_to_ruby(value) : Qnil;
2061
2198
  init_args[2] = traceback ? pycall_pyobject_to_ruby(traceback) : Qnil;
2062
2199
 
2063
- return rb_class_new_instance(3, init_args, cPyError);
2200
+ return rb_class_new_instance(3, init_args, pyerror_class());
2064
2201
  }
2065
2202
 
2066
2203
  VALUE
@@ -2094,7 +2231,7 @@ pycall_pyerror_fetch_and_raise(char const *format, ...)
2094
2231
  msg = rb_vsprintf(format, args);
2095
2232
  va_end(args);
2096
2233
 
2097
- rb_exc_raise(rb_exc_new3(eError, msg));
2234
+ rb_exc_raise(rb_exc_new3(error_class(), msg));
2098
2235
  }
2099
2236
 
2100
2237
  unsigned long
@@ -2225,7 +2362,7 @@ init_python(void)
2225
2362
  Py_API(Py_IncRef)((PyObject *)Py_API(PyUnicode_Type));
2226
2363
  rb_define_const(mAPI, "PyUnicode_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyUnicode_Type)));
2227
2364
 
2228
- pycall_init_exceptions(pycall_libpython_handle);
2365
+ pycall_init_exceptions(libpython_handle());
2229
2366
  }
2230
2367
 
2231
2368
  static VALUE
@@ -2286,6 +2423,7 @@ pycall_pyerror_s_fetch(VALUE klass)
2286
2423
  static void
2287
2424
  init_pyerror(void)
2288
2425
  {
2426
+ VALUE cPyError = pyerror_class();
2289
2427
  rb_define_singleton_method(cPyError, "occurred?", pycall_pyerror_s_occurred_p, 0);
2290
2428
  rb_define_singleton_method(cPyError, "fetch", pycall_pyerror_s_fetch, 0);
2291
2429
  }
@@ -2293,7 +2431,7 @@ init_pyerror(void)
2293
2431
  static void
2294
2432
  init_tuple(void)
2295
2433
  {
2296
- cTuple = rb_funcall(mPyCall, rb_intern("wrap_class"), 1, pycall_pytypeptr_new((PyObject *)Py_API(PyTuple_Type)));
2434
+ VALUE cTuple = rb_funcall(mPyCall, rb_intern("wrap_class"), 1, pycall_pytypeptr_new((PyObject *)Py_API(PyTuple_Type)));
2297
2435
  rb_define_const(mPyCall, "Tuple", cTuple);
2298
2436
  rb_funcall(cTuple, rb_intern("register_python_type_mapping"), 0);
2299
2437
  rb_define_singleton_method(cTuple, "new", pycall_tuple_s_new, -1);
@@ -2308,11 +2446,7 @@ Init_pycall(void)
2308
2446
  pycall_hash_salt = FIX2LONG(rb_hash(rb_str_new2("PyCall::PyObject")));
2309
2447
 
2310
2448
  mPyCall = rb_define_module("PyCall");
2311
- mPyObjectWrapper = rb_const_get_at(mPyCall, rb_intern("PyObjectWrapper"));
2312
- mPyTypeObjectWrapper = rb_const_get_at(mPyCall, rb_intern("PyTypeObjectWrapper"));
2313
2449
  mGCGuard = rb_define_module_under(mPyCall, "GCGuard");
2314
- eError = rb_const_get_at(mPyCall, rb_intern("Error"));
2315
- cPyError = rb_const_get_at(mPyCall, rb_intern("PyError"));
2316
2450
 
2317
2451
  /* PyCall */
2318
2452
 
@@ -2321,6 +2455,8 @@ Init_pycall(void)
2321
2455
  pycall_tls_create((pycall_tls_key *)&without_gvl_key);
2322
2456
  rb_define_module_function(mPyCall, "without_gvl", pycall_m_without_gvl, 0);
2323
2457
 
2458
+ rb_nativethread_lock_initialize(&pending_decrefs.lock);
2459
+
2324
2460
  /* PyCall::PyPtr */
2325
2461
 
2326
2462
  cPyPtr = rb_define_class_under(mPyCall, "PyPtr", rb_cBasicObject);
@@ -2362,8 +2498,7 @@ Init_pycall(void)
2362
2498
  /* PyCall::LibPython::API */
2363
2499
 
2364
2500
  mLibPython = rb_define_module_under(mPyCall, "LibPython");
2365
- pycall_libpython_handle = rb_funcall(mLibPython, rb_intern("handle"), 0);
2366
- pycall_init_libpython_api_table(pycall_libpython_handle);
2501
+ pycall_init_libpython_api_table(libpython_handle());
2367
2502
 
2368
2503
  mAPI = rb_define_module_under(mLibPython, "API");
2369
2504
 
@@ -2405,9 +2540,8 @@ Init_pycall(void)
2405
2540
  rb_define_module_function(mConversion, "from_ruby", pycall_conv_m_from_ruby, 1);
2406
2541
  rb_define_module_function(mConversion, "to_ruby", pycall_conv_m_to_ruby, 1);
2407
2542
 
2408
- python_type_mapping = rb_hash_new();
2409
2543
  id_python_type_mapping = rb_intern("__python_type_mapping__");
2410
- rb_ivar_set(mConversion, id_python_type_mapping, python_type_mapping);
2544
+ rb_ivar_set(mConversion, id_python_type_mapping, rb_hash_new());
2411
2545
 
2412
2546
  /* initialize the constat PYTHON_VERSION */
2413
2547
 
@@ -11,6 +11,7 @@ extern "C" {
11
11
  #include <ruby.h>
12
12
  #include <ruby/encoding.h>
13
13
  #include <ruby/thread.h>
14
+ #include <ruby/thread_native.h>
14
15
 
15
16
  #include <assert.h>
16
17
  #include <inttypes.h>
@@ -71,7 +72,7 @@ typedef intptr_t Py_intptr_t;
71
72
  #ifdef HAVE_SSIZE_T
72
73
  typedef ssize_t Py_ssize_t;
73
74
  #elif SIZEOF_SIZE_T == SIZEOF_VOIDP
74
- typedef Py_intptr_tr Py_ssize_t;
75
+ typedef Py_intptr_t Py_ssize_t;
75
76
  #elif SIZEOF_SIZE_T == SIZEOF_INT
76
77
  typedef int Py_ssize_t;
77
78
  #elif SIZEOF_SIZE_T == SIZEOF_LONG
@@ -745,11 +746,9 @@ void pycall_init_ruby_wrapper(void);
745
746
  extern intptr_t pycall_hash_salt;
746
747
  extern VALUE pycall_mPyCall;
747
748
  extern VALUE pycall_cPyPtr;
748
- extern VALUE pycall_eError;
749
749
 
750
750
  #define mPyCall pycall_mPyCall
751
751
  #define cPyPtr pycall_cPyPtr
752
- #define eError pycall_eError
753
752
 
754
753
  /* #define PYCALL_DEBUG_DUMP_REFCNT */
755
754
 
@@ -6,7 +6,6 @@ static PyMemberDef PyRuby_members[] = {
6
6
  {NULL} /* sentinel */
7
7
  };
8
8
 
9
- static VALUE PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj);
10
9
  static void PyRuby_dealloc_with_gvl(PyRubyObject *);
11
10
  static PyObject * PyRuby_repr_with_gvl(PyRubyObject *);
12
11
  static PyObject * PyRuby_call_with_gvl(PyRubyObject *, PyObject *, PyObject *);
@@ -102,9 +101,7 @@ PyRuby_repr(PyRubyObject *pyro)
102
101
  VALUE obj, str;
103
102
  PyObject *res;
104
103
 
105
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
106
- if (obj == Qundef)
107
- return NULL;
104
+ obj = PyRuby_get_ruby_object((PyObject *)pyro);
108
105
 
109
106
  str = rb_inspect(obj);
110
107
  res = pycall_pystring_from_format("<PyCall.ruby_object %s>", StringValueCStr(str));
@@ -143,9 +140,7 @@ PyRuby_hash_long(PyRubyObject *pyro)
143
140
  VALUE obj, rbhash;
144
141
  intptr_t h;
145
142
 
146
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
147
- if (obj == Qundef)
148
- return (void *)-1;
143
+ obj = PyRuby_get_ruby_object((PyObject *)pyro);
149
144
 
150
145
  rbhash = rb_hash(obj);
151
146
  h = FIX2LONG(rbhash); /* Ruby's hash value is a Fixnum */
@@ -170,9 +165,7 @@ PyRuby_hash_hash_t(PyRubyObject *pyro)
170
165
  VALUE obj, rbhash;
171
166
  Py_hash_t h;
172
167
 
173
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
174
- if (obj == Qundef)
175
- return (void *)-1;
168
+ obj = PyRuby_get_ruby_object((PyObject *)pyro);
176
169
 
177
170
  rbhash = rb_hash(obj);
178
171
  #if SIZEOF_PY_HASH_T == SIZEOF_LONG
@@ -242,9 +235,7 @@ PyRuby_call(struct PyRuby_call_params *params)
242
235
  PyObject *pyobj_res;
243
236
  int state;
244
237
 
245
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)params->pyro);
246
- if (obj == Qundef)
247
- return NULL;
238
+ obj = PyRuby_get_ruby_object((PyObject *)params->pyro);
248
239
 
249
240
  id_call = rb_intern("call");
250
241
  if (!rb_respond_to(obj, id_call)) {
@@ -296,9 +287,7 @@ PyRuby_getattro(struct PyRuby_getattro_params *params)
296
287
  ID name_id;
297
288
  PyObject *pyobj_res;
298
289
 
299
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)params->pyro);
300
- if (obj == Qundef)
301
- return NULL;
290
+ obj = PyRuby_get_ruby_object((PyObject *)params->pyro);
302
291
 
303
292
  name = pycall_pyobject_to_ruby(params->pyobj_name);
304
293
  name_cstr = StringValueCStr(name);
@@ -489,56 +478,3 @@ pycall_init_ruby_wrapper(void)
489
478
  rb_define_module_function(mPyCall, "wrap_ruby_object", pycall_m_wrap_ruby_object, 1);
490
479
  }
491
480
 
492
- /* --- File internal utilities --- */
493
-
494
- static VALUE
495
- funcall_id2ref(VALUE object_id)
496
- {
497
- VALUE rb_mObjSpace;
498
- object_id = rb_check_to_integer(object_id, "to_int");
499
- rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
500
- return rb_funcall(rb_mObjSpace, rb_intern("_id2ref"), 1, object_id);
501
- }
502
-
503
- static VALUE
504
- protect_id2ref(VALUE object_id)
505
- {
506
- VALUE obj;
507
- int state;
508
-
509
- obj = rb_protect((VALUE (*)(VALUE))funcall_id2ref, object_id, &state);
510
- if (state)
511
- return Qundef;
512
-
513
- return obj;
514
- }
515
-
516
- static VALUE
517
- protect_id2ref_and_set_pyerr(VALUE object_id)
518
- {
519
- VALUE obj = protect_id2ref(object_id);
520
- if (obj != Qundef)
521
- return obj;
522
-
523
- obj = rb_errinfo();
524
- if (RTEST(rb_obj_is_kind_of(obj, rb_eRangeError))) {
525
- Py_API(PyErr_SetString)(Py_API(PyExc_RuntimeError), "[BUG] referenced object was garbage-collected");
526
- }
527
- else {
528
- VALUE emesg = rb_check_funcall(obj, rb_intern("message"), 0, 0);
529
- Py_API(PyErr_Format)(Py_API(PyExc_RuntimeError),
530
- "[BUG] Unable to obtain ruby object from ID: %s (%s)",
531
- StringValueCStr(emesg), rb_class2name(CLASS_OF(obj)));
532
- }
533
- return Qundef;
534
- }
535
-
536
- static VALUE
537
- PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj)
538
- {
539
- VALUE obj_id;
540
- if (!PyRuby_Check(pyobj))
541
- return Qundef;
542
- obj_id = rb_obj_id(PyRuby_get_ruby_object(pyobj));
543
- return protect_id2ref_and_set_pyerr(obj_id);
544
- }
@@ -231,7 +231,7 @@ module PyCall
231
231
  else
232
232
  name, basic_size = *args
233
233
  new.tap do |t|
234
- # NOTE: Disable autorelease for avoiding SEGV occurrance in Python's GC collect function
234
+ # NOTE: Disable autorelease for avoiding SEGV occurrence in Python's GC collect function
235
235
  # at which the __new__ method object of this type object is freed.
236
236
  t.pointer.autorelease = false
237
237