1 // Copyright 2013 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/utility/run_loop.h" 6 7 #include <assert.h> 8 9 #include <algorithm> 10 #include <vector> 11 12 #include "mojo/public/utility/run_loop_handler.h" 13 #include "mojo/public/utility/thread_local.h" 14 15 namespace mojo { 16 namespace utility { 17 namespace { 18 19 ThreadLocalPointer<RunLoop>* tls_run_loop = NULL; 20 21 const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0); 22 23 } // namespace 24 25 // State needed for one iteration of WaitMany(). 26 struct RunLoop::WaitState { 27 WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {} 28 29 std::vector<Handle> handles; 30 std::vector<MojoWaitFlags> wait_flags; 31 MojoDeadline deadline; 32 }; 33 34 struct RunLoop::RunState { 35 RunState() : should_quit(false) {} 36 37 bool should_quit; 38 }; 39 40 RunLoop::RunLoop() : run_state_(NULL), next_handler_id_(0) { 41 assert(tls_run_loop); 42 assert(!tls_run_loop->Get()); 43 tls_run_loop->Set(this); 44 } 45 46 RunLoop::~RunLoop() { 47 assert(tls_run_loop->Get() == this); 48 tls_run_loop->Set(NULL); 49 } 50 51 // static 52 void RunLoop::SetUp() { 53 assert(!tls_run_loop); 54 tls_run_loop = new ThreadLocalPointer<RunLoop>; 55 } 56 57 // static 58 void RunLoop::TearDown() { 59 assert(!current()); 60 assert(tls_run_loop); 61 delete tls_run_loop; 62 tls_run_loop = NULL; 63 } 64 65 // static 66 RunLoop* RunLoop::current() { 67 assert(tls_run_loop); 68 return tls_run_loop->Get(); 69 } 70 71 void RunLoop::AddHandler(RunLoopHandler* handler, 72 const Handle& handle, 73 MojoWaitFlags wait_flags, 74 MojoDeadline deadline) { 75 assert(current() == this); 76 assert(handler); 77 assert(handle.is_valid()); 78 // Assume it's an error if someone tries to reregister an existing handle. 79 assert(0u == handler_data_.count(handle)); 80 HandlerData handler_data; 81 handler_data.handler = handler; 82 handler_data.wait_flags = wait_flags; 83 handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ? 84 kInvalidTimeTicks : 85 GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline); 86 handler_data.id = next_handler_id_++; 87 handler_data_[handle] = handler_data; 88 } 89 90 void RunLoop::RemoveHandler(const Handle& handle) { 91 assert(current() == this); 92 handler_data_.erase(handle); 93 } 94 95 void RunLoop::Run() { 96 assert(current() == this); 97 // We don't currently support nesting. 98 assert(!run_state_); 99 RunState* old_state = run_state_; 100 RunState run_state; 101 run_state_ = &run_state; 102 while (!run_state.should_quit) 103 Wait(); 104 run_state_ = old_state; 105 } 106 107 void RunLoop::Quit() { 108 assert(current() == this); 109 if (run_state_) 110 run_state_->should_quit = true; 111 } 112 113 void RunLoop::Wait() { 114 const WaitState wait_state = GetWaitState(); 115 if (wait_state.handles.empty()) { 116 Quit(); 117 return; 118 } 119 120 const MojoResult result = 121 WaitMany(wait_state.handles, wait_state.wait_flags, wait_state.deadline); 122 if (result >= 0) { 123 const size_t index = static_cast<size_t>(result); 124 assert(handler_data_.find(wait_state.handles[index]) != 125 handler_data_.end()); 126 handler_data_[wait_state.handles[index]].handler->OnHandleReady( 127 wait_state.handles[index]); 128 } else { 129 switch (result) { 130 case MOJO_RESULT_INVALID_ARGUMENT: 131 case MOJO_RESULT_FAILED_PRECONDITION: 132 RemoveFirstInvalidHandle(wait_state); 133 break; 134 case MOJO_RESULT_DEADLINE_EXCEEDED: 135 break; 136 default: 137 assert(false); 138 } 139 } 140 141 NotifyDeadlineExceeded(); 142 } 143 144 void RunLoop::NotifyDeadlineExceeded() { 145 // Make a copy in case someone tries to add/remove new handlers as part of 146 // notifying. 147 const HandleToHandlerData cloned_handlers(handler_data_); 148 const MojoTimeTicks now(GetTimeTicksNow()); 149 for (HandleToHandlerData::const_iterator i = cloned_handlers.begin(); 150 i != cloned_handlers.end(); ++i) { 151 // Since we're iterating over a clone of the handlers, verify the handler is 152 // still valid before notifying. 153 if (i->second.deadline != kInvalidTimeTicks && 154 i->second.deadline < now && 155 handler_data_.find(i->first) != handler_data_.end() && 156 handler_data_[i->first].id == i->second.id) { 157 i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); 158 } 159 } 160 } 161 162 void RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) { 163 for (size_t i = 0; i < wait_state.handles.size(); ++i) { 164 const MojoResult result = 165 mojo::Wait(wait_state.handles[i], wait_state.wait_flags[i], 166 static_cast<MojoDeadline>(0)); 167 if (result == MOJO_RESULT_INVALID_ARGUMENT || 168 result == MOJO_RESULT_FAILED_PRECONDITION) { 169 // Remove the handle first, this way if OnHandleError() tries to remove 170 // the handle our iterator isn't invalidated. 171 assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end()); 172 RunLoopHandler* handler = 173 handler_data_[wait_state.handles[i]].handler; 174 handler_data_.erase(wait_state.handles[i]); 175 handler->OnHandleError(wait_state.handles[i], result); 176 return; 177 } else { 178 assert(MOJO_RESULT_DEADLINE_EXCEEDED == result); 179 } 180 } 181 } 182 183 RunLoop::WaitState RunLoop::GetWaitState() const { 184 WaitState wait_state; 185 MojoTimeTicks min_time = kInvalidTimeTicks; 186 for (HandleToHandlerData::const_iterator i = handler_data_.begin(); 187 i != handler_data_.end(); ++i) { 188 wait_state.handles.push_back(i->first); 189 wait_state.wait_flags.push_back(i->second.wait_flags); 190 if (i->second.deadline != kInvalidTimeTicks && 191 (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { 192 min_time = i->second.deadline; 193 } 194 } 195 if (min_time != kInvalidTimeTicks) { 196 const MojoTimeTicks now = GetTimeTicksNow(); 197 if (min_time < now) 198 wait_state.deadline = static_cast<MojoDeadline>(0); 199 else 200 wait_state.deadline = static_cast<MojoDeadline>(min_time - now); 201 } 202 return wait_state; 203 } 204 205 } // namespace utility 206 } // namespace mojo 207