Skip to content

Commit

Permalink
Add routine to cancel feval on KeyboardInterrupt #27
Browse files Browse the repository at this point in the history
  • Loading branch information
mducle committed Oct 2, 2024
1 parent f861b05 commit d3106dc
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
10 changes: 8 additions & 2 deletions src/libpymcr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,21 @@ namespace libpymcr {
template <class T> T matlab_env::evalloop(matlab::cpplib::FutureResult<T> resAsync) {
std::chrono::duration<int, std::milli> period(1);
std::future_status status = resAsync.wait_for(std::chrono::duration<int, std::milli>(1));
bool error_already_set = false;
while (status != std::future_status::ready) {
status = resAsync.wait_for(period);
// Prints outputs and errors
py::gil_scoped_acquire gil_acquire;
// Check if there is an interrupt on the Python side (needs GIL)
if (!error_already_set && PyErr_CheckSignals() != 0) {
resAsync.cancel();
error_already_set = true;
}
if(_m_output.get()->in_avail() > 0) {
py::gil_scoped_acquire gil_acquire;
py::print(_m_output.get()->str(), py::arg("flush")=true);
py::gil_scoped_release gil_release;
_m_output.get()->str(std::basic_string<char16_t>());
}
py::gil_scoped_release gil_release;
}
return resAsync.get();
}
Expand Down
30 changes: 23 additions & 7 deletions src/matlab_cpp_shared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ uintptr_t cppsharedlib_feval_with_completion(const uint64_t matlabHandle,
size_t nrhs, void(*success)(void*, size_t, bool, matlab::data::impl::ArrayImpl**),
void(*exception)(void*, size_t, bool, size_t, const void*), void* p, void* output,
void* error, void(*write)(void*, const char16_t*, size_t), void(*deleter)(void*));
bool cppsharedlib_cancel_feval_with_completion(uintptr_t taskHandle, bool allowInteruption);

namespace {
typedef std::basic_streambuf<char16_t> StreamBuffer;
Expand All @@ -49,6 +50,23 @@ namespace {

namespace matlab {

namespace cpplib {
template <class T> class FutureResult : public std::future<T> {
public:
FutureResult(std::future<T>&& a_future, uintptr_t a_taskreference)
: future(std::move(a_future)), taskReference(a_taskreference) {};
T get() { return future.get(); }
template<class Rep, class Period>
std::future_status wait_for(const std::chrono::duration<Rep, Period>& rel_time) const {
return future.wait_for(rel_time); }
bool cancel(bool allowInterrupt = true) {
return cppsharedlib_cancel_feval_with_completion(taskReference, allowInterrupt); }
private:
std::future<T> future;
uintptr_t taskReference;
};
}

namespace execution {

class Exception : public std::exception, public matlab::Exception {
Expand Down Expand Up @@ -157,7 +175,7 @@ namespace matlab {
bool scalar,
typename T = typename std::conditional<scalar, matlab::data::Array, std::vector<matlab::data::Array>>::type
>
std::future<T> _feval(const std::u16string &function, const size_t nlhs, const std::vector<matlab::data::Array> &args,
matlab::cpplib::FutureResult<T> _feval(const std::u16string &function, const size_t nlhs, const std::vector<matlab::data::Array> &args,
const SSBuffer &output = SSBuffer(), const SSBuffer &error = SSBuffer()) {
size_t nrhs = args.size();
matlab::data::impl::ArrayImpl** argsImpl = new matlab::data::impl::ArrayImpl*[nrhs];
Expand All @@ -170,7 +188,7 @@ namespace matlab {
std::string utf8functionname = convertUTF16StringToASCIIString(function);
uintptr_t handle = cppsharedlib_feval_with_completion(matlabHandle, utf8functionname.c_str(), nlhs, scalar,
argsImpl, nrhs, &_promise_data, &_promise_exception, p, output_, error_, &_write_buffer, &_delete_buffer);
return p->get_future();
return matlab::cpplib::FutureResult<T>(p->get_future(), handle);
}
std::vector<matlab::data::Array> feval(const std::u16string &function, const size_t nlhs,
const std::vector<matlab::data::Array> &args,
Expand All @@ -187,15 +205,15 @@ namespace matlab {
std::vector<matlab::data::Array> args = {arg};
return _feval<true>(function, 1, args, output, error).get();
}
std::future<std::vector<matlab::data::Array>> fevalAsync(const std::u16string &function, const size_t nlhs,
matlab::cpplib::FutureResult<std::vector<matlab::data::Array>> fevalAsync(const std::u16string &function, const size_t nlhs,
const std::vector<matlab::data::Array> &args, const SSBuffer &output = SSBuffer(), const SSBuffer &error = SSBuffer()) {
return _feval<false>(function, nlhs, args, output, error);
}
std::future<matlab::data::Array> fevalAsync(const std::u16string &function, const std::vector<matlab::data::Array> &args,
matlab::cpplib::FutureResult<matlab::data::Array> fevalAsync(const std::u16string &function, const std::vector<matlab::data::Array> &args,
const SSBuffer &output = SSBuffer(), const SSBuffer &error = SSBuffer()) {
return _feval<true>(function, 1, args, output, error);
}
std::future<matlab::data::Array> fevalAsync(const std::u16string &function, const matlab::data::Array &arg,
matlab::cpplib::FutureResult<matlab::data::Array> fevalAsync(const std::u16string &function, const matlab::data::Array &arg,
const SSBuffer &output = SSBuffer(), const SSBuffer &error = SSBuffer()) {
std::vector<matlab::data::Array> args = {arg};
return _feval<true>(function, 1, args, output, error);
Expand All @@ -209,8 +227,6 @@ namespace matlab {

namespace cpplib {

template<typename T> using FutureResult = std::future<T>;

enum class MATLABApplicationMode {
OUT_OF_PROCESS = 0,
IN_PROCESS = 1
Expand Down

0 comments on commit d3106dc

Please sign in to comment.