c_WaitableWaitHandle* AsioContext::getBlamedWaitHandle() { // first let's try to find wait handle, responsible for wakeup auto session = AsioSession::Get(); auto ete_queue = session->getExternalThreadEventQueue(); c_ExternalThreadEventWaitHandle* ewh = ete_queue->lastReceived(); if (ewh != nullptr && ewh->getContextIdx() == session->getCurrentContextIdx()) { return ewh; } // may return cancelled wait handle, which no longer has contextIdx c_SleepWaitHandle* swh = session->nextSleepEvent(); if (swh != nullptr && !swh->isFinished() && swh->getContextIdx() == session->getCurrentContextIdx() && swh->getWakeTime() <= AsioSession::TimePoint::clock::now()) { return swh; } // not found? let's find a wait handle from current context to blame if (!m_externalThreadEvents.empty()) { return m_externalThreadEvents[0]; } if (!m_sleepEvents.empty()) { return m_sleepEvents[0]; } return nullptr; }
void AsioSession::enterContext(ActRec* savedFP) { if (UNLIKELY(getCurrentContextIdx() >= MAX_CONTEXT_DEPTH)) { SystemLib::throwInvalidOperationExceptionObject( "Unable to enter asio context: too many contexts open"); } m_contexts.push_back(req::make_raw<AsioContext>(savedFP)); assert(static_cast<context_idx_t>(m_contexts.size()) == m_contexts.size()); assert(isInContext()); }
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; }
void AsioSession::enterContext() { assert(!isInContext() || getCurrentContext()->isRunning()); if (UNLIKELY(getCurrentContextIdx() >= MAX_CONTEXT_DEPTH)) { Object e(SystemLib::AllocInvalidOperationExceptionObject( "Unable to enter asio context: too many contexts open")); throw e; } m_contexts.push_back(new AsioContext()); assert(static_cast<context_idx_t>(m_contexts.size()) == m_contexts.size()); assert(isInContext()); assert(!getCurrentContext()->isRunning()); }
Object f_asio_get_running_in_context(int ctx_idx) { auto session = AsioSession::Get(); if (ctx_idx <= 0) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected ctx_idx to be a positive integer")); throw e; } if (ctx_idx > session->getCurrentContextIdx()) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected ctx_idx to be less than or equal to the current context index")); throw e; } assert(session->getContext(ctx_idx)); assert(session->getContext(ctx_idx)->isRunning()); return session->getContext(ctx_idx)->getCurrent(); }
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_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); } }