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 MemFile::unzip() { assertx(m_len != -1); assertx(!m_malloced); assertx(m_cursor == 0); int len = m_len; char *data = gzdecode(m_data, len); if (data == nullptr) { raise_fatal_error((std::string("cannot unzip mem stream: ") + getName()).c_str()); } m_data = data; m_malloced = true; m_len = len; }
String c_AsyncFunctionWaitHandle::getName() { switch (getState()) { case STATE_BLOCKED: case STATE_READY: case STATE_RUNNING: { auto func = actRec()->func(); if (!actRec()->getThisOrClass() || func->cls()->attrs() & AttrNoOverride) { auto name = func->fullName(); if (func->isClosureBody()) { const char* p = strchr(name->data(), ':'); if (p) { return concat(String(name->data(), p + 1 - name->data(), CopyString), s__closure_); } else { return s__closure_; } } return String{const_cast<StringData*>(name)}; } String funcName; if (actRec()->func()->isClosureBody()) { // Can we do better than this? funcName = s__closure_; } else { funcName = const_cast<StringData*>(actRec()->func()->name()); } String clsName; if (actRec()->hasThis()) { clsName = const_cast<StringData*>(actRec()->getThis()-> getVMClass()->name()); } else if (actRec()->hasClass()) { clsName = const_cast<StringData*>(actRec()->getClass()->name()); } else { return funcName; } return concat3(clsName, "::", funcName); } default: raise_fatal_error( "Invariant violation: encountered unexpected state"); } }
String c_AsyncFunctionWaitHandle::getName() { switch (getState()) { case STATE_BLOCKED: case STATE_READY: case STATE_RUNNING: { auto func = actRec()->func(); if (!func->cls() || func->cls()->attrs() & AttrNoOverride || actRec()->localsDecRefd()) { auto name = func->fullName(); if (func->isClosureBody()) { const char* p = strchr(name->data(), ':'); if (p) { return concat(String(name->data(), p + 1 - name->data(), CopyString), s__closure_); } else { return s__closure_; } } return String{const_cast<StringData*>(name)}; } auto const cls = actRec()->hasThis() ? actRec()->getThis()->getVMClass() : actRec()->getClass(); if (cls == func->cls() && !func->isClosureBody()) { return String{const_cast<StringData*>(func->fullName())}; } StrNR funcName(func->isClosureBody() ? s__closure_.get() : func->name()); return concat3(cls->nameStr(), "::", funcName); } default: raise_fatal_error( "Invariant violation: encountered unexpected state"); } }
static void create_miter_for_walk(folly::Optional<MArrayIter>& miter, Variant& var) { if (!var.is(KindOfObject)) { miter.emplace(var.asRef()->m_data.pref); return; } auto const odata = var.getObjectData(); if (odata->isCollection()) { raise_error("Collection elements cannot be taken by reference"); } bool isIterable; Object iterable = odata->iterableObject(isIterable); if (isIterable) { raise_fatal_error("An iterator cannot be used with " "foreach by reference"); } Array properties = iterable->o_toIterArray(null_string, ObjectData::CreateRefs); miter.emplace(properties.detach()); }
bool MemFile::open(const String& filename, const String& mode) { assertx(m_len == -1); // mem files are read-only const char* mode_str = mode.c_str(); if (strchr(mode_str, '+') || strchr(mode_str, 'a') || strchr(mode_str, 'w')) { return false; } int len = INT_MIN; bool compressed = false; char *data = StaticContentCache::TheFileCache->read(filename.c_str(), len, compressed); // -1: PHP file; -2: directory if (len != INT_MIN && len != -1 && len != -2) { assertx(len >= 0); if (compressed) { assertx(RuntimeOption::EnableOnDemandUncompress); data = gzdecode(data, len); if (data == nullptr) { raise_fatal_error("cannot unzip compressed data"); } m_data = data; m_malloced = true; m_len = len; return true; } setName(filename.toCppString()); m_data = data; m_len = len; return true; } if (len != INT_MIN) { Logger::Error("Cannot open a PHP file or a directory as MemFile: %s", filename.c_str()); } return false; }
bool MemFile::flush() { raise_fatal_error((std::string("cannot flush a mem stream: ") + getName()).c_str()); }
int64_t MemFile::writeImpl(const char* /*buffer*/, int64_t /*length*/) { raise_fatal_error((std::string("cannot write a mem stream: ") + getName()).c_str()); }
ArrayData* GlobalsArray::CopyStatic(const ArrayData*) { raise_fatal_error("GlobalsArray::copyStatic " "not implemented."); }
ArrayData* GlobalsArray::CopyWithStrongIterators(const ArrayData* ad) { raise_fatal_error( "Unimplemented ArrayData::copyWithStrongIterators"); }
const String& ResourceData::o_getClassNameHook() const { raise_fatal_error("Resource did not provide a name"); }
ArrayData* APCLocalArray::CopyWithStrongIterators(const ArrayData*) { raise_fatal_error( "Unimplemented ArrayData::copyWithStrongIterators"); }
void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) { assert(wait_handle); assert(wait_handle->getContext() == this); auto session = AsioSession::Get(); auto ete_queue = session->getExternalThreadEventQueue(); if (!session->hasAbruptInterruptException()) { session->initAbruptInterruptException(); } while (!wait_handle->isFinished()) { // Run queue of ready async functions once. if (!m_runnableQueue.empty()) { auto wh = m_runnableQueue.back(); m_runnableQueue.pop_back(); if (wh->getState() != c_ResumableWaitHandle::STATE_READY) { // may happen if wh was scheduled in multiple contexts decRefObj(wh); } else { wh->resume(); } continue; } if (!m_fastRunnableQueue.empty()) { auto wh = m_fastRunnableQueue.back(); m_fastRunnableQueue.pop_back(); if (wh->getState() != c_ResumableWaitHandle::STATE_READY) { // may happen if wh was scheduled in multiple contexts decRefObj(wh); } else { wh->resume(); } continue; } // Process all sleep handles that have completed their sleep. if (session->processSleepEvents()) { continue; } // Process all external thread events that have completed their operation. // Queue may contain received unprocessed events from failed runUntil(). if (UNLIKELY(ete_queue->hasReceived()) || ete_queue->tryReceiveSome()) { ete_queue->processAllReceived(); continue; } // Run default priority queue once. if (runSingle(m_priorityQueueDefault)) { continue; } // Wait for pending external thread events... if (!m_externalThreadEvents.empty()) { // ...but only until the next sleeper (from any context) finishes. onIOWaitEnter(session); // check if onIOWaitEnter callback unblocked any wait handles if (LIKELY(m_runnableQueue.empty() && m_fastRunnableQueue.empty() && !m_externalThreadEvents.empty() && !ete_queue->hasReceived() && m_priorityQueueDefault.empty())) { auto waketime = session->sleepWakeTime(); ete_queue->receiveSomeUntil(waketime); } onIOWaitExit(session, this); if (ete_queue->hasReceived()) { // Either we didn't have to wait, or we waited but no sleeper timed us // out, so just handle the ETEs. ete_queue->processAllReceived(); } else { // No received events means the next-to-wake sleeper timed us out. session->processSleepEvents(); } continue; } // If we're here, then the only things left are sleepers. Wait for one to // be ready (in any context). if (!m_sleepEvents.empty()) { onIOWaitEnter(session); // check if onIOWaitEnter callback unblocked any wait handles if (LIKELY(m_runnableQueue.empty() && m_fastRunnableQueue.empty() && m_externalThreadEvents.empty() && m_priorityQueueDefault.empty() && !m_sleepEvents.empty())) { std::this_thread::sleep_until(session->sleepWakeTime()); } onIOWaitExit(session, this); session->processSleepEvents(); continue; } // Run no-pending-io priority queue once. if (runSingle(m_priorityQueueNoPendingIO)) { continue; } // What? The wait handle did not finish? We know it is part of the current // context and since there is nothing else to run, it cannot be in RUNNING // or READY/SCHEDULED state. So it must be BLOCKED on something. Apparently, // the same logic can be used recursively on the something, so there is an // infinite chain of blocked wait handles. But our memory is not infinite. // What could it possibly mean? I think we are in a deep sh^H^Hcycle. // But we can't, the cycles are detected and avoided at blockOn() time. // So, looks like it's not cycle, but the word I started typing first. assert(false); raise_fatal_error( "Invariant violation: queues are empty, but wait handle did not finish"); } }
static ArrayData* ZSetStrThrow(ArrayData* ad, StringData* k, RefData* v) { raise_fatal_error("Unimplemented ArrayData::ZSetStr"); }
static ArrayData* ZSetIntThrow(ArrayData* ad, int64_t k, RefData* v) { raise_fatal_error("Unimplemented ArrayData::ZSetInt"); }
static ArrayData* ZAppendThrow(ArrayData* ad, RefData* v, int64_t* key_ptr) { raise_fatal_error("Unimplemented ArrayData::ZAppend"); }