Make pycapnp GIL friendly
Now calling `wait` from one thread will not block all threads
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
#include "capnp/dynamic.h"
|
||||
#include <stdexcept>
|
||||
#include "Python.h"
|
||||
#include <iostream>
|
||||
|
||||
extern "C" {
|
||||
PyObject * wrap_remote_call(PyObject * func, capnp::Response<capnp::DynamicStruct> &);
|
||||
@@ -17,12 +16,38 @@ extern "C" {
|
||||
::capnp::RemotePromise< ::capnp::DynamicStruct> * extract_remote_promise(PyObject *);
|
||||
}
|
||||
|
||||
class GILAcquire {
|
||||
public:
|
||||
GILAcquire() : gstate(PyGILState_Ensure()) {}
|
||||
~GILAcquire() {
|
||||
PyGILState_Release(gstate);
|
||||
}
|
||||
|
||||
PyGILState_STATE gstate;
|
||||
};
|
||||
|
||||
class GILRelease {
|
||||
public:
|
||||
GILRelease() {
|
||||
Py_UNBLOCK_THREADS
|
||||
}
|
||||
~GILRelease() {
|
||||
Py_BLOCK_THREADS
|
||||
}
|
||||
|
||||
PyThreadState *_save; // The macros above read/write from this variable
|
||||
};
|
||||
|
||||
::kj::Promise<PyObject *> convert_to_pypromise(capnp::RemotePromise<capnp::DynamicStruct> & promise) {
|
||||
return promise.then([](capnp::Response<capnp::DynamicStruct>&& response) { return wrap_dynamic_struct_reader(response); } );
|
||||
}
|
||||
|
||||
::kj::Promise<PyObject *> convert_to_pypromise(kj::Promise<void> & promise) {
|
||||
return promise.then([]() { Py_RETURN_NONE;} );
|
||||
return promise.then([]() {
|
||||
GILAcquire gil;
|
||||
Py_INCREF( Py_None );
|
||||
return Py_None;
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@@ -31,6 +56,7 @@ template<class T>
|
||||
}
|
||||
|
||||
void reraise_kj_exception() {
|
||||
GILAcquire gil;
|
||||
try {
|
||||
if (PyErr_Occurred())
|
||||
; // let the latest Python exn pass through and ignore the current one
|
||||
@@ -51,6 +77,7 @@ void reraise_kj_exception() {
|
||||
}
|
||||
|
||||
void check_py_error() {
|
||||
GILAcquire gil;
|
||||
PyObject * err = PyErr_Occurred();
|
||||
if(err) {
|
||||
PyObject * ptype, *pvalue, *ptraceback;
|
||||
@@ -80,6 +107,7 @@ void check_py_error() {
|
||||
}
|
||||
|
||||
kj::Promise<PyObject *> wrapPyFunc(PyObject * func, PyObject * arg) {
|
||||
GILAcquire gil;
|
||||
auto arg_promise = extract_promise(arg);
|
||||
|
||||
if(arg_promise == NULL) {
|
||||
@@ -102,6 +130,7 @@ kj::Promise<PyObject *> wrapPyFunc(PyObject * func, PyObject * arg) {
|
||||
}
|
||||
|
||||
kj::Promise<PyObject *> wrapPyFuncNoArg(PyObject * func) {
|
||||
GILAcquire gil;
|
||||
PyObject * result = PyObject_CallFunctionObjArgs(func, NULL);
|
||||
|
||||
check_py_error();
|
||||
@@ -116,6 +145,7 @@ kj::Promise<PyObject *> wrapPyFuncNoArg(PyObject * func) {
|
||||
}
|
||||
|
||||
kj::Promise<PyObject *> wrapRemoteCall(PyObject * func, capnp::Response<capnp::DynamicStruct> & arg) {
|
||||
GILAcquire gil;
|
||||
PyObject * ret = wrap_remote_call(func, arg);
|
||||
|
||||
check_py_error();
|
||||
@@ -163,10 +193,12 @@ public:
|
||||
|
||||
PythonInterfaceDynamicImpl(capnp::InterfaceSchema & schema, PyObject * _py_server)
|
||||
: capnp::DynamicCapability::Server(schema), py_server(_py_server) {
|
||||
GILAcquire gil;
|
||||
Py_INCREF(_py_server);
|
||||
}
|
||||
|
||||
~PythonInterfaceDynamicImpl() {
|
||||
GILAcquire gil;
|
||||
Py_DECREF(py_server);
|
||||
}
|
||||
|
||||
@@ -192,14 +224,17 @@ public:
|
||||
PyObject * obj;
|
||||
|
||||
PyRefCounter(PyObject * o) : obj(o) {
|
||||
GILAcquire gil;
|
||||
Py_INCREF(obj);
|
||||
}
|
||||
|
||||
PyRefCounter(const PyRefCounter & ref) : obj(ref.obj) {
|
||||
GILAcquire gil;
|
||||
Py_INCREF(obj);
|
||||
}
|
||||
|
||||
~PyRefCounter() {
|
||||
GILAcquire gil;
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user