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_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() } }
// throws on context depth level overflows and cross-context cycles void c_WaitableWaitHandle::join() { JIT::EagerVMRegAnchor _; AsioSession* session = AsioSession::Get(); assert(!isFinished()); assert(!session->isInContext() || session->getCurrentContext()->isRunning()); if (UNLIKELY(session->hasOnJoinCallback())) { session->onJoin(this); } // enter new asio context and set up guard that will exit once we are done session->enterContext(); auto exit_guard = folly::makeGuard([&] { session->exitContext(); }); assert(session->isInContext()); assert(!session->getCurrentContext()->isRunning()); // import this wait handle to the newly created context // throws if cross-context cycle found enterContext(session->getCurrentContextIdx()); // run queues until we are finished session->getCurrentContext()->runUntil(this); assert(isFinished()); }
// throws on context depth level overflows and cross-context cycles void c_WaitableWaitHandle::join() { AsioSession* session = AsioSession::Get(); assert(!isFinished()); assert(!session->isInContext() || session->getCurrentContext()->isRunning()); if (UNLIKELY(session->hasOnJoinCallback())) { session->onJoin(this); } // enter new asio context and set up guard that will exit once we are done session->enterContext(); assert(session->isInContext()); assert(!session->getCurrentContext()->isRunning()); try { // import this wait handle to the newly created context // throws if cross-context cycle found enterContext(session->getCurrentContextIdx()); // run queues until we are finished session->getCurrentContext()->runUntil(this); } catch (const Object& exception) { // recover from PHP exceptions; HPHP internal exceptions are deliberately // ignored as there is no easy way to recover from them session->exitContext(); throw; } session->exitContext(); assert(isFinished()); }
void c_AsyncFunctionWaitHandle::Create(c_Continuation* continuation) { assert(continuation); assert(continuation->m_label > 0); assert(continuation->m_waitHandle.isNull()); AsioSession* session = AsioSession::Get(); uint16_t depth = session->getCurrentWaitHandleDepth(); if (UNLIKELY(depth >= MAX_DEPTH)) { Object e(SystemLib::AllocInvalidOperationExceptionObject( "Asio stack overflow")); throw e; } Cell* value = tvAssertCell(continuation->m_value.asTypedValue()); assert(dynamic_cast<c_WaitableWaitHandle*>(c_WaitHandle::fromCell(value))); auto child = static_cast<c_WaitableWaitHandle*>(value->m_data.pobj); assert(!child->isFinished()); // import child into the current context, detect cross-context cycles if (session->isInContext()) { child->enterContext(session->getCurrentContextIdx()); } continuation->m_waitHandle = NEWOBJ(c_AsyncFunctionWaitHandle)(); continuation->m_waitHandle->initialize(continuation, child, depth + 1); // needs to be called after continuation->m_waitHandle is set if (UNLIKELY(session->hasOnAsyncFunctionCreateCallback())) { session->onAsyncFunctionCreate(continuation->m_waitHandle.get()); } }
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() } }
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; }
CSSM_RETURN CSSMAPI CSSM_DeleteContext (CSSM_CC_HANDLE CCHandle) { BEGIN_API HandleContext &context = enterContext(CCHandle); StLock<CountingMutex, &CountingMutex::enter, &CountingMutex::exit> _(context.attachment, true); // ignore error return from CSP event notify (can't decline deletion) context.validateChange(CSSM_CONTEXT_EVENT_DELETE); context.destroy(&context, context.attachment); END_API(CSSM) }
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_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; } }