ext/pycall/pycall.c in pycall-1.2.1 vs ext/pycall/pycall.c in pycall-1.3.0.dev
- old
+ new
@@ -68,10 +68,56 @@
{
Py_API(PyOS_AfterFork)();
return Qnil;
}
+static volatile pycall_tls_key without_gvl_key;
+
+int
+pycall_without_gvl_p(void)
+{
+ /*
+ * In pthread, the default value is NULL (== 0).
+ *
+ * In Win32 thread, the default value is 0 (initialized by TlsAlloc).
+ */
+ return (int)pycall_tls_get(without_gvl_key);
+}
+
+static inline int
+pycall_set_without_gvl(void)
+{
+ return pycall_tls_set(without_gvl_key, (void *)1);
+}
+
+static inline int
+pycall_set_with_gvl(void)
+{
+ return pycall_tls_set(without_gvl_key, (void *)0);
+}
+
+VALUE
+pycall_without_gvl(VALUE (* func)(VALUE), VALUE arg)
+{
+ int state;
+ VALUE result;
+
+ pycall_set_without_gvl();
+
+ result = rb_protect(func, arg, &state);
+
+ pycall_set_with_gvl();
+
+ return result;
+}
+
+static VALUE
+pycall_m_without_gvl(VALUE mod)
+{
+ return pycall_without_gvl(rb_yield, Qnil);
+}
+
/* ==== PyCall::PyPtr ==== */
const rb_data_type_t pycall_pyptr_data_type = {
"PyCall::PyPtr",
{ 0, pycall_pyptr_free, pycall_pyptr_memsize, },
@@ -888,30 +934,35 @@
PyObject *pycallable;
PyObject *args;
PyObject *kwargs;
};
-PyObject *
+static inline PyObject *
call_pyobject_call(struct call_pyobject_call_params *params)
{
PyObject *res;
res = Py_API(PyObject_Call)(params->pycallable, params->args, params->kwargs); /* New reference */
return res;
}
PyObject *
-pyobject_call_without_gvl(PyObject *pycallable, PyObject *args, PyObject *kwargs)
+pyobject_call(PyObject *pycallable, PyObject *args, PyObject *kwargs)
{
PyObject *res;
struct call_pyobject_call_params params;
params.pycallable = pycallable;
params.args = args;
params.kwargs = kwargs;
- res = (PyObject *)rb_thread_call_without_gvl(
- (void * (*)(void *))call_pyobject_call, (void *)¶ms,
- (rb_unblock_function_t *)pycall_interrupt_python_thread, NULL);
+ if (pycall_without_gvl_p()) {
+ res = (PyObject *)rb_thread_call_without_gvl(
+ (void * (*)(void *))call_pyobject_call, (void *)¶ms,
+ (rb_unblock_function_t *)pycall_interrupt_python_thread, NULL);
+ }
+ else {
+ res = call_pyobject_call(¶ms);
+ }
return res;
}
static VALUE
@@ -959,11 +1010,11 @@
pycall_pyerror_fetch_and_raise("PyDict_SetItemString in pycall_extract_kwargs_from_ruby_hash");
}
}
}
- res = pyobject_call_without_gvl(pycallable, args, kwargs); /* New reference */
+ res = pyobject_call(pycallable, args, kwargs); /* New reference */
if (!res) {
pycall_pyerror_fetch_and_raise("PyObject_Call in pycall_call_python_callable");
}
obj = pycall_pyobject_to_ruby(res);
pycall_Py_DecRef(res);
@@ -2182,9 +2233,12 @@
cPyError = rb_const_get_at(mPyCall, rb_intern("PyError"));
/* PyCall */
rb_define_module_function(mPyCall, "after_fork", pycall_after_fork, 0);
+
+ pycall_tls_create(&without_gvl_key);
+ rb_define_module_function(mPyCall, "without_gvl", pycall_m_without_gvl, 0);
/* PyCall::PyPtr */
cPyPtr = rb_define_class_under(mPyCall, "PyPtr", rb_cBasicObject);
rb_define_singleton_method(cPyPtr, "incref", pycall_pyptr_s_incref, 1);