bool getResult(TLTypePtr output) { if (isSucceeded()) { m_layer->processReply(this, output); } return isSucceeded() && output->isValid(); }
Object c_GenMapWaitHandle::ti_create(const Variant& dependencies) { if (UNLIKELY(!dependencies.isObject() || dependencies.getObjectData()->getCollectionType() != Collection::MapType)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Map")); throw e; } assert(dependencies.getObjectData()->instanceof(c_Map::classof())); auto deps = p_Map::attach(c_Map::Clone(dependencies.getObjectData())); for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); if (UNLIKELY(!c_WaitHandle::fromCell(current))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be a map of WaitHandle instances")); throw e; } } Object exception; for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto k = deps->iter_key(iter_pos); deps->set(k.asCell(), &child->getResult()); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); p_GenMapWaitHandle my_wh = NEWOBJ(c_GenMapWaitHandle)(); my_wh->initialize(exception, deps.get(), iter_pos, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenMapCreateCallback())) { session->onGenMapCreate(my_wh.get(), dependencies); } return my_wh; } } if (exception.isNull()) { return Object::attach(c_StaticWaitHandle::CreateSucceeded( make_tv<KindOfObject>(deps.detach()))); } else { return Object::attach(c_StaticWaitHandle::CreateFailed(exception.detach())); } }
void c_GenVectorWaitHandle::onUnblocked() { for (; m_iterPos < m_deps->size(); ++m_iterPos) { Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } if (m_exception.isNull()) { setResult(make_tv<KindOfObject>(m_deps.get())); m_deps = nullptr; } else { setException(m_exception.get()); m_exception = nullptr; m_deps = nullptr; } }
Object c_GenArrayWaitHandle::ti_create(const char* cls, CArrRef dependencies) { Array deps = dependencies->copy(); for (ssize_t iter_pos = deps->iter_begin(); iter_pos != ArrayData::invalid_index; iter_pos = deps->iter_advance(iter_pos)) { TypedValue* current = deps->nvGetValueRef(iter_pos); if (UNLIKELY(current->m_type == KindOfRef)) { tvUnbox(current); } if (!c_WaitHandle::fromTypedValue(current) && !IS_NULL_TYPE(current->m_type)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an array of WaitHandle instances")); throw e; } } Object exception; for (ssize_t iter_pos = deps->iter_begin(); iter_pos != ArrayData::invalid_index; iter_pos = deps->iter_advance(iter_pos)) { TypedValue* current = deps->nvGetValueRef(iter_pos); if (IS_NULL_TYPE(current->m_type)) { // {uninit,null} yields null tvWriteNull(current); continue; } assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { tvSetIgnoreRef(child->getResult(), current); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); c_GenArrayWaitHandle* my_wh = NEWOBJ(c_GenArrayWaitHandle)(); my_wh->initialize(exception, deps, iter_pos, child_wh); return my_wh; } } if (exception.isNull()) { TypedValue tv; tv.m_type = KindOfArray; tv.m_data.parr = deps.get(); return c_StaticResultWaitHandle::Create(&tv); } else { return c_StaticExceptionWaitHandle::Create(exception.get()); } }
String c_WaitHandle::t_getname() { if (isSucceeded()) { return s_result; } else if (isFailed()) { return s_exception; } assert(instanceof(c_WaitableWaitHandle::classof())); return static_cast<c_WaitableWaitHandle*>(this)->getName(); }
Object c_GenVectorWaitHandle::ti_create(const Variant& dependencies) { if (UNLIKELY(!dependencies.isObject() || dependencies.getObjectData()->getCollectionType() != Collection::VectorType)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Vector")); throw e; } assert(dependencies.getObjectData()->instanceof(c_Vector::classof())); auto deps = SmartObject<c_Vector>::attach( c_Vector::Clone(dependencies.getObjectData())); for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { Cell* current = deps->at(iter_pos); if (UNLIKELY(!c_WaitHandle::fromCell(current))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be a vector of WaitHandle instances")); throw e; } } Object exception; for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { auto current = tvAssertCell(deps->at(iter_pos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto result = child->getResult(); deps->set(iter_pos, &result); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); SmartObject<c_GenVectorWaitHandle> my_wh(newobj<c_GenVectorWaitHandle>()); my_wh->initialize(exception, deps.get(), iter_pos, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenVectorCreateCallback())) { session->onGenVectorCreate(my_wh.get(), dependencies); } return my_wh; } } if (exception.isNull()) { return Object::attach(c_StaticWaitHandle::CreateSucceeded( make_tv<KindOfObject>(deps.detach()))); } else { return Object::attach(c_StaticWaitHandle::CreateFailed(exception.detach())); } }
Variant c_WaitHandle::result() { assert(isFinished()); if (LIKELY(isSucceeded())) { // succeeded? return result return cellAsCVarRef(getResult()); } else { // failed? throw exception throw Object{getException()}; } }
Object c_SetResultToRefWaitHandle::ti_create(CObjRef wait_handle, VRefParam ref) { TypedValue* var_or_cell = ref->asTypedValue(); if (wait_handle.isNull()) { tvSetNull(*var_or_cell); return wait_handle; } if (!wait_handle.get()->getAttribute(ObjectData::IsWaitHandle)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected wait_handle to be an instance of WaitHandle or null")); throw e; } auto wh = static_cast<c_WaitHandle*>(wait_handle.get()); // succeeded? set result to ref and give back succeeded wait handle if (wh->isSucceeded()) { tvSet(wh->getResult(), *var_or_cell); return wh; } // failed? reset ref and give back failed wait handle if (wh->isFailed()) { tvSetNull(*var_or_cell); return wh; } // it's still running so it must be WaitableWaitHandle auto child = static_cast<c_WaitableWaitHandle*>(wh); // import child into the current context, detect cross-context cycles auto session = AsioSession::Get(); if (session->isInContext()) { child->enterContext(session->getCurrentContextIdx()); } // make sure the reference is properly boxed so that we can store cell pointer if (UNLIKELY(var_or_cell->m_type != KindOfRef)) { tvBox(var_or_cell); } p_SetResultToRefWaitHandle my_wh = NEWOBJ(c_SetResultToRefWaitHandle)(); my_wh->initialize(child, var_or_cell->m_data.pref); if (UNLIKELY(session->hasOnSetResultToRefCreateCallback())) { session->onSetResultToRefCreate(my_wh.get(), child); } return my_wh; }
Object c_GenVectorWaitHandle::ti_create(CVarRef dependencies) { if (UNLIKELY(!dependencies.instanceof(c_Vector::s_cls))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Vector")); throw e; } assert(dynamic_cast<c_Vector*>(dependencies.getObjectData())); p_Vector deps = static_cast<c_Vector*>(dependencies.getObjectData())->clone(); for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { Cell* current = deps->at(iter_pos); if (UNLIKELY(!c_WaitHandle::fromCell(current))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be a vector of WaitHandle instances")); throw e; } } Object exception; for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { Cell* current = tvAssertCell(deps->at(iter_pos)); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); p_GenVectorWaitHandle my_wh = NEWOBJ(c_GenVectorWaitHandle)(); my_wh->initialize(exception, deps.get(), iter_pos, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenVectorCreateCallback())) { session->onGenVectorCreate(my_wh.get(), dependencies); } return my_wh; } } if (exception.isNull()) { return c_StaticResultWaitHandle::Create(make_tv<KindOfObject>(deps.get())); } else { return c_StaticExceptionWaitHandle::Create(exception.get()); } }
void c_AsyncFunctionWaitHandle::resume() { auto const child = m_children[0].getChild(); assert(getState() == STATE_READY); assert(child->isFinished()); setState(STATE_RUNNING); if (LIKELY(child->isSucceeded())) { // child succeeded, pass the result to the async function g_context->resumeAsyncFunc(resumable(), child, child->getResult()); } else { // child failed, raise the exception inside the async function g_context->resumeAsyncFuncThrow(resumable(), child, child->getException()); } }
void c_GenMapWaitHandle::onUnblocked() { assert(getState() == STATE_BLOCKED); for (; m_deps->iter_valid(m_iterPos); m_iterPos = m_deps->iter_next(m_iterPos)) { auto* current = tvAssertCell(m_deps->iter_value(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto k = m_deps->iter_key(m_iterPos); m_deps->set(k.asCell(), &child->getResult()); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { if (isInContext()) { child_wh->enterContext(getContextIdx()); } detectCycle(child_wh); blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } auto const parentChain = getFirstParent(); if (m_exception.isNull()) { setState(STATE_SUCCEEDED); tvWriteObject(m_deps.get(), &m_resultOrException); } else { setState(STATE_FAILED); tvWriteObject(m_exception.get(), &m_resultOrException); m_exception = nullptr; } m_deps = nullptr; UnblockChain(parentChain); decRefObj(this); }
Variant c_WaitHandle::t_join() { if (!isFinished()) { // run the full blown machinery assert(instanceof(c_WaitableWaitHandle::classof())); static_cast<c_WaitableWaitHandle*>(this)->join(); } assert(isFinished()); if (LIKELY(isSucceeded())) { // succeeded? return result return cellAsCVarRef(getResult()); } else { // failed? throw exception throw Object{getException()}; } }
void c_GenArrayWaitHandle::onUnblocked() { for (; m_iterPos != ArrayData::invalid_index; m_iterPos = m_deps->iter_advance(m_iterPos)) { TypedValue* current = m_deps->nvGetValueRef(m_iterPos); if (IS_NULL_TYPE(current->m_type)) { // {uninit,null} yields null tvWriteNull(current); continue; } assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { tvSetIgnoreRef(child->getResult(), current); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } if (m_exception.isNull()) { TypedValue result; result.m_type = KindOfArray; result.m_data.parr = m_deps.get(); setResult(&result); m_deps = nullptr; } else { setException(m_exception.get()); m_exception = nullptr; m_deps = nullptr; } }
Variant c_WaitHandle::t_join() { if (!isFinished()) { // run the full blown machinery assert(dynamic_cast<c_WaitableWaitHandle*>(this)); static_cast<c_WaitableWaitHandle*>(this)->join(); } assert(isFinished()); if (LIKELY(isSucceeded())) { // succeeded? return result return tvAsCVarRef(getResult()); } else { // failed? throw exception Object e(getException()); throw e; } }
void c_GenVectorWaitHandle::onUnblocked() { assert(getState() == STATE_BLOCKED); for (; m_iterPos < m_deps->size(); ++m_iterPos) { Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto result = child->getResult(); m_deps->set(m_iterPos, &result); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { detectCycle(child_wh); child_wh->getParentChain() .addParent(m_blockable, AsioBlockable::Kind::GenVectorWaitHandle); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } auto parentChain = getParentChain(); if (m_exception.isNull()) { setState(STATE_SUCCEEDED); tvWriteObject(m_deps.get(), &m_resultOrException); } else { setState(STATE_FAILED); tvWriteObject(m_exception.get(), &m_resultOrException); m_exception = nullptr; } m_deps = nullptr; parentChain.unblock(); decRefObj(this); }
void c_GenVectorWaitHandle::onUnblocked() { assert(getState() == STATE_BLOCKED); for (; m_iterPos < m_deps->size(); ++m_iterPos) { Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { if (isInContext()) { child_wh->enterContext(getContextIdx()); } detectCycle(child_wh); blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } if (m_exception.isNull()) { setState(STATE_SUCCEEDED); tvWriteObject(m_deps.get(), &m_resultOrException); } else { setState(STATE_FAILED); tvWriteObject(m_exception.get(), &m_resultOrException); m_exception = nullptr; } m_deps = nullptr; done(); }
void c_AsyncFunctionWaitHandle::resume() { // may happen if scheduled in multiple contexts if (getState() != STATE_SCHEDULED) { decRefObj(this); return; } auto const child = m_children[0].getChild(); assert(getState() == STATE_SCHEDULED); assert(child->isFinished()); setState(STATE_RUNNING); if (LIKELY(child->isSucceeded())) { // child succeeded, pass the result to the async function g_context->resumeAsyncFunc(resumable(), child, child->getResult()); } else { // child failed, raise the exception inside the async function g_context->resumeAsyncFuncThrow(resumable(), child, child->getException()); } }
void c_GenMapWaitHandle::onUnblocked() { for (; m_deps->iter_valid(m_iterPos); m_iterPos = m_deps->iter_next(m_iterPos)) { Cell* current = tvAssertCell(m_deps->iter_value(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { if (isInContext()) { child_wh->enterContext(getContextIdx()); } detectCycle(child_wh); blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } if (m_exception.isNull()) { setResult(make_tv<KindOfObject>(m_deps.get())); m_deps = nullptr; } else { setException(m_exception.get()); m_exception = nullptr; m_deps = nullptr; } }
bool c_WaitHandle::t_issucceeded() { return isSucceeded(); }
void c_AsyncFunctionWaitHandle::run() { // may happen if scheduled in multiple contexts if (getState() != STATE_SCHEDULED) { return; } try { setState(STATE_RUNNING); // resume async function if (LIKELY(m_child->isSucceeded())) { // child succeeded, pass the result to the async function g_context->resumeAsyncFunc(resumable(), m_child, m_child->getResult()); } else if (m_child->isFailed()) { // child failed, raise the exception inside the async function g_context->resumeAsyncFuncThrow(resumable(), m_child, m_child->getException()); } else { throw FatalErrorException( "Invariant violation: child neither succeeded nor failed"); } retry: // async function reached RetC, which already set m_resultOrException if (isSucceeded()) { m_child = nullptr; markAsSucceeded(); return; } // async function reached AsyncSuspend, which already set m_child assert(!m_child->isFinished()); assert(m_child->instanceof(c_WaitableWaitHandle::classof())); // import child into the current context, detect cross-context cycles try { child()->enterContext(getContextIdx()); } catch (Object& e) { g_context->resumeAsyncFuncThrow(resumable(), m_child, e.get()); goto retry; } // detect cycles if (UNLIKELY(isDescendantOf(child()))) { Object e(createCycleException(child())); g_context->resumeAsyncFuncThrow(resumable(), m_child, e.get()); goto retry; } // on await callback AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnAsyncFunctionAwaitCallback())) { session->onAsyncFunctionAwait(this, m_child); } // set up dependency setState(STATE_BLOCKED); blockOn(child()); } catch (const Object& exception) { // process exception thrown by the async function m_child = nullptr; markAsFailed(exception); } catch (...) { // process C++ exception m_child = nullptr; markAsFailed(AsioSession::Get()->getAbruptInterruptException()); throw; } }
Object c_GenMapWaitHandle::ti_create(const Variant& dependencies) { ObjectData* obj; if (UNLIKELY(!dependencies.isObject() || !(obj = dependencies.getObjectData())->isCollection() || obj->collectionType() != CollectionType::Map)) { SystemLib::throwInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Map"); } assertx(obj->collectionType() == CollectionType::Map); auto deps = req::ptr<c_Map>::attach(c_Map::Clone(obj)); auto ctx_idx = std::numeric_limits<context_idx_t>::max(); for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); auto const child = c_WaitHandle::fromCell(current); if (UNLIKELY(!child)) { SystemLib::throwInvalidArgumentExceptionObject( "Expected dependencies to be a map of WaitHandle instances"); } if (!child->isFinished()) { ctx_idx = std::min( ctx_idx, static_cast<c_WaitableWaitHandle*>(child)->getContextIdx() ); } } Object exception; for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto k = deps->iter_key(iter_pos); auto result = child->getResult(); deps->set(k.asCell(), &result); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); auto my_wh = req::make<c_GenMapWaitHandle>(); my_wh->initialize(exception, deps.get(), iter_pos, ctx_idx, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenMapCreate())) { session->onGenMapCreate(my_wh.get(), dependencies); } return Object(std::move(my_wh)); } } if (exception.isNull()) { return Object::attach(c_StaticWaitHandle::CreateSucceeded( make_tv<KindOfObject>(deps.detach()))); } else { return Object::attach(c_StaticWaitHandle::CreateFailed(exception.detach())); } }