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; } }