/**
 * Receive at least one finished event.
 */
void AsioExternalThreadEventQueue::receiveSome() {
  // Wait for over nine thousand hours.
  bool received UNUSED = receiveSomeUntil(
      std::chrono::steady_clock::now() + std::chrono::hours(9001));
  assert(received);
}
Example #2
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();
  auto& sleep_queue = session->getSleepEventQueue();

  if (!session->hasAbruptInterruptException()) {
    session->initAbruptInterruptException();
  }

  while (!wait_handle->isFinished()) {
    // Run queue of ready async functions once.
    if (!m_runnableQueue.empty()) {
      auto current = m_runnableQueue.back();
      m_runnableQueue.pop_back();
      current->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.
      AsioSession::TimePoint waketime;
      if (sleep_queue.empty()) {
        waketime = AsioSession::getLatestWakeTime();
      } else {
        waketime = sleep_queue.top()->getWakeTime();
      }

      // Wait if necessary.
      if (LIKELY(!ete_queue->hasReceived())) {
        onIOWaitEnter(session);
        ete_queue->receiveSomeUntil(waketime);
        onIOWaitExit(session);
      }

      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);
      std::this_thread::sleep_until(sleep_queue.top()->getWakeTime());
      onIOWaitExit(session);

      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 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);
    throw FatalErrorException(
      "Invariant violation: queues are empty, but wait handle did not finish");
  }
}
/**
 * Receive at least one finished event.
 */
void AsioExternalThreadEventQueue::receiveSome() {
  bool received UNUSED = receiveSomeUntil(AsioSession::getLatestWakeTime());
  assert(received);
}