1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "mojo/public/cpp/utility/run_loop.h"
12 #include "mojo/public/cpp/utility/lib/thread_local.h"
13 #include "mojo/public/cpp/utility/run_loop_handler.h"
18 internal::ThreadLocalPointer<RunLoop> current_run_loop;
20 const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0);
24 // State needed for one iteration of WaitMany().
25 struct RunLoop::WaitState {
26 WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {}
28 std::vector<Handle> handles;
29 std::vector<MojoHandleSignals> handle_signals;
30 MojoDeadline deadline;
33 struct RunLoop::RunState {
34 RunState() : should_quit(false) {}
40 : run_state_(NULL), next_handler_id_(0), next_sequence_number_(0) {
42 current_run_loop.Set(this);
46 assert(current() == this);
47 NotifyHandlers(MOJO_RESULT_ABORTED, IGNORE_DEADLINE);
48 current_run_loop.Set(NULL);
52 void RunLoop::SetUp() {
53 current_run_loop.Allocate();
57 void RunLoop::TearDown() {
59 current_run_loop.Free();
63 RunLoop* RunLoop::current() {
64 return current_run_loop.Get();
67 void RunLoop::AddHandler(RunLoopHandler* handler,
69 MojoHandleSignals handle_signals,
70 MojoDeadline deadline) {
71 assert(current() == this);
73 assert(handle.is_valid());
74 // Assume it's an error if someone tries to reregister an existing handle.
75 assert(0u == handler_data_.count(handle));
76 HandlerData handler_data;
77 handler_data.handler = handler;
78 handler_data.handle_signals = handle_signals;
79 handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ?
81 GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline);
82 handler_data.id = next_handler_id_++;
83 handler_data_[handle] = handler_data;
86 void RunLoop::RemoveHandler(const Handle& handle) {
87 assert(current() == this);
88 handler_data_.erase(handle);
91 bool RunLoop::HasHandler(const Handle& handle) const {
92 return handler_data_.find(handle) != handler_data_.end();
96 RunInternal(UNTIL_EMPTY);
99 void RunLoop::RunUntilIdle() {
100 RunInternal(UNTIL_IDLE);
103 void RunLoop::RunInternal(RunMode run_mode) {
104 assert(current() == this);
105 RunState* old_state = run_state_;
107 run_state_ = &run_state;
109 bool did_work = DoDelayedWork();
110 if (run_state.should_quit)
112 did_work |= Wait(run_mode == UNTIL_IDLE);
113 if (run_state.should_quit)
115 if (!did_work && run_mode == UNTIL_IDLE)
118 run_state_ = old_state;
121 bool RunLoop::DoDelayedWork() {
122 MojoTimeTicks now = GetTimeTicksNow();
123 if (!delayed_tasks_.empty() && delayed_tasks_.top().run_time <= now) {
124 PendingTask task = delayed_tasks_.top();
125 delayed_tasks_.pop();
132 void RunLoop::Quit() {
133 assert(current() == this);
135 run_state_->should_quit = true;
138 void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) {
139 assert(current() == this);
140 MojoTimeTicks run_time = delay + GetTimeTicksNow();
141 delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++));
144 bool RunLoop::Wait(bool non_blocking) {
145 const WaitState wait_state = GetWaitState(non_blocking);
146 if (wait_state.handles.empty() && delayed_tasks_.empty()) {
151 const MojoResult result = WaitMany(wait_state.handles,
152 wait_state.handle_signals,
153 wait_state.deadline);
155 const size_t index = static_cast<size_t>(result);
156 assert(handler_data_.find(wait_state.handles[index]) !=
157 handler_data_.end());
158 handler_data_[wait_state.handles[index]].handler->OnHandleReady(
159 wait_state.handles[index]);
164 case MOJO_RESULT_INVALID_ARGUMENT:
165 case MOJO_RESULT_FAILED_PRECONDITION:
166 return RemoveFirstInvalidHandle(wait_state);
167 case MOJO_RESULT_DEADLINE_EXCEEDED:
168 return NotifyHandlers(MOJO_RESULT_DEADLINE_EXCEEDED, CHECK_DEADLINE);
175 bool RunLoop::NotifyHandlers(MojoResult error, CheckDeadline check) {
176 bool notified = false;
178 // Make a copy in case someone tries to add/remove new handlers as part of
180 const HandleToHandlerData cloned_handlers(handler_data_);
181 const MojoTimeTicks now(GetTimeTicksNow());
182 for (HandleToHandlerData::const_iterator i = cloned_handlers.begin();
183 i != cloned_handlers.end(); ++i) {
184 // Only check deadline exceeded if that's what we're notifying.
185 if (check == CHECK_DEADLINE && (i->second.deadline == kInvalidTimeTicks ||
186 i->second.deadline > now)) {
190 // Since we're iterating over a clone of the handlers, verify the handler
191 // is still valid before notifying.
192 if (handler_data_.find(i->first) == handler_data_.end() ||
193 handler_data_[i->first].id != i->second.id) {
197 RunLoopHandler* handler = i->second.handler;
198 handler_data_.erase(i->first);
199 handler->OnHandleError(i->first, error);
206 bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) {
207 for (size_t i = 0; i < wait_state.handles.size(); ++i) {
208 const MojoResult result =
209 mojo::Wait(wait_state.handles[i], wait_state.handle_signals[i],
210 static_cast<MojoDeadline>(0));
211 if (result == MOJO_RESULT_INVALID_ARGUMENT ||
212 result == MOJO_RESULT_FAILED_PRECONDITION) {
213 // Remove the handle first, this way if OnHandleError() tries to remove
214 // the handle our iterator isn't invalidated.
215 assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end());
216 RunLoopHandler* handler =
217 handler_data_[wait_state.handles[i]].handler;
218 handler_data_.erase(wait_state.handles[i]);
219 handler->OnHandleError(wait_state.handles[i], result);
222 assert(MOJO_RESULT_DEADLINE_EXCEEDED == result);
227 RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const {
228 WaitState wait_state;
229 MojoTimeTicks min_time = kInvalidTimeTicks;
230 for (HandleToHandlerData::const_iterator i = handler_data_.begin();
231 i != handler_data_.end(); ++i) {
232 wait_state.handles.push_back(i->first);
233 wait_state.handle_signals.push_back(i->second.handle_signals);
234 if (!non_blocking && i->second.deadline != kInvalidTimeTicks &&
235 (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) {
236 min_time = i->second.deadline;
239 if (!delayed_tasks_.empty()) {
240 MojoTimeTicks delayed_min_time = delayed_tasks_.top().run_time;
241 if (min_time == kInvalidTimeTicks)
242 min_time = delayed_min_time;
244 min_time = std::min(min_time, delayed_min_time);
247 wait_state.deadline = static_cast<MojoDeadline>(0);
248 } else if (min_time != kInvalidTimeTicks) {
249 const MojoTimeTicks now = GetTimeTicksNow();
251 wait_state.deadline = static_cast<MojoDeadline>(0);
253 wait_state.deadline = static_cast<MojoDeadline>(min_time - now);
258 RunLoop::PendingTask::PendingTask(const Closure& task,
259 MojoTimeTicks run_time,
260 uint64_t sequence_number)
261 : task(task), run_time(run_time), sequence_number(sequence_number) {
264 RunLoop::PendingTask::~PendingTask() {
267 bool RunLoop::PendingTask::operator<(const RunLoop::PendingTask& other) const {
268 if (run_time != other.run_time) {
269 // std::priority_queue<> puts the least element at the end of the queue. We
270 // want the soonest eligible task to be at the head of the queue, so
271 // run_times further in the future are considered lesser.
272 return run_time > other.run_time;
275 return sequence_number > other.sequence_number;