void c_AsyncGeneratorWaitHandle::enterContextImpl(context_idx_t ctx_idx) { switch (getState()) { case STATE_BLOCKED: // enter child into new context recursively assert(m_child); m_child->enterContext(ctx_idx); setContextIdx(ctx_idx); break; case STATE_SCHEDULED: // reschedule so that we get run setContextIdx(ctx_idx); getContext()->schedule(this); incRefCount(); break; case STATE_RUNNING: { Object e(SystemLib::AllocInvalidOperationExceptionObject( "Detected cross-context dependency cycle. You are trying to depend " "on something that is running you serially.")); throw e; } default: assert(false); } }
void c_RescheduleWaitHandle::exitContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // not in a context being exited assert(getContextIdx() <= ctx_idx); if (getContextIdx() != ctx_idx) { return; } if (UNLIKELY(getState() != STATE_SCHEDULED)) { raise_fatal_error("Invariant violation: encountered unexpected state"); } // move us to the parent context setContextIdx(getContextIdx() - 1); // reschedule if still in a context if (isInContext()) { scheduleInContext(); } // recursively move all wait handles blocked by us getParentChain().exitContext(ctx_idx); }
void c_RescheduleWaitHandle::exitContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // not in a context being exited assert(getContextIdx() <= ctx_idx); if (getContextIdx() != ctx_idx) { return; } if (UNLIKELY(getState() != STATE_SCHEDULED)) { throw FatalErrorException( "Invariant violation: encountered unexpected state"); } // move us to the parent context setContextIdx(getContextIdx() - 1); // reschedule if still in a context if (isInContext()) { getContext()->schedule(this, m_queue, m_priority); } // recursively move all wait handles blocked by us for (auto pwh = getFirstParent(); pwh; pwh = pwh->getNextParent()) { pwh->exitContextBlocked(ctx_idx); } }
void c_AwaitAllWaitHandle::enterContextImpl(context_idx_t ctx_idx) { assert(getState() == STATE_BLOCKED); assert(m_cur >= 0); // recursively import current child m_children[m_cur]->enterContext(ctx_idx); // import ourselves setContextIdx(ctx_idx); // try to import other children auto cur = m_cur; auto child = &m_children[cur]; while (cur > 0) { --cur; --child; if ((*child)->isFinished()) { continue; } try { (*child)->enterContext(ctx_idx); } catch (const Object& cycle_exception) { // exception will be eventually processed by onUnblocked() } } }
void c_GenArrayWaitHandle::enterContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // already in the more specific context? if (LIKELY(getContextIdx() >= ctx_idx)) { return; } assert(getState() == STATE_BLOCKED); // recursively import current child { assert(m_iterPos != ArrayData::invalid_index); TypedValue* current = m_deps->nvGetValueRef(m_iterPos); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitableWaitHandle*>(current->m_data.pobj)); auto child_wh = static_cast<c_WaitableWaitHandle*>(current->m_data.pobj); child_wh->enterContext(ctx_idx); } // import ourselves setContextIdx(ctx_idx); // try to import other children try { for (ssize_t iter_pos = m_deps->iter_advance(m_iterPos); iter_pos != ArrayData::invalid_index; iter_pos = m_deps->iter_advance(iter_pos)) { TypedValue* current = m_deps->nvGetValueRef(iter_pos); if (IS_NULL_TYPE(current->m_type)) { 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->isFinished()) { continue; } assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); child_wh->enterContext(ctx_idx); } } catch (const Object& cycle_exception) { // exception will be eventually processed by onUnblocked() } }
void c_ExternalThreadEventWaitHandle::enterContextImpl(context_idx_t ctx_idx) { assert(getState() == STATE_WAITING); if (isInContext()) { unregisterFromContext(); } setContextIdx(ctx_idx); registerToContext(); }
void c_SessionScopedWaitHandle::enterContextImpl(context_idx_t ctx_idx) { assert(getState() == STATE_WAITING); if (isInContext()) { unregisterFromContext(); } setContextIdx(ctx_idx); registerToContext(); }
void c_RescheduleWaitHandle::initialize(uint32_t queue, int64_t priority) { setState(STATE_SCHEDULED); setContextIdx(AsioSession::Get()->getCurrentContextIdx()); m_queue = queue; m_priority = priority; if (isInContext()) { scheduleInContext(); } }
void c_AsyncGeneratorWaitHandle::initialize(AsyncGenerator* gen, c_WaitableWaitHandle* child) { setState(STATE_BLOCKED); setContextIdx(child->getContextIdx()); m_generator = gen; m_generator->toObject()->incRefCount(); m_child = child; m_child->getParentChain() .addParent(m_blockable, AsioBlockable::Kind::AsyncGeneratorWaitHandle); incRefCount(); }
void c_GenMapWaitHandle::initialize(const Object& exception, c_Map* deps, ssize_t iter_pos, c_WaitableWaitHandle* child) { setState(STATE_BLOCKED); setContextIdx(child->getContextIdx()); m_exception = exception; m_deps = deps; m_iterPos = iter_pos; child->getParentChain() .addParent(m_blockable, AsioBlockable::Kind::GenMapWaitHandle); incRefCount(); }
c_WaitableWaitHandle::c_WaitableWaitHandle(Class* cb) : c_WaitHandle(cb) , m_creator(AsioSession::Get()->getCurrentWaitHandle()) , m_firstParent(nullptr) { setState(STATE_NEW); setContextIdx(AsioSession::Get()->getCurrentContextIdx()); // ref creator if (m_creator) { m_creator->incRefCount(); } }
void c_GenVectorWaitHandle::enterContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // already in the more specific context? if (LIKELY(getContextIdx() >= ctx_idx)) { return; } assert(getState() == STATE_BLOCKED); // recursively import current child { assert(m_iterPos < m_deps->size()); Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitableWaitHandle*>(current->m_data.pobj)); auto child_wh = static_cast<c_WaitableWaitHandle*>(current->m_data.pobj); child_wh->enterContext(ctx_idx); } // import ourselves setContextIdx(ctx_idx); // try to import other children try { for (int64_t iter_pos = m_iterPos + 1; iter_pos < m_deps->size(); ++iter_pos) { Cell* current = tvAssertCell(m_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->isFinished()) { continue; } assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); child_wh->enterContext(ctx_idx); } } catch (const Object& cycle_exception) { // exception will be eventually processed by onUnblocked() } }
void c_ContinuationWaitHandle::enterContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // already in the more specific context? if (LIKELY(getContextIdx() >= ctx_idx)) { return; } switch (getState()) { case STATE_BLOCKED: // enter child into new context recursively assert(dynamic_cast<c_WaitableWaitHandle*>(m_child.get())); static_cast<c_WaitableWaitHandle*>(m_child.get())->enterContext(ctx_idx); setContextIdx(ctx_idx); break; case STATE_SCHEDULED: // reschedule so that we get run setContextIdx(ctx_idx); getContext()->schedule(this); break; case STATE_RUNNING: { Object e(SystemLib::AllocInvalidOperationExceptionObject( "Detected cross-context dependency cycle. You are trying to depend " "on something that is running you serially.")); throw e; } default: assert(false); } }
void c_AwaitAllWaitHandle::initialize(context_idx_t ctx_idx) { setState(STATE_BLOCKED); setContextIdx(ctx_idx); if (UNLIKELY(AsioSession::Get()->hasOnAwaitAllCreate())) { auto vector = req::make<c_Vector>(); for (int32_t idx = m_cap - 1; idx >= 0; --idx) { TypedValue child = make_tv<KindOfObject>(m_children[idx].m_child); vector->add(&child); } AsioSession::Get()->onAwaitAllCreate(this, Variant(std::move(vector))); } incRefCount(); }
void c_SleepWaitHandle::exitContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); assert(getState() == STATE_WAITING); assert(getContextIdx() == ctx_idx); // Move us to the parent context. setContextIdx(getContextIdx() - 1); // Re-register if still in a context. if (isInContext()) { registerToContext(); } // Recursively move all wait handles blocked by us. getParentChain().exitContext(ctx_idx); }
void c_BlockableWaitHandle::exitContextBlocked(context_idx_t ctx_idx) { assert(getState() == STATE_BLOCKED); assert(AsioSession::Get()->getContext(ctx_idx)); // not in a context being exited assert(getContextIdx() <= ctx_idx); if (getContextIdx() != ctx_idx) { return; } // move us to the parent context setContextIdx(getContextIdx() - 1); // recursively move all wait handles blocked by us getParentChain().exitContext(ctx_idx); }
void c_ConditionWaitHandle::initialize(c_WaitableWaitHandle* child) { assert(!child->isFinished()); setState(STATE_BLOCKED); setContextIdx(child->getContextIdx()); m_child = child; m_child->incRefCount(); m_child->getParentChain() .addParent(m_blockable, AsioBlockable::Kind::ConditionWaitHandle); incRefCount(); auto const session = AsioSession::Get(); if (UNLIKELY(session->hasOnConditionCreate())) { session->onConditionCreate(this, child); } }
void c_AsyncFunctionWaitHandle::exitContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { decRefObj(this); return; } // not in a context being exited assert(getContextIdx() <= ctx_idx); if (getContextIdx() != ctx_idx) { decRefObj(this); return; } switch (getState()) { case STATE_BLOCKED: // we were already ran due to duplicit scheduling; the context will be // updated thru exitContext() call on the non-blocked wait handle we // recursively depend on decRefObj(this); break; case STATE_READY: // Recursively move all wait handles blocked by us. getParentChain().exitContext(ctx_idx); // Move us to the parent context. setContextIdx(getContextIdx() - 1); // Reschedule if still in a context. if (isInContext()) { if (isFastResumable()) { getContext()->scheduleFast(this); } else { getContext()->schedule(this); } } else { decRefObj(this); } break; default: assert(false); } }
void c_GenVectorWaitHandle::initialize( const Object& exception, c_Vector* deps, int64_t iter_pos, context_idx_t ctx_idx, c_WaitableWaitHandle* child ) { setState(STATE_BLOCKED); setContextIdx(ctx_idx); m_exception = exception; m_deps = deps; m_iterPos = iter_pos; child->getParentChain() .addParent(m_blockable, AsioBlockable::Kind::GenVectorWaitHandle); incRefCount(); }
void c_AwaitAllWaitHandle::initialize(context_idx_t ctx_idx) { setState(STATE_BLOCKED); setContextIdx(ctx_idx); assert(m_cur >= 0); if (UNLIKELY(AsioSession::Get()->hasOnAwaitAllCreateCallback())) { auto vector = makeSmartPtr<c_Vector>(); for (int32_t idx = m_cur; idx >= 0; --idx) { TypedValue child = make_tv<KindOfObject>(m_children[idx]); vector->add(&child); } AsioSession::Get()->onAwaitAllCreate(this, Variant(std::move(vector))); } blockOnCurrent<false>(); incRefCount(); }
void c_ExternalThreadEventWaitHandle::exitContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); assert(getContextIdx() == ctx_idx); assert(getState() == STATE_WAITING); // Move us to the parent context. setContextIdx(getContextIdx() - 1); // Re-register if still in a context. if (isInContext()) { registerToContext(); } // Recursively move all wait handles blocked by us. for (auto pwh = getFirstParent(); pwh; pwh = pwh->getNextParent()) { pwh->exitContextBlocked(ctx_idx); } }
void c_SetResultToRefWaitHandle::enterContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // already in the more specific context? if (LIKELY(getContextIdx() >= ctx_idx)) { return; } assert(getState() == STATE_BLOCKED); m_child->enterContext(ctx_idx); setContextIdx(ctx_idx); }
void c_ExternalThreadEventWaitHandle::initialize( AsioExternalThreadEvent* event, ObjectData* priv_data ) { auto const session = AsioSession::Get(); setState(STATE_WAITING); setContextIdx(session->getCurrentContextIdx()); m_event = event; m_privData = priv_data; if (isInContext()) { registerToContext(); } if (UNLIKELY(session->hasOnExternalThreadEventCreate())) { session->onExternalThreadEventCreate(this); } }
void c_RescheduleWaitHandle::enterContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // already in the more specific context? if (LIKELY(getContextIdx() >= ctx_idx)) { return; } assert(getState() == STATE_SCHEDULED); setContextIdx(ctx_idx); getContext()->schedule(this, m_queue, m_priority); }
void c_SleepWaitHandle::initialize(int64_t usecs) { auto const session = AsioSession::Get(); setState(STATE_WAITING); setContextIdx(session->getCurrentContextIdx()); m_waketime = AsioSession::TimePoint::clock::now() + std::chrono::microseconds(usecs); incRefCount(); session->enqueueSleepEvent(this); if (isInContext()) { registerToContext(); } if (UNLIKELY(session->hasOnSleepCreate())) { session->onSleepCreate(this); } }
void c_ContinuationWaitHandle::exitContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // not in a context being exited assert(getContextIdx() <= ctx_idx); if (getContextIdx() != ctx_idx) { return; } switch (getState()) { case STATE_BLOCKED: // we were already ran due to duplicit scheduling; the context will be // updated thru exitContext() call on the non-blocked wait handle we // recursively depend on break; case STATE_SCHEDULED: // move us to the parent context setContextIdx(getContextIdx() - 1); // reschedule if still in a context if (isInContext()) { getContext()->schedule(this); } // recursively move all wait handles blocked by us for (auto pwh = getFirstParent(); pwh; pwh = pwh->getNextParent()) { pwh->exitContextBlocked(ctx_idx); } break; default: assert(false); } }
void c_GenVectorWaitHandle::enterContextImpl(context_idx_t ctx_idx) { assert(getState() == STATE_BLOCKED); // recursively import current child { assert(m_iterPos < m_deps->size()); Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(current->m_data.pobj); child_wh->enterContext(ctx_idx); } // import ourselves setContextIdx(ctx_idx); // try to import other children try { for (int64_t iter_pos = m_iterPos + 1; iter_pos < m_deps->size(); ++iter_pos) { Cell* current = tvAssertCell(m_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->isFinished()) { continue; } assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); child_wh->enterContext(ctx_idx); } } catch (const Object& cycle_exception) { // exception will be eventually processed by onUnblocked() } }
void c_ExternalThreadEventWaitHandle::enterContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // already in the more specific context? if (LIKELY(getContextIdx() >= ctx_idx)) { return; } assert(getState() == STATE_WAITING); if (isInContext()) { getContext()->unregisterExternalThreadEvent(m_index); } setContextIdx(ctx_idx); m_index = getContext()->registerExternalThreadEvent(this); }
void c_SetResultToRefWaitHandle::enterContextImpl(context_idx_t ctx_idx) { assert(getState() == STATE_BLOCKED); m_child->enterContext(ctx_idx); setContextIdx(ctx_idx); }
void c_AsyncFunctionWaitHandle::initialize(c_WaitableWaitHandle* child) { setState(STATE_BLOCKED); setContextIdx(child->getContextIdx()); m_children[0].setChild(child); incRefCount(); // account for child->this back-reference }