| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/public/cpp/utility/run_loop.h" | 5 #include "mojo/public/cpp/utility/run_loop.h" |
| 6 | 6 |
| 7 #include <assert.h> | 7 #include <assert.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 } | 137 } |
| 138 | 138 |
| 139 void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) { | 139 void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) { |
| 140 assert(current() == this); | 140 assert(current() == this); |
| 141 MojoTimeTicks run_time = delay + GetTimeTicksNow(); | 141 MojoTimeTicks run_time = delay + GetTimeTicksNow(); |
| 142 delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++)); | 142 delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++)); |
| 143 } | 143 } |
| 144 | 144 |
| 145 bool RunLoop::Wait(bool non_blocking) { | 145 bool RunLoop::Wait(bool non_blocking) { |
| 146 const WaitState wait_state = GetWaitState(non_blocking); | 146 const WaitState wait_state = GetWaitState(non_blocking); |
| 147 if (wait_state.handles.empty() && delayed_tasks_.empty()) { | 147 if (wait_state.handles.empty()) { |
| 148 Quit(); | 148 if (delayed_tasks_.empty()) |
| 149 Quit(); |
| 149 return false; | 150 return false; |
| 150 } | 151 } |
| 151 | 152 |
| 152 const MojoResult result = WaitMany( | 153 const WaitManyResult wmr = |
| 153 wait_state.handles, wait_state.handle_signals, wait_state.deadline); | 154 WaitMany(wait_state.handles, wait_state.handle_signals, |
| 154 if (result >= 0) { | 155 wait_state.deadline, nullptr); |
| 155 const size_t index = static_cast<size_t>(result); | 156 |
| 156 assert(handler_data_.find(wait_state.handles[index]) != | 157 if (!wmr.IsIndexValid()) { |
| 157 handler_data_.end()); | 158 assert(wmr.result == MOJO_RESULT_DEADLINE_EXCEEDED); |
| 158 handler_data_[wait_state.handles[index]].handler->OnHandleReady( | 159 return NotifyHandlers(MOJO_RESULT_DEADLINE_EXCEEDED, CHECK_DEADLINE); |
| 159 wait_state.handles[index]); | |
| 160 return true; | |
| 161 } | 160 } |
| 162 | 161 |
| 163 switch (result) { | 162 Handle handle = wait_state.handles[wmr.index]; |
| 163 assert(handler_data_.find(handle) != handler_data_.end()); |
| 164 RunLoopHandler* handler = handler_data_[handle].handler; |
| 165 |
| 166 switch (wmr.result) { |
| 167 case MOJO_RESULT_OK: |
| 168 handler->OnHandleReady(handle); |
| 169 return true; |
| 164 case MOJO_RESULT_INVALID_ARGUMENT: | 170 case MOJO_RESULT_INVALID_ARGUMENT: |
| 165 case MOJO_RESULT_FAILED_PRECONDITION: | 171 case MOJO_RESULT_FAILED_PRECONDITION: |
| 166 return RemoveFirstInvalidHandle(wait_state); | 172 // Remove the handle first, this way if OnHandleError() tries to remove |
| 167 case MOJO_RESULT_DEADLINE_EXCEEDED: | 173 // the handle our iterator isn't invalidated. |
| 168 return NotifyHandlers(MOJO_RESULT_DEADLINE_EXCEEDED, CHECK_DEADLINE); | 174 handler_data_.erase(handle); |
| 175 handler->OnHandleError(handle, wmr.result); |
| 176 return true; |
| 177 default: |
| 178 assert(false); |
| 179 return false; |
| 169 } | 180 } |
| 170 | |
| 171 assert(false); | |
| 172 return false; | |
| 173 } | 181 } |
| 174 | 182 |
| 175 bool RunLoop::NotifyHandlers(MojoResult error, CheckDeadline check) { | 183 bool RunLoop::NotifyHandlers(MojoResult error, CheckDeadline check) { |
| 176 bool notified = false; | 184 bool notified = false; |
| 177 | 185 |
| 178 // Make a copy in case someone tries to add/remove new handlers as part of | 186 // Make a copy in case someone tries to add/remove new handlers as part of |
| 179 // notifying. | 187 // notifying. |
| 180 const HandleToHandlerData cloned_handlers(handler_data_); | 188 const HandleToHandlerData cloned_handlers(handler_data_); |
| 181 const MojoTimeTicks now(GetTimeTicksNow()); | 189 const MojoTimeTicks now(GetTimeTicksNow()); |
| 182 for (HandleToHandlerData::const_iterator i = cloned_handlers.begin(); | 190 for (HandleToHandlerData::const_iterator i = cloned_handlers.begin(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 197 | 205 |
| 198 RunLoopHandler* handler = i->second.handler; | 206 RunLoopHandler* handler = i->second.handler; |
| 199 handler_data_.erase(i->first); | 207 handler_data_.erase(i->first); |
| 200 handler->OnHandleError(i->first, error); | 208 handler->OnHandleError(i->first, error); |
| 201 notified = true; | 209 notified = true; |
| 202 } | 210 } |
| 203 | 211 |
| 204 return notified; | 212 return notified; |
| 205 } | 213 } |
| 206 | 214 |
| 207 bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) { | |
| 208 for (size_t i = 0; i < wait_state.handles.size(); ++i) { | |
| 209 const MojoResult result = mojo::Wait(wait_state.handles[i], | |
| 210 wait_state.handle_signals[i], | |
| 211 static_cast<MojoDeadline>(0)); | |
| 212 if (result == MOJO_RESULT_INVALID_ARGUMENT || | |
| 213 result == MOJO_RESULT_FAILED_PRECONDITION) { | |
| 214 // Remove the handle first, this way if OnHandleError() tries to remove | |
| 215 // the handle our iterator isn't invalidated. | |
| 216 assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end()); | |
| 217 RunLoopHandler* handler = 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 || MOJO_RESULT_OK == result); | |
| 223 } | |
| 224 return false; | |
| 225 } | |
| 226 | |
| 227 RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const { | 215 RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const { |
| 228 WaitState wait_state; | 216 WaitState wait_state; |
| 229 MojoTimeTicks min_time = kInvalidTimeTicks; | 217 MojoTimeTicks min_time = kInvalidTimeTicks; |
| 230 for (HandleToHandlerData::const_iterator i = handler_data_.begin(); | 218 for (HandleToHandlerData::const_iterator i = handler_data_.begin(); |
| 231 i != handler_data_.end(); | 219 i != handler_data_.end(); |
| 232 ++i) { | 220 ++i) { |
| 233 wait_state.handles.push_back(i->first); | 221 wait_state.handles.push_back(i->first); |
| 234 wait_state.handle_signals.push_back(i->second.handle_signals); | 222 wait_state.handle_signals.push_back(i->second.handle_signals); |
| 235 if (!non_blocking && i->second.deadline != kInvalidTimeTicks && | 223 if (!non_blocking && i->second.deadline != kInvalidTimeTicks && |
| 236 (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { | 224 (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 // std::priority_queue<> puts the least element at the end of the queue. We | 258 // std::priority_queue<> puts the least element at the end of the queue. We |
| 271 // want the soonest eligible task to be at the head of the queue, so | 259 // want the soonest eligible task to be at the head of the queue, so |
| 272 // run_times further in the future are considered lesser. | 260 // run_times further in the future are considered lesser. |
| 273 return run_time > other.run_time; | 261 return run_time > other.run_time; |
| 274 } | 262 } |
| 275 | 263 |
| 276 return sequence_number > other.sequence_number; | 264 return sequence_number > other.sequence_number; |
| 277 } | 265 } |
| 278 | 266 |
| 279 } // namespace mojo | 267 } // namespace mojo |
| OLD | NEW |