void AsioBlockableChain::unblock() { auto cur = m_firstParent; while (cur) { auto const next = cur->getNextParent(); // May free cur. switch (cur->getKind()) { case Kind::AsyncFunctionWaitHandleNode: getAsyncFunctionWaitHandleNode(cur)->onUnblocked(); break; case Kind::AsyncGeneratorWaitHandle: getAsyncGeneratorWaitHandle(cur)->onUnblocked(); break; case Kind::AwaitAllWaitHandle: getAwaitAllWaitHandle(cur)->onUnblocked(); break; case Kind::ConditionWaitHandle: getConditionWaitHandle(cur)->onUnblocked(); break; case Kind::GenArrayWaitHandle: getGenArrayWaitHandle(cur)->onUnblocked(); break; case Kind::GenMapWaitHandle: getGenMapWaitHandle(cur)->onUnblocked(); break; case Kind::GenVectorWaitHandle: getGenVectorWaitHandle(cur)->onUnblocked(); break; } cur = next; } }
void AsioBlockableChain::exitContext(context_idx_t ctx_idx) { for (auto cur = m_firstParent; cur; cur = cur->getNextParent()) { switch (cur->getKind()) { case Kind::AsyncFunctionWaitHandleNode: exitContextImpl(getAsyncFunctionWaitHandleNode(cur), ctx_idx); break; case Kind::AsyncGeneratorWaitHandle: exitContextImpl(getAsyncGeneratorWaitHandle(cur), ctx_idx); break; case Kind::AwaitAllWaitHandle: exitContextImpl(getAwaitAllWaitHandle(cur), ctx_idx); break; case Kind::ConditionWaitHandle: exitContextImpl(getConditionWaitHandle(cur), ctx_idx); break; case Kind::GenArrayWaitHandle: exitContextImpl(getGenArrayWaitHandle(cur), ctx_idx); break; case Kind::GenMapWaitHandle: exitContextImpl(getGenMapWaitHandle(cur), ctx_idx); break; case Kind::GenVectorWaitHandle: exitContextImpl(getGenVectorWaitHandle(cur), ctx_idx); break; } } }
Array c_WaitableWaitHandle::t_getdependencystack() { Array result = Array::Create(); if (isFinished()) return result; hphp_hash_set<int64_t> visited; auto wait_handle = this; while (wait_handle != nullptr) { result.append(wait_handle); visited.insert(wait_handle->t_getid()); auto context_idx = wait_handle->getContextIdx(); // 1. find parent in the same context auto p = wait_handle->getFirstParent(); while (p) { if ((p->getContextIdx() == context_idx) && visited.find(p->t_getid()) == visited.end()) { wait_handle = p; break; } p = p->getNextParent(); } if (p) continue; // 2. cross the context boundary result.append(null_object); wait_handle = (context_idx > 1) ? AsioSession::Get()->getContext(context_idx - 1)->getCurrent() : nullptr; } return result; }
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); } }
c_WaitableWaitHandle* AsioBlockableChain::firstInContext(context_idx_t ctx_idx) { for (auto cur = m_firstParent; cur; cur = cur->getNextParent()) { auto const wh = cur->getWaitHandle(); if (!wh->isFinished() && wh->getContextIdx() == ctx_idx) { return wh; } } return nullptr; }
Array AsioBlockableChain::toArray() { Array result = Array::Create(); for (auto cur = m_firstParent; cur; cur = cur->getNextParent()) { auto const wh = cur->getWaitHandle(); if (!wh->isFinished()) { result.append(wh); } } return result; }
void AsioBlockableChain::exitContext(context_idx_t ctx_idx) { for (auto cur = m_firstParent; cur; cur = cur->getNextParent()) { switch (cur->getKind()) { case AsioBlockable::Kind::BlockableWaitHandle: cur->getBlockableWaitHandle()->exitContextBlocked(ctx_idx); break; case AsioBlockable::Kind::ConditionWaitHandle: cur->getConditionWaitHandle()->exitContextBlocked(ctx_idx); break; } } }
c_BlockableWaitHandle* AsioBlockableChain::firstInContext(context_idx_t ctx_idx) { for (auto cur = m_firstParent; cur; cur = cur->getNextParent()) { switch (cur->getKind()) { case AsioBlockable::Kind::BlockableWaitHandle: { auto const wh = cur->getBlockableWaitHandle(); if (wh->getContextIdx() == ctx_idx) return wh; break; } case AsioBlockable::Kind::ConditionWaitHandle: // ConditionWaitHandle not supported in legacy dependency stack. break; } } return nullptr; }
Array AsioBlockableChain::toArray() { Array result = Array::Create(); for (auto cur = m_firstParent; cur; cur = cur->getNextParent()) { switch (cur->getKind()) { case AsioBlockable::Kind::BlockableWaitHandle: result.append(cur->getBlockableWaitHandle()); break; case AsioBlockable::Kind::ConditionWaitHandle: result.append(cur->getConditionWaitHandle()); break; } } return result; }
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_SCHEDULED: // Recursively move all wait handles blocked by us. for (auto pwh = getFirstParent(); pwh; pwh = pwh->getNextParent()) { pwh->exitContextBlocked(ctx_idx); } // Move us to the parent context. setContextIdx(getContextIdx() - 1); // Reschedule if still in a context. if (isInContext()) { getContext()->schedule(this); } else { decRefObj(this); } break; default: assert(false); } }
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 AsioBlockableChain::unblock() { auto cur = m_firstParent; while (cur) { auto const next = cur->getNextParent(); // May free cur. switch (cur->getKind()) { case AsioBlockable::Kind::BlockableWaitHandle: dispatchUnblock(cur->getBlockableWaitHandle()); break; case AsioBlockable::Kind::ConditionWaitHandle: cur->getConditionWaitHandle()->onUnblocked(); break; } cur = next; } }
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 for (auto pwh = getFirstParent(); pwh; pwh = pwh->getNextParent()) { pwh->exitContextBlocked(ctx_idx); } }
Array c_WaitableWaitHandle::t_getdependencystack() { Array result = Array::Create(); if (isFinished()) return result; hphp_hash_set<int64_t> visited; auto wait_handle = this; auto session = AsioSession::Get(); while (wait_handle != nullptr) { result.append(wait_handle); visited.insert(wait_handle->t_getid()); auto context_idx = wait_handle->getContextIdx(); // 1. find parent in the same context auto p = wait_handle->getFirstParent(); while (p) { if ((p->getContextIdx() == context_idx) && visited.find(p->t_getid()) == visited.end()) { wait_handle = p; break; } p = p->getNextParent(); } if (p) continue; // 2. cross the context boundary auto context = session->getContext(context_idx); if (!context) { break; } wait_handle = c_ResumableWaitHandle::getRunning(context->getSavedFP()); auto target_context_idx = wait_handle ? wait_handle->getContextIdx() : 0; while (context_idx > target_context_idx) { --context_idx; result.append(null_object); } } return result; }
void Comparator::check( spec_reader::Specification& spec, file_reader::FileReader& file, report_generator::Report& report ) { ShPtrSpecNode node = spec.getFirstNode(); ShPtrElement element( new basic_element::Element( node ) ); element_checker::Checker checker; size_t size = checker.getSize( element ); char buffer1[ size ]; if( ! file.readData( buffer1, size ) ) throw std::runtime_error( "[comparator] End of file, cannot read data" ); element->set( buffer1, size ); checker.check( element ); LOG_TRACE( "[comparator] checked:" << element->_id << " = " << element->_dispValue << " (" << statusMap.at( element->_status ) << ")" ); std::shared_ptr< basic_element::Element > parent; parent = getNextParent( element, node ); report.add( element ); report.print( element ); while( ( node = element->next() ) != nullptr ) { // LOG_FATAL( node->getId() ); ShPtrElement previous = element; if( skipElementCheck( previous ) ) { LOG_TRACE( "[comparator] Go back in file (" << size << " bytes)" ); file.goBack( size ); previous = element->getPrevious(); } element = std::make_shared< basic_element::Element >( node, previous, parent ); size = checker.getSize( element ); if( size > ( file.getLength() - file.getPosition() ) && ( isInUnorderedGroup( element ) || element->_isOptional ) ) { LOG_TRACE( "[comparator] Critical remaining file data size: " << size << "/" << file.getLength() - file.getPosition() ); size = file.getLength() - file.getPosition(); if( size == 0 ) break; } char buffer[ size ]; if( ! file.readData( buffer, size ) ) throw std::runtime_error( "[comparator] End of file, cannot read data" ); element->set( buffer, size ); checker.check( element ); LOG_TRACE( "[comparator] checked: " << element->_id << " = " << element->_dispValue << " (" << statusMap.at( element->_status ) << ") @ " << element << " << Previous: " << previous << " << Parent: " ); // LOG_COLOR( common::details::kColorMagenta, "[comparator] checked: " << element->_id << " = " << element->_dispValue << " (" << statusMap.at( element->_status ) << ") @ " << element << " << Previous: " << previous << " << Parent: " << parent << std::endl ); // if( ! skipElementCheck( element ) && parent != nullptr ) // parent->_childrenSize += element->_size; updateParentSize( element ); checkGroupSize( element, file ); report.add( element ); report.update( parent ); parent = getNextParent( element, node ); if( parent != nullptr ) { LOG_TRACE( "[comparator] next parent: id = " << parent->_id ); } else LOG_TRACE( "[comparator] next parent: null" ); report.print( element ); } if( ! file.isEndOfFile() ) LOG_WARNING( "Did not reach the end of file, remaining " << file.getLength() - file.getPosition() << " bytes." ); }