void c_AsyncFunctionWaitHandle::initialize(c_WaitableWaitHandle* child) { setState(STATE_BLOCKED); m_child = child; blockOn(child); incRefCount(); }
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; } }
void c_AsyncGeneratorWaitHandle::await(c_WaitableWaitHandle* child) { // Prepare child for establishing dependency. May throw. prepareChild(child); // Set up the dependency. m_child = child; setState(STATE_BLOCKED); blockOn(m_child); }
void c_SetResultToRefWaitHandle::initialize(c_WaitableWaitHandle* child, RefData* ref) { m_child = child; m_ref = ref; m_ref->incRefCount(); try { blockOn(child); } catch (const Object& cycle_exception) { markAsFailed(cycle_exception); } }
void c_AsyncGeneratorWaitHandle::initialize(c_AsyncGenerator* gen, c_WaitableWaitHandle* child) { setState(STATE_BLOCKED); m_generator = gen; m_generator->incRefCount(); m_child = child; blockOn(child); incRefCount(); }
void c_ContinuationWaitHandle::run() { // may happen if scheduled in multiple contexts if (getState() != STATE_SCHEDULED) { return; } try { setState(STATE_RUNNING); do { // iterate continuation if (m_child.isNull()) { // first iteration or null dependency m_continuation->call_next(); } else if (m_child->isSucceeded()) { // child succeeded, pass the result to the continuation m_continuation->call_send(m_child->getResult()); } else if (m_child->isFailed()) { // child failed, raise the exception inside continuation m_continuation->call_raise(m_child->getException()); } else { throw FatalErrorException( "Invariant violation: child neither succeeded nor failed"); } // continuation finished, retrieve result from its m_value if (m_continuation->m_done) { markAsSucceeded(m_continuation->m_value.asTypedValue()); return; } // set up dependency TypedValue* value = m_continuation->m_value.asTypedValue(); if (IS_NULL_TYPE(value->m_type)) { // null dependency m_child = nullptr; } else { c_WaitHandle* child = c_WaitHandle::fromTypedValue(value); if (UNLIKELY(!child)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected yield argument to be an instance of WaitHandle")); throw e; } m_child = child; } } while (m_child.isNull() || m_child->isFinished()); // we are blocked on m_child so it must be WaitableWaitHandle assert(dynamic_cast<c_WaitableWaitHandle*>(m_child.get())); blockOn(static_cast<c_WaitableWaitHandle*>(m_child.get())); } catch (Object exception) { // process exception thrown by generator or blockOn cycle detection markAsFailed(exception); } }
void c_AsyncFunctionWaitHandle::initialize(c_Continuation* continuation, c_WaitableWaitHandle* child, uint16_t depth) { continuation->start(); m_continuation = continuation; m_child = child; m_privData = nullptr; m_depth = depth; blockOn(m_child.get()); }
void c_GenArrayWaitHandle::initialize(CObjRef exception, CArrRef deps, ssize_t iter_pos, c_WaitableWaitHandle* child) { m_exception = exception; m_deps = deps; m_iterPos = iter_pos; try { blockOn(child); } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); m_iterPos = m_deps->iter_advance(m_iterPos); onUnblocked(); } }
void c_GenVectorWaitHandle::initialize(CObjRef exception, c_Vector* deps, int64_t iter_pos, c_WaitableWaitHandle* child) { m_exception = exception; m_deps = deps; m_iterPos = iter_pos; try { blockOn(child); } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); ++m_iterPos; onUnblocked(); } }
void c_AsyncFunctionWaitHandle::await(Offset resumeOffset, c_WaitableWaitHandle* child) { // Prepare child for establishing dependency. May throw. prepareChild(child); // Suspend the async function. resumable()->setResumeAddr(nullptr, resumeOffset); // Set up the dependency. m_child = child; setState(STATE_BLOCKED); blockOn(m_child); }
void c_AsyncFunctionWaitHandle::initialize(c_WaitableWaitHandle* child) { setState(STATE_BLOCKED); m_child = child; m_privData = nullptr; blockOn(child); // needs to be called with non-zero refcnt auto session = AsioSession::Get(); if (UNLIKELY(session->hasOnAsyncFunctionCreateCallback())) { session->onAsyncFunctionCreate(this, child); } }
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); }
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; } }
void c_GenMapWaitHandle::initialize(CObjRef exception, c_Map* deps, ssize_t iter_pos, c_WaitableWaitHandle* child) { m_exception = exception; m_deps = deps; m_iterPos = iter_pos; if (isInContext()) { try { child->enterContext(getContextIdx()); } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); m_iterPos = m_deps->iter_next(m_iterPos); onUnblocked(); return; } } blockOn(child); }
void c_GenVectorWaitHandle::initialize(const Object& exception, c_Vector* deps, int64_t iter_pos, c_WaitableWaitHandle* child) { m_exception = exception; m_deps = deps; m_iterPos = iter_pos; if (isInContext()) { try { child->enterContext(getContextIdx()); } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); ++m_iterPos; onUnblocked(); return; } } blockOn(child); }
void c_AwaitAllWaitHandle::blockOnCurrent() { auto child = m_children[m_cur]; assert(!child->isFinished()); try { if (isInContext()) { child->enterContext(getContextIdx()); } if (checkCycle) { detectCycle(child); } } catch (const Object& cycle_exception) { markAsFailed(cycle_exception); return; } blockOn(child); }
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_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; } }
void c_SetResultToRefWaitHandle::initialize(c_WaitableWaitHandle* child, RefData* ref) { m_child = child; m_ref = ref; m_ref->incRefCount(); blockOn(child); }
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; } }
void c_AsyncFunctionWaitHandle::run() { // may happen if scheduled in multiple contexts if (getState() != STATE_SCHEDULED) { return; } try { setState(STATE_RUNNING); // iterate continuation if (LIKELY(m_child->isSucceeded())) { // child succeeded, pass the result to the continuation m_continuation->call_send(m_child->getResult()); } else if (m_child->isFailed()) { // child failed, raise the exception inside continuation m_continuation->call_raise(m_child->getException()); } else { throw FatalErrorException( "Invariant violation: child neither succeeded nor failed"); } // continuation finished, retrieve result from its m_value if (m_continuation->done()) { markAsSucceeded(*m_continuation->m_value.asCell()); return; } retry: // save child Cell* value = tvAssertCell(m_continuation->m_value.asTypedValue()); assert(dynamic_cast<c_WaitableWaitHandle*>(c_WaitHandle::fromCell(value))); m_child = static_cast<c_WaitableWaitHandle*>(value->m_data.pobj); assert(!m_child->isFinished()); // import child into the current context, detect cross-context cycles try { m_child->enterContext(getContextIdx()); } catch (Object& e) { m_continuation->call_raise(e.get()); goto retry; } // detect cycles if (UNLIKELY(isDescendantOf(m_child.get()))) { Object e(createCycleException(m_child.get())); m_continuation->call_raise(e.get()); goto retry; } // on await callback AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnAsyncFunctionAwaitCallback())) { session->onAsyncFunctionAwait(this, m_child.get()); } // set up dependency blockOn(m_child.get()); } catch (const Object& exception) { // process exception thrown by the async function markAsFailed(exception); } catch (...) { // process C++ exception markAsFailed(AsioSession::Get()->getAbruptInterruptException()); throw; } }