/** * 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); }
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); }