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 |