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. 4 5#include "mojo/public/cpp/utility/run_loop.h" 6 7#include <assert.h> 8 9#include <algorithm> 10#include <vector> 11 12#include "mojo/public/cpp/utility/lib/thread_local.h" 13#include "mojo/public/cpp/utility/run_loop_handler.h" 14 15namespace mojo { 16namespace { 17 18internal::ThreadLocalPointer<RunLoop> current_run_loop; 19 20const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0); 21 22} // namespace 23 24// State needed for one iteration of WaitMany(). 25struct RunLoop::WaitState { 26 WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {} 27 28 std::vector<Handle> handles; 29 std::vector<MojoHandleSignals> handle_signals; 30 MojoDeadline deadline; 31}; 32 33struct RunLoop::RunState { 34 RunState() : should_quit(false) {} 35 36 bool should_quit; 37}; 38 39RunLoop::RunLoop() 40 : run_state_(NULL), next_handler_id_(0), next_sequence_number_(0) { 41 assert(!current()); 42 current_run_loop.Set(this); 43} 44 45RunLoop::~RunLoop() { 46 assert(current() == this); 47 NotifyHandlers(MOJO_RESULT_ABORTED, IGNORE_DEADLINE); 48 current_run_loop.Set(NULL); 49} 50 51// static 52void RunLoop::SetUp() { 53 current_run_loop.Allocate(); 54} 55 56// static 57void RunLoop::TearDown() { 58 assert(!current()); 59 current_run_loop.Free(); 60} 61 62// static 63RunLoop* RunLoop::current() { 64 return current_run_loop.Get(); 65} 66 67void RunLoop::AddHandler(RunLoopHandler* handler, 68 const Handle& handle, 69 MojoHandleSignals handle_signals, 70 MojoDeadline deadline) { 71 assert(current() == this); 72 assert(handler); 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) ? 80 kInvalidTimeTicks : 81 GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline); 82 handler_data.id = next_handler_id_++; 83 handler_data_[handle] = handler_data; 84} 85 86void RunLoop::RemoveHandler(const Handle& handle) { 87 assert(current() == this); 88 handler_data_.erase(handle); 89} 90 91bool RunLoop::HasHandler(const Handle& handle) const { 92 return handler_data_.find(handle) != handler_data_.end(); 93} 94 95void RunLoop::Run() { 96 RunInternal(UNTIL_EMPTY); 97} 98 99void RunLoop::RunUntilIdle() { 100 RunInternal(UNTIL_IDLE); 101} 102 103void RunLoop::RunInternal(RunMode run_mode) { 104 assert(current() == this); 105 RunState* old_state = run_state_; 106 RunState run_state; 107 run_state_ = &run_state; 108 for (;;) { 109 bool did_work = DoDelayedWork(); 110 if (run_state.should_quit) 111 break; 112 did_work |= Wait(run_mode == UNTIL_IDLE); 113 if (run_state.should_quit) 114 break; 115 if (!did_work && run_mode == UNTIL_IDLE) 116 break; 117 } 118 run_state_ = old_state; 119} 120 121bool 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(); 126 task.task.Run(); 127 return true; 128 } 129 return false; 130} 131 132void RunLoop::Quit() { 133 assert(current() == this); 134 if (run_state_) 135 run_state_->should_quit = true; 136} 137 138void 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_++)); 142} 143 144bool RunLoop::Wait(bool non_blocking) { 145 const WaitState wait_state = GetWaitState(non_blocking); 146 if (wait_state.handles.empty() && delayed_tasks_.empty()) { 147 Quit(); 148 return false; 149 } 150 151 const MojoResult result = WaitMany(wait_state.handles, 152 wait_state.handle_signals, 153 wait_state.deadline); 154 if (result >= 0) { 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]); 160 return true; 161 } 162 163 switch (result) { 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); 169 } 170 171 assert(false); 172 return false; 173} 174 175bool RunLoop::NotifyHandlers(MojoResult error, CheckDeadline check) { 176 bool notified = false; 177 178 // Make a copy in case someone tries to add/remove new handlers as part of 179 // notifying. 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)) { 187 continue; 188 } 189 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) { 194 continue; 195 } 196 197 RunLoopHandler* handler = i->second.handler; 198 handler_data_.erase(i->first); 199 handler->OnHandleError(i->first, error); 200 notified = true; 201 } 202 203 return notified; 204} 205 206bool 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); 220 return true; 221 } 222 assert(MOJO_RESULT_DEADLINE_EXCEEDED == result); 223 } 224 return false; 225} 226 227RunLoop::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; 237 } 238 } 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; 243 else 244 min_time = std::min(min_time, delayed_min_time); 245 } 246 if (non_blocking) { 247 wait_state.deadline = static_cast<MojoDeadline>(0); 248 } else if (min_time != kInvalidTimeTicks) { 249 const MojoTimeTicks now = GetTimeTicksNow(); 250 if (min_time < now) 251 wait_state.deadline = static_cast<MojoDeadline>(0); 252 else 253 wait_state.deadline = static_cast<MojoDeadline>(min_time - now); 254 } 255 return wait_state; 256} 257 258RunLoop::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) { 262} 263 264RunLoop::PendingTask::~PendingTask() { 265} 266 267bool 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; 273 } 274 275 return sequence_number > other.sequence_number; 276} 277 278} // namespace mojo 279