Index: mojo/public/cpp/utility/lib/run_loop.cc |
diff --git a/mojo/public/cpp/utility/lib/run_loop.cc b/mojo/public/cpp/utility/lib/run_loop.cc |
deleted file mode 100644 |
index e5c8b8690f746db9da4d4cb113461a8142862e67..0000000000000000000000000000000000000000 |
--- a/mojo/public/cpp/utility/lib/run_loop.cc |
+++ /dev/null |
@@ -1,396 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "mojo/public/cpp/utility/run_loop.h" |
- |
-#include <assert.h> |
-#include <mojo/macros.h> |
-#include <pthread.h> |
- |
-#include <algorithm> |
-#include <limits> |
-#include <utility> |
-#include <vector> |
- |
-#include "mojo/public/cpp/system/time.h" |
-#include "mojo/public/cpp/system/wait.h" |
-#include "mojo/public/cpp/utility/run_loop_handler.h" |
- |
-namespace mojo { |
-namespace { |
- |
-// The initial and maximum number of results that we'll accept from |
-// |WaitSetWait()|. TODO(vtl): I just made up these numbers. |
-constexpr uint32_t kInitialWaitSetNumResults = 16u; |
-constexpr uint32_t kMaximumWaitSetNumResults = 256u; |
- |
-pthread_key_t g_current_run_loop_key; |
- |
-// Ensures that the "current run loop" functionality is available (i.e., that we |
-// have a TLS slot). |
-void InitializeCurrentRunLoopIfNecessary() { |
- static pthread_once_t current_run_loop_key_once = PTHREAD_ONCE_INIT; |
- int error = pthread_once(¤t_run_loop_key_once, []() { |
- int error = pthread_key_create(&g_current_run_loop_key, nullptr); |
- MOJO_ALLOW_UNUSED_LOCAL(error); |
- assert(!error); |
- }); |
- MOJO_ALLOW_UNUSED_LOCAL(error); |
- assert(!error); |
-} |
- |
-void SetCurrentRunLoop(RunLoop* run_loop) { |
- InitializeCurrentRunLoopIfNecessary(); |
- |
- int error = pthread_setspecific(g_current_run_loop_key, run_loop); |
- MOJO_ALLOW_UNUSED_LOCAL(error); |
- assert(!error); |
-} |
- |
-} // namespace |
- |
-RunLoop::DelayedTaskInfo::DelayedTaskInfo(RunLoopHandler::Id id, |
- const Closure& task, |
- MojoTimeTicks absolute_run_time) |
- : id(id), task(task), absolute_run_time(absolute_run_time) {} |
- |
-RunLoop::DelayedTaskInfo::~DelayedTaskInfo() {} |
- |
-struct RunLoop::RunState { |
- bool should_quit = false; |
- uint32_t results_size = kInitialWaitSetNumResults; |
- std::vector<MojoWaitSetResult> results; |
-}; |
- |
-// static |
-constexpr MojoTimeTicks RunLoop::kInvalidTimeTicks; |
- |
-RunLoop::RunLoop() { |
- MojoResult result = CreateWaitSet(nullptr, &wait_set_); |
- MOJO_ALLOW_UNUSED_LOCAL(result); |
- assert(result == MOJO_RESULT_OK); |
- assert(wait_set_.is_valid()); |
- |
- assert(!current()); |
- SetCurrentRunLoop(this); |
-} |
- |
-RunLoop::~RunLoop() { |
- assert(current() == this); |
- |
- // Notify all handlers that they've been aborted. Note that handlers could |
- // conceivably call |RemoveHandler()| (which would be a bit shady, admittedly, |
- // even if we handle it correctly). (They could also call |AddHandler()|, |
- // which would be even shadier; we handle this "correctly", but we may still |
- // end up looping infinitely in that case.) |
- while (!handlers_.empty()) { |
- auto it = handlers_.begin(); |
- auto handler = it->second.handler; |
- auto id = it->first; |
- handlers_.erase(it); |
- handler->OnHandleError(id, MOJO_RESULT_ABORTED); |
- } |
- |
- SetCurrentRunLoop(nullptr); |
-} |
- |
-// static |
-RunLoop* RunLoop::current() { |
- InitializeCurrentRunLoopIfNecessary(); |
- return static_cast<RunLoop*>(pthread_getspecific(g_current_run_loop_key)); |
-} |
- |
-RunLoopHandler::Id RunLoop::AddHandler(RunLoopHandler* handler, |
- const Handle& handle, |
- MojoHandleSignals handle_signals, |
- MojoDeadline deadline) { |
- assert(current() == this); |
- assert(handler); |
- assert(handle.is_valid()); |
- |
- // Generate a |RunLoopHandler::Id|. |
- auto id = next_id_++; |
- |
- // Calculate the absolute deadline. |
- auto absolute_deadline = kInvalidTimeTicks; // Default to "forever". |
- static constexpr auto kMaxMojoTimeTicks = |
- std::numeric_limits<MojoTimeTicks>::max(); |
- if (deadline <= static_cast<MojoDeadline>(kMaxMojoTimeTicks)) { |
- auto now = GetTimeTicksNow(); |
- if (deadline <= static_cast<MojoDeadline>(kMaxMojoTimeTicks - now)) { |
- absolute_deadline = now + static_cast<MojoTimeTicks>(deadline); |
- handler_deadlines_.push(HandlerDeadlineInfo(id, absolute_deadline)); |
- } |
- // Else either |deadline| or |now| is so large (hopefully the former) that |
- // |now + deadline| would overflow. We'll take that to mean forever. |
- } |
- // Else |deadline| is either very large (which we may as well take as forever) |
- // or |MOJO_DEADLINE_INDEFINITE| (which is forever). |
- |
- // Add an entry to |handlers_|. |
- handlers_.insert(std::make_pair( |
- id, HandlerInfo(handler, handle_signals, absolute_deadline))); |
- // Add an entry to the wait set. |
- MojoResult result = |
- WaitSetAdd(wait_set_.get(), handle, handle_signals, id, nullptr); |
- MOJO_ALLOW_UNUSED_LOCAL(result); |
- assert(result == MOJO_RESULT_OK); |
- |
- return id; |
-} |
- |
-void RunLoop::RemoveHandler(RunLoopHandler::Id id) { |
- assert(current() == this); |
- |
- // Remove the entry from |handlers_|. |
- auto it = handlers_.find(id); |
- if (it == handlers_.end()) |
- return; |
- handlers_.erase(it); |
- // Remove the entry from the wait set. |
- MojoResult result = WaitSetRemove(wait_set_.get(), id); |
- MOJO_ALLOW_UNUSED_LOCAL(result); |
- assert(result == MOJO_RESULT_OK); |
-} |
- |
-void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) { |
- assert(current() == this); |
- |
- // Generate a |RunLoopHandler::Id|. |
- auto id = next_id_++; |
- |
- // Calculate the absolute run time. |
- auto now = GetTimeTicksNow(); |
- assert(delay <= std::numeric_limits<MojoTimeTicks>::max() - now); |
- auto absolute_run_time = now + delay; |
- |
- // Add an entry to |delayed_tasks_|. |
- delayed_tasks_.push(DelayedTaskInfo(id, task, absolute_run_time)); |
-} |
- |
-void RunLoop::Run() { |
- RunInternal(false); |
-} |
- |
-void RunLoop::RunUntilIdle() { |
- RunInternal(true); |
-} |
- |
-void RunLoop::Quit() { |
- assert(current() == this); |
- |
- if (current_run_state_) |
- current_run_state_->should_quit = true; |
-} |
- |
-void RunLoop::RunInternal(bool quit_when_idle) { |
- assert(current() == this); |
- |
- auto old_run_state = current_run_state_; |
- RunState run_state; |
- current_run_state_ = &run_state; |
- |
- while (DoIteration(quit_when_idle)) |
- ; // The work is done in |DoIteration()|. |
- |
- current_run_state_ = old_run_state; |
-} |
- |
-bool RunLoop::DoIteration(bool quit_when_idle) { |
- assert(current_run_state_); |
- RunState& run_state = *current_run_state_; |
- assert(!run_state.should_quit); |
- |
- bool should_continue = false; |
- |
- auto now = GetTimeTicksNow(); |
- |
- // First, execute any already-enqueued tasks that are ready. |
- |
- // This is a fake task that we use to compare to enqueued tasks (if one were |
- // to post a task now with no delay, it'd look like this). This is convenient |
- // since |DelayedTaskInfo| has an |operator<| (used by the priority queue |
- // |delayed_tasks_|). |
- // |
- // We want to execute tasks that are "greater" than |now_task| (i.e., |
- // |now_task| is less than them) -- this includes all tasks that are currently |
- // ready, but not any newly-posted tasks (i.e., those that are posted as a |
- // result of executing ready tasks). |
- DelayedTaskInfo now_task(next_id_, Closure(), now); |
- |
- while (!delayed_tasks_.empty() && now_task < delayed_tasks_.top()) { |
- // We could just execute the task directly from |delayed_tasks_.top()|, |
- // since no newly-posted task should change the top of the priority queue, |
- // but doing the below is more obviously correct. |
- Closure task = delayed_tasks_.top().task; |
- delayed_tasks_.pop(); |
- task.Run(); |
- should_continue = true; |
- |
- if (run_state.should_quit) |
- return false; |
- } |
- |
- // Next, "wait" and deal with handles/handlers. |
- |
- if (handlers_.empty()) |
- return should_continue; |
- |
- // Calculate the deadline for the wait. Don't wait if |quit_when_idle| is |
- // true. Otherwise, the minimum of the earliest delayed task run time and the |
- // earliest handler deadline (or "forever" if there are no delayed tasks and |
- // no handler deadlines). (Warning: |CalculateAbsoluteDeadline()| may return a |
- // deadline earlier than |now|.) |
- bool absolute_deadline_is_for_delayed_task = false; |
- MojoTimeTicks absolute_deadline = |
- quit_when_idle |
- ? now |
- : CalculateAbsoluteDeadline(&absolute_deadline_is_for_delayed_task); |
- MojoDeadline relative_deadline = |
- (absolute_deadline == kInvalidTimeTicks) |
- ? MOJO_DEADLINE_INDEFINITE |
- : static_cast<MojoDeadline>(std::max(now, absolute_deadline) - now); |
- |
- run_state.results.resize(run_state.results_size); |
- uint32_t max_results = run_state.results_size; |
- switch (WaitSetWait(wait_set_.get(), relative_deadline, |
- ¤t_run_state_->results, &max_results)) { |
- case MOJO_RESULT_OK: |
- // If there were more results than we could accept, try increasing the |
- // number we accept (up to our limit). |
- if (max_results > run_state.results_size) { |
- run_state.results_size = |
- std::min(kMaximumWaitSetNumResults, run_state.results_size * 2u); |
- } |
- should_continue |= NotifyResults(run_state.results); |
- break; |
- case MOJO_RESULT_INVALID_ARGUMENT: |
- assert(false); // This shouldn't happen. |
- return false; |
- case MOJO_RESULT_CANCELLED: |
- assert(false); // This shouldn't happen. |
- return false; |
- case MOJO_RESULT_RESOURCE_EXHAUSTED: |
- assert(false); // Sadness. |
- return false; |
- case MOJO_RESULT_BUSY: |
- assert(false); // This shouldn't happen. |
- return false; |
- case MOJO_RESULT_DEADLINE_EXCEEDED: |
- should_continue |= NotifyHandlersDeadlineExceeded(absolute_deadline); |
- // If we timed out due for a delayed task, pretend that we did work since |
- // we're not idle yet (there'll be work to do immediately the next time |
- // through the loop). |
- should_continue |= absolute_deadline_is_for_delayed_task; |
- break; |
- default: |
- assert(false); // This *really* shouldn't happen. |
- return false; |
- } |
- |
- if (run_state.should_quit) |
- return false; |
- |
- return quit_when_idle ? should_continue : !handlers_.empty(); |
-} |
- |
-MojoTimeTicks RunLoop::CalculateAbsoluteDeadline(bool* is_delayed_task) { |
- assert(!handlers_.empty()); |
- |
- // Default to "forever". |
- MojoTimeTicks absolute_deadline = kInvalidTimeTicks; |
- if (delayed_tasks_.empty()) { |
- *is_delayed_task = false; |
- } else { |
- // If there are delayed tasks, our deadline can be no later than the |
- // earliest run time. |
- absolute_deadline = delayed_tasks_.top().absolute_run_time; |
- *is_delayed_task = true; |
- } |
- |
- // Find the earliest handler deadline. |
- while (!handler_deadlines_.empty()) { |
- const HandlerDeadlineInfo& info = handler_deadlines_.top(); |
- const auto it = handlers_.find(info.id); |
- // We might have a stale entry at the top. If so, remove it and continue. |
- if (it == handlers_.end()) { |
- handler_deadlines_.pop(); |
- continue; |
- } |
- |
- if (absolute_deadline == kInvalidTimeTicks || |
- info.absolute_deadline < absolute_deadline) { |
- absolute_deadline = info.absolute_deadline; |
- *is_delayed_task = false; |
- } |
- |
- break; |
- } |
- |
- return absolute_deadline; |
-} |
- |
-bool RunLoop::NotifyResults(const std::vector<MojoWaitSetResult>& results) { |
- assert(!results.empty()); |
- |
- bool did_work = false; |
- for (const auto& result : results) { |
- auto id = result.cookie; |
- auto it = handlers_.find(id); |
- // Though we should find an entry for the first result, a handler that we |
- // invoke may remove other handlers. |
- if (it == handlers_.end()) |
- continue; |
- |
- auto handler = it->second.handler; |
- handlers_.erase(it); |
- MojoResult r = WaitSetRemove(wait_set_.get(), id); |
- MOJO_ALLOW_UNUSED_LOCAL(r); |
- assert(r == MOJO_RESULT_OK); |
- if (result.wait_result == MOJO_RESULT_OK) |
- handler->OnHandleReady(id); |
- else |
- handler->OnHandleError(id, result.wait_result); |
- did_work = true; |
- |
- if (current_run_state_->should_quit) |
- break; |
- } |
- return did_work; |
-} |
- |
-bool RunLoop::NotifyHandlersDeadlineExceeded(MojoTimeTicks absolute_deadline) { |
- assert(!handlers_.empty()); |
- assert(absolute_deadline != kInvalidTimeTicks); |
- |
- bool did_work = false; |
- while (!handler_deadlines_.empty()) { |
- const HandlerDeadlineInfo& info = handler_deadlines_.top(); |
- |
- if (info.absolute_deadline > absolute_deadline) |
- break; |
- |
- const auto it = handlers_.find(info.id); |
- // Though the top shouldn't be stale, there may be stale entries after it |
- // (with the same deadline). Moreover, previously-run handlers may have |
- // removed yet-to-be-run handlers. |
- if (it == handlers_.end()) { |
- handler_deadlines_.pop(); |
- continue; |
- } |
- |
- auto handler = it->second.handler; |
- auto id = info.id; |
- handlers_.erase(it); // Invalidates |it|. |
- handler_deadlines_.pop(); // Invalidates |info|. |
- handler->OnHandleError(id, MOJO_RESULT_DEADLINE_EXCEEDED); |
- did_work = true; |
- |
- if (current_run_state_->should_quit) |
- break; |
- } |
- return did_work; |
-} |
- |
-} // namespace mojo |