Move exported functions used in capabilityHelper.h from extern "C" to api.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman
2020-02-28 16:58:26 -08:00
parent e0d3618aa6
commit dbc9debbbf
7 changed files with 215 additions and 172 deletions

View File

@@ -0,0 +1,159 @@
#include "capnp/helpers/capabilityHelper.h"
#include "capnp/lib/capnp_api.h"
::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); } );
}
void reraise_kj_exception() {
GILAcquire gil;
try {
if (PyErr_Occurred())
; // let the latest Python exn pass through and ignore the current one
else
throw;
}
catch (kj::Exception& exn) {
auto obj = wrap_kj_exception_for_reraise(exn);
PyErr_SetObject((PyObject*)obj->ob_type, obj);
Py_DECREF(obj);
}
catch (const std::exception& exn) {
PyErr_SetString(PyExc_RuntimeError, exn.what());
}
catch (...)
{
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
}
void check_py_error() {
GILAcquire gil;
PyObject * err = PyErr_Occurred();
if(err) {
PyObject * ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
if(ptype == NULL || pvalue == NULL || ptraceback == NULL)
throw kj::Exception(kj::Exception::Type::FAILED, kj::heapString("capabilityHelper.h"), 44, kj::heapString("Unknown error occurred"));
PyObject * info = get_exception_info(ptype, pvalue, ptraceback);
PyObject * py_filename = PyTuple_GetItem(info, 0);
kj::String filename(kj::heapString(PyBytes_AsString(py_filename)));
PyObject * py_line = PyTuple_GetItem(info, 1);
int line = PyLong_AsLong(py_line);
PyObject * py_description = PyTuple_GetItem(info, 2);
kj::String description(kj::heapString(PyBytes_AsString(py_description)));
Py_DECREF(ptype);
Py_DECREF(pvalue);
Py_DECREF(ptraceback);
Py_DECREF(info);
PyErr_Clear();
throw kj::Exception(kj::Exception::Type::FAILED, kj::mv(filename), line, kj::mv(description));
}
}
kj::Promise<PyObject *> wrapPyFunc(PyObject * func, PyObject * arg) {
GILAcquire gil;
auto arg_promise = extract_promise(arg);
if(arg_promise == NULL) {
PyObject * result = PyObject_CallFunctionObjArgs(func, arg, NULL);
Py_DECREF(arg);
check_py_error();
auto promise = extract_promise(result);
if(promise != NULL)
return kj::mv(*promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
auto remote_promise = extract_remote_promise(result);
if(remote_promise != NULL)
return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
return result;
}
else {
return arg_promise->then([&](PyObject * new_arg){ return wrapPyFunc(func, new_arg); });// TODO: delete arg_promise?
}
}
kj::Promise<PyObject *> wrapPyFuncNoArg(PyObject * func) {
GILAcquire gil;
PyObject * result = PyObject_CallFunctionObjArgs(func, NULL);
check_py_error();
auto promise = extract_promise(result);
if(promise != NULL)
return kj::mv(*promise);
auto remote_promise = extract_remote_promise(result);
if(remote_promise != NULL)
return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
return result;
}
kj::Promise<PyObject *> wrapRemoteCall(PyObject * func, capnp::Response<capnp::DynamicStruct> & arg) {
GILAcquire gil;
PyObject * ret = wrap_remote_call(func, arg);
check_py_error();
auto promise = extract_promise(ret);
if(promise != NULL)
return kj::mv(*promise);
auto remote_promise = extract_remote_promise(ret);
if(remote_promise != NULL)
return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
return ret;
}
::kj::Promise<PyObject *> then(kj::Promise<PyObject *> & promise, PyObject * func, PyObject * error_func) {
if(error_func == Py_None)
return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); } );
else
return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); }
, [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } );
}
::kj::Promise<PyObject *> then(::capnp::RemotePromise< ::capnp::DynamicStruct> & promise, PyObject * func, PyObject * error_func) {
if(error_func == Py_None)
return promise.then([func](capnp::Response<capnp::DynamicStruct>&& arg) { return wrapRemoteCall(func, arg); } );
else
return promise.then([func](capnp::Response<capnp::DynamicStruct>&& arg) { return wrapRemoteCall(func, arg); }
, [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } );
}
::kj::Promise<PyObject *> then(kj::Promise<void> & promise, PyObject * func, PyObject * error_func) {
if(error_func == Py_None)
return promise.then([func]() { return wrapPyFuncNoArg(func); } );
else
return promise.then([func]() { return wrapPyFuncNoArg(func); }
, [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } );
}
::kj::Promise<PyObject *> then(kj::Promise<kj::Array<PyObject *> > && promise) {
return promise.then([](kj::Array<PyObject *>&& arg) { return convert_array_pyobject(arg); } );
}
kj::Promise<void> PythonInterfaceDynamicImpl::call(capnp::InterfaceSchema::Method method,
capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context) {
auto methodName = method.getProto().getName();
kj::Promise<void> * promise = call_server_method(py_server, const_cast<char *>(methodName.cStr()), context);
check_py_error();
if(promise == nullptr)
return kj::READY_NOW;
kj::Promise<void> ret(kj::mv(*promise));
delete promise;
return ret;
};
void init_capnp_api() {
import_capnp__lib__capnp();
}

View File

@@ -4,18 +4,6 @@
#include <stdexcept>
#include "Python.h"
extern "C" {
PyObject * wrap_remote_call(PyObject * func, capnp::Response<capnp::DynamicStruct> &);
PyObject * wrap_dynamic_struct_reader(capnp::Response<capnp::DynamicStruct> &);
::kj::Promise<void> * call_server_method(PyObject * py_server, char * name, capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> & context);
PyObject * wrap_kj_exception(kj::Exception &);
PyObject * wrap_kj_exception_for_reraise(kj::Exception &);
PyObject * get_exception_info(PyObject *, PyObject *, PyObject *);
PyObject * convert_array_pyobject(kj::Array<PyObject *>&);
::kj::Promise<PyObject *> * extract_promise(PyObject *);
::capnp::RemotePromise< ::capnp::DynamicStruct> * extract_remote_promise(PyObject *);
}
class GILAcquire {
public:
GILAcquire() : gstate(PyGILState_Ensure()) {}
@@ -38,11 +26,9 @@ public:
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(capnp::RemotePromise<capnp::DynamicStruct> & promise);
::kj::Promise<PyObject *> convert_to_pypromise(kj::Promise<void> & promise) {
inline ::kj::Promise<PyObject *> convert_to_pypromise(kj::Promise<void> & promise) {
return promise.then([]() {
GILAcquire gil;
Py_INCREF( Py_None );
@@ -55,138 +41,22 @@ template<class T>
return promise.then([](T) { } );
}
void reraise_kj_exception() {
GILAcquire gil;
try {
if (PyErr_Occurred())
; // let the latest Python exn pass through and ignore the current one
else
throw;
}
catch (kj::Exception& exn) {
auto obj = wrap_kj_exception_for_reraise(exn);
PyErr_SetObject((PyObject*)obj->ob_type, obj);
Py_DECREF(obj);
}
catch (const std::exception& exn) {
PyErr_SetString(PyExc_RuntimeError, exn.what());
}
catch (...)
{
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
}
void reraise_kj_exception();
void check_py_error() {
GILAcquire gil;
PyObject * err = PyErr_Occurred();
if(err) {
PyObject * ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
if(ptype == NULL || pvalue == NULL || ptraceback == NULL)
throw kj::Exception(kj::Exception::Type::FAILED, kj::heapString("capabilityHelper.h"), 44, kj::heapString("Unknown error occurred"));
void check_py_error();
PyObject * info = get_exception_info(ptype, pvalue, ptraceback);
kj::Promise<PyObject *> wrapPyFunc(PyObject * func, PyObject * arg);
PyObject * py_filename = PyTuple_GetItem(info, 0);
kj::String filename(kj::heapString(PyBytes_AsString(py_filename)));
kj::Promise<PyObject *> wrapPyFuncNoArg(PyObject * func);
PyObject * py_line = PyTuple_GetItem(info, 1);
int line = PyInt_AsLong(py_line);
kj::Promise<PyObject *> wrapRemoteCall(PyObject * func, capnp::Response<capnp::DynamicStruct> & arg);
PyObject * py_description = PyTuple_GetItem(info, 2);
kj::String description(kj::heapString(PyBytes_AsString(py_description)));
::kj::Promise<PyObject *> then(kj::Promise<PyObject *> & promise, PyObject * func, PyObject * error_func);
::kj::Promise<PyObject *> then(::capnp::RemotePromise< ::capnp::DynamicStruct> & promise, PyObject * func, PyObject * error_func);
Py_DECREF(ptype);
Py_DECREF(pvalue);
Py_DECREF(ptraceback);
Py_DECREF(info);
PyErr_Clear();
::kj::Promise<PyObject *> then(kj::Promise<void> & promise, PyObject * func, PyObject * error_func);
throw kj::Exception(kj::Exception::Type::FAILED, kj::mv(filename), line, kj::mv(description));
}
}
kj::Promise<PyObject *> wrapPyFunc(PyObject * func, PyObject * arg) {
GILAcquire gil;
auto arg_promise = extract_promise(arg);
if(arg_promise == NULL) {
PyObject * result = PyObject_CallFunctionObjArgs(func, arg, NULL);
Py_DECREF(arg);
check_py_error();
auto promise = extract_promise(result);
if(promise != NULL)
return kj::mv(*promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
auto remote_promise = extract_remote_promise(result);
if(remote_promise != NULL)
return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
return result;
}
else {
return arg_promise->then([&](PyObject * new_arg){ return wrapPyFunc(func, new_arg); });// TODO: delete arg_promise?
}
}
kj::Promise<PyObject *> wrapPyFuncNoArg(PyObject * func) {
GILAcquire gil;
PyObject * result = PyObject_CallFunctionObjArgs(func, NULL);
check_py_error();
auto promise = extract_promise(result);
if(promise != NULL)
return kj::mv(*promise);
auto remote_promise = extract_remote_promise(result);
if(remote_promise != NULL)
return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
return result;
}
kj::Promise<PyObject *> wrapRemoteCall(PyObject * func, capnp::Response<capnp::DynamicStruct> & arg) {
GILAcquire gil;
PyObject * ret = wrap_remote_call(func, arg);
check_py_error();
auto promise = extract_promise(ret);
if(promise != NULL)
return kj::mv(*promise);
auto remote_promise = extract_remote_promise(ret);
if(remote_promise != NULL)
return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx
return ret;
}
::kj::Promise<PyObject *> then(kj::Promise<PyObject *> & promise, PyObject * func, PyObject * error_func) {
if(error_func == Py_None)
return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); } );
else
return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); }
, [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } );
}
::kj::Promise<PyObject *> then(::capnp::RemotePromise< ::capnp::DynamicStruct> & promise, PyObject * func, PyObject * error_func) {
if(error_func == Py_None)
return promise.then([func](capnp::Response<capnp::DynamicStruct>&& arg) { return wrapRemoteCall(func, arg); } );
else
return promise.then([func](capnp::Response<capnp::DynamicStruct>&& arg) { return wrapRemoteCall(func, arg); }
, [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } );
}
::kj::Promise<PyObject *> then(kj::Promise<void> & promise, PyObject * func, PyObject * error_func) {
if(error_func == Py_None)
return promise.then([func]() { return wrapPyFuncNoArg(func); } );
else
return promise.then([func]() { return wrapPyFuncNoArg(func); }
, [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } );
}
::kj::Promise<PyObject *> then(kj::Promise<kj::Array<PyObject *> > && promise) {
return promise.then([](kj::Array<PyObject *>&& arg) { return convert_array_pyobject(arg); } );
}
::kj::Promise<PyObject *> then(kj::Promise<kj::Array<PyObject *> > && promise);
class PythonInterfaceDynamicImpl final: public capnp::DynamicCapability::Server {
public:
@@ -204,20 +74,7 @@ public:
}
kj::Promise<void> call(capnp::InterfaceSchema::Method method,
capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context) {
auto methodName = method.getProto().getName();
kj::Promise<void> * promise = call_server_method(py_server, const_cast<char *>(methodName.cStr()), context);
check_py_error();
if(promise == nullptr)
return kj::READY_NOW;
kj::Promise<void> ret(kj::mv(*promise));
delete promise;
return ret;
}
capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context);
};
class PyRefCounter {
@@ -240,13 +97,15 @@ public:
}
};
capnp::DynamicCapability::Client new_client(capnp::InterfaceSchema & schema, PyObject * server) {
inline capnp::DynamicCapability::Client new_client(capnp::InterfaceSchema & schema, PyObject * server) {
return capnp::DynamicCapability::Client(kj::heap<PythonInterfaceDynamicImpl>(schema, server));
}
capnp::DynamicValue::Reader new_server(capnp::InterfaceSchema & schema, PyObject * server) {
inline capnp::DynamicValue::Reader new_server(capnp::InterfaceSchema & schema, PyObject * server) {
return capnp::DynamicValue::Reader(kj::heap<PythonInterfaceDynamicImpl>(schema, server));
}
capnp::Capability::Client server_to_client(capnp::InterfaceSchema & schema, PyObject * server) {
inline capnp::Capability::Client server_to_client(capnp::InterfaceSchema & schema, PyObject * server) {
return kj::heap<PythonInterfaceDynamicImpl>(schema, server);
}
void init_capnp_api();

View File

@@ -25,6 +25,7 @@ cdef extern from "capnp/helpers/capabilityHelper.h":
PyPromise convert_to_pypromise(RemotePromise&)
PyPromise convert_to_pypromise(VoidPromise&)
VoidPromise convert_to_voidpromise(PyPromise&)
void init_capnp_api()
cdef extern from "capnp/helpers/rpcHelper.h":
Capability.Client bootstrapHelper(RpcSystem&)