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 *)&params, - (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 *)&params, + (rb_unblock_function_t *)pycall_interrupt_python_thread, NULL); + } + else { + res = call_pyobject_call(&params); + } 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);