예제 #1
0
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);
}
예제 #2
0
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");
  }
}
예제 #5
0
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());
}
예제 #6
0
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;
}
예제 #7
0
bool MemFile::flush() {
  raise_fatal_error((std::string("cannot flush a mem stream: ") +
                             getName()).c_str());
}
예제 #8
0
int64_t MemFile::writeImpl(const char* /*buffer*/, int64_t /*length*/) {
  raise_fatal_error((std::string("cannot write a mem stream: ") +
                             getName()).c_str());
}
예제 #9
0
ArrayData* GlobalsArray::CopyStatic(const ArrayData*) {
  raise_fatal_error("GlobalsArray::copyStatic "
    "not implemented.");
}
예제 #10
0
ArrayData*
GlobalsArray::CopyWithStrongIterators(const ArrayData* ad) {
  raise_fatal_error(
    "Unimplemented ArrayData::copyWithStrongIterators");
}
예제 #11
0
const String& ResourceData::o_getClassNameHook() const {
  raise_fatal_error("Resource did not provide a name");
}
예제 #12
0
ArrayData* APCLocalArray::CopyWithStrongIterators(const ArrayData*) {
  raise_fatal_error(
    "Unimplemented ArrayData::copyWithStrongIterators");
}
예제 #13
0
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");
  }
}
예제 #14
0
static ArrayData* ZSetStrThrow(ArrayData* ad, StringData* k, RefData* v) {
  raise_fatal_error("Unimplemented ArrayData::ZSetStr");
}
예제 #15
0
static ArrayData* ZSetIntThrow(ArrayData* ad, int64_t k, RefData* v) {
  raise_fatal_error("Unimplemented ArrayData::ZSetInt");
}
예제 #16
0
static ArrayData* ZAppendThrow(ArrayData* ad, RefData* v, int64_t* key_ptr) {
  raise_fatal_error("Unimplemented ArrayData::ZAppend");
}