// // Copyright (c) ZeroC, Inc. All rights reserved. // #include "ice.h" #include "Future.h" #include "Util.h" using namespace std; using namespace IceMatlab; void IceMatlab::Future::token(function t) { lock_guard lock(_mutex); if(stateImpl() != State::Finished) { _token = std::move(t); } } bool IceMatlab::Future::waitForState(State state, double timeout) { unique_lock lock(_mutex); if(timeout < 0) { _cond.wait(lock, [this, state]{ return state == this->stateImpl(); }); return !_exception; } else { auto now = chrono::system_clock::now(); auto stop = now + chrono::milliseconds(static_cast(timeout * 1000)); bool b = _cond.wait_until(lock, stop, [this, state]{ return state == this->stateImpl(); }); return b && !_exception; } } bool IceMatlab::Future::waitForState(const string& s, double timeout) { State state; if(s == "running") { state = State::Running; } else if(s == "sent") { state = State::Sent; } else if(s == "finished") { state = State::Finished; } else { throw std::invalid_argument("state must be one of 'running', 'sent' or 'finished'"); } return waitForState(state, timeout); } void IceMatlab::Future::exception(exception_ptr e) { lock_guard lock(_mutex); _token = nullptr; _exception = e; _cond.notify_all(); } exception_ptr IceMatlab::Future::getException() const { lock_guard lock(const_cast(_mutex)); return _exception; } void IceMatlab::Future::sent() { } string IceMatlab::Future::state() const { lock_guard lock(const_cast(_mutex)); string st; switch(stateImpl()) { case State::Running: st = "running"; break; case State::Sent: st = "sent"; break; case State::Finished: st = "finished"; break; } return st; } void IceMatlab::Future::cancel() { lock_guard lock(_mutex); if(_token) { _token(); _token = nullptr; } } // // SimpleFuture // IceMatlab::SimpleFuture::SimpleFuture() : _state(State::Running) { } void IceMatlab::SimpleFuture::done() { lock_guard lock(_mutex); _state = State::Finished; _cond.notify_all(); } IceMatlab::Future::State IceMatlab::SimpleFuture::stateImpl() const { if(_exception) { return State::Finished; } else { return _state; } } extern "C" { mxArray* Ice_SimpleFuture_unref(void* self) { delete reinterpret_cast*>(self); return 0; } mxArray* Ice_SimpleFuture_wait(void* self) { bool b = deref(self)->waitForState("finished", -1); return createResultValue(createBool(b)); } mxArray* Ice_SimpleFuture_waitState(void* self, mxArray* st, double timeout) { try { string s = getStringFromUTF16(st); bool b = deref(self)->waitForState(s, timeout); return createResultValue(createBool(b)); } catch(const std::exception& ex) { return createResultException(convertException(ex)); } } mxArray* Ice_SimpleFuture_state(void* self) { return createResultValue(createStringFromUTF8(deref(self)->state())); } mxArray* Ice_SimpleFuture_cancel(void* self) { deref(self)->cancel(); return 0; } mxArray* Ice_SimpleFuture_check(void* self) { auto f = deref(self); if(!f->waitForState(Future::State::Finished, -1)) { assert(f->getException()); try { rethrow_exception(f->getException()); } catch(const std::exception& ex) { // // The C++ object won't be used after this. // delete reinterpret_cast*>(self); return convertException(ex); } } // // The C++ object won't be used after this. // delete reinterpret_cast*>(self); return 0; } }