OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/message_pump/message_pump_mojo.h" | 5 #include "mojo/message_pump/message_pump_mojo.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <map> | 10 #include <map> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/containers/small_map.h" | 13 #include "base/containers/small_map.h" |
14 #include "base/debug/alias.h" | 14 #include "base/debug/alias.h" |
15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/threading/thread_local.h" | 17 #include "base/threading/thread_local.h" |
| 18 #include "base/threading/thread_restrictions.h" |
18 #include "base/time/time.h" | 19 #include "base/time/time.h" |
19 #include "mojo/message_pump/message_pump_mojo_handler.h" | 20 #include "mojo/message_pump/message_pump_mojo_handler.h" |
20 #include "mojo/message_pump/time_helper.h" | 21 #include "mojo/message_pump/time_helper.h" |
21 #include "mojo/public/c/system/wait_set.h" | 22 #include "mojo/public/c/system/wait_set.h" |
22 | 23 |
23 namespace mojo { | 24 namespace mojo { |
24 namespace common { | 25 namespace common { |
25 namespace { | 26 namespace { |
26 | 27 |
27 base::LazyInstance<base::ThreadLocalPointer<MessagePumpMojo> >::Leaky | 28 base::LazyInstance<base::ThreadLocalPointer<MessagePumpMojo> >::Leaky |
(...skipping 13 matching lines...) Expand all Loading... |
41 } // namespace | 42 } // namespace |
42 | 43 |
43 struct MessagePumpMojo::RunState { | 44 struct MessagePumpMojo::RunState { |
44 RunState() : should_quit(false) {} | 45 RunState() : should_quit(false) {} |
45 | 46 |
46 base::TimeTicks delayed_work_time; | 47 base::TimeTicks delayed_work_time; |
47 | 48 |
48 bool should_quit; | 49 bool should_quit; |
49 }; | 50 }; |
50 | 51 |
51 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) { | 52 MessagePumpMojo::MessagePumpMojo() |
| 53 : run_state_(NULL), next_handler_id_(0), event_(false, false) { |
52 DCHECK(!current()) | 54 DCHECK(!current()) |
53 << "There is already a MessagePumpMojo instance on this thread."; | 55 << "There is already a MessagePumpMojo instance on this thread."; |
54 g_tls_current_pump.Pointer()->Set(this); | 56 g_tls_current_pump.Pointer()->Set(this); |
55 | 57 |
56 MojoResult result = CreateMessagePipe(nullptr, &read_handle_, &write_handle_); | 58 MojoResult result = CreateMessagePipe(nullptr, &read_handle_, &write_handle_); |
57 CHECK_EQ(result, MOJO_RESULT_OK); | 59 CHECK_EQ(result, MOJO_RESULT_OK); |
58 CHECK(read_handle_.is_valid()); | 60 CHECK(read_handle_.is_valid()); |
59 CHECK(write_handle_.is_valid()); | 61 CHECK(write_handle_.is_valid()); |
60 | 62 |
61 MojoHandle handle; | 63 MojoHandle handle; |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 base::AutoLock auto_lock(run_state_lock_); | 165 base::AutoLock auto_lock(run_state_lock_); |
164 if (!run_state_) | 166 if (!run_state_) |
165 return; | 167 return; |
166 run_state_->delayed_work_time = delayed_work_time; | 168 run_state_->delayed_work_time = delayed_work_time; |
167 } | 169 } |
168 | 170 |
169 void MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) { | 171 void MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) { |
170 bool more_work_is_plausible = true; | 172 bool more_work_is_plausible = true; |
171 for (;;) { | 173 for (;;) { |
172 const bool block = !more_work_is_plausible; | 174 const bool block = !more_work_is_plausible; |
173 more_work_is_plausible = DoInternalWork(*run_state, block); | 175 if (read_handle_.is_valid()) { |
| 176 more_work_is_plausible = DoInternalWork(*run_state, block); |
| 177 } else { |
| 178 more_work_is_plausible = DoNonMojoWork(*run_state, block); |
| 179 } |
174 | 180 |
175 if (run_state->should_quit) | 181 if (run_state->should_quit) |
176 break; | 182 break; |
177 | 183 |
178 more_work_is_plausible |= delegate->DoWork(); | 184 more_work_is_plausible |= delegate->DoWork(); |
179 if (run_state->should_quit) | 185 if (run_state->should_quit) |
180 break; | 186 break; |
181 | 187 |
182 more_work_is_plausible |= delegate->DoDelayedWork( | 188 more_work_is_plausible |= delegate->DoDelayedWork( |
183 &run_state->delayed_work_time); | 189 &run_state->delayed_work_time); |
(...skipping 18 matching lines...) Expand all Loading... |
202 // unnecessary work. | 208 // unnecessary work. |
203 did_work = WaitForReadyHandles(run_state); | 209 did_work = WaitForReadyHandles(run_state); |
204 } | 210 } |
205 | 211 |
206 did_work |= ProcessReadyHandles(); | 212 did_work |= ProcessReadyHandles(); |
207 did_work |= RemoveExpiredHandles(); | 213 did_work |= RemoveExpiredHandles(); |
208 | 214 |
209 return did_work; | 215 return did_work; |
210 } | 216 } |
211 | 217 |
| 218 bool MessagePumpMojo::DoNonMojoWork(const RunState& run_state, bool block) { |
| 219 bool did_work = block; |
| 220 if (block) { |
| 221 const MojoDeadline deadline = GetDeadlineForWait(run_state); |
| 222 // Stolen from base/message_loop/message_pump_default.cc |
| 223 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 224 if (deadline == MOJO_DEADLINE_INDEFINITE) { |
| 225 event_.Wait(); |
| 226 } else { |
| 227 if (deadline > 0) { |
| 228 event_.TimedWait(base::TimeDelta::FromMicroseconds(deadline)); |
| 229 } else { |
| 230 did_work = false; |
| 231 } |
| 232 } |
| 233 // Since event_ is auto-reset, we don't need to do anything special here |
| 234 // other than service each delegate method. |
| 235 } |
| 236 |
| 237 did_work |= RemoveExpiredHandles(); |
| 238 |
| 239 return did_work; |
| 240 } |
| 241 |
212 bool MessagePumpMojo::WaitForReadyHandles(const RunState& run_state) const { | 242 bool MessagePumpMojo::WaitForReadyHandles(const RunState& run_state) const { |
213 const MojoDeadline deadline = GetDeadlineForWait(run_state); | 243 const MojoDeadline deadline = GetDeadlineForWait(run_state); |
214 const MojoResult wait_result = Wait( | 244 const MojoResult wait_result = Wait( |
215 wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, deadline, nullptr); | 245 wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, deadline, nullptr); |
216 if (wait_result == MOJO_RESULT_OK) { | 246 if (wait_result == MOJO_RESULT_OK) { |
217 // Handles may be ready. Or not since wake-ups can be spurious in certain | 247 // Handles may be ready. Or not since wake-ups can be spurious in certain |
218 // circumstances. | 248 // circumstances. |
219 return true; | 249 return true; |
220 } else if (wait_result == MOJO_RESULT_DEADLINE_EXCEEDED) { | 250 } else if (wait_result == MOJO_RESULT_DEADLINE_EXCEEDED) { |
221 return false; | 251 return false; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 (it == handlers_.end() || it->second.id != ready_handles[handle])) { | 313 (it == handlers_.end() || it->second.id != ready_handles[handle])) { |
284 continue; | 314 continue; |
285 } | 315 } |
286 | 316 |
287 switch (handle_results[i]) { | 317 switch (handle_results[i]) { |
288 case MOJO_RESULT_CANCELLED: | 318 case MOJO_RESULT_CANCELLED: |
289 case MOJO_RESULT_FAILED_PRECONDITION: | 319 case MOJO_RESULT_FAILED_PRECONDITION: |
290 DVLOG(1) << "Error: " << handle_results[i] | 320 DVLOG(1) << "Error: " << handle_results[i] |
291 << " handle: " << handle.value(); | 321 << " handle: " << handle.value(); |
292 if (handle.value() == read_handle_.get().value()) { | 322 if (handle.value() == read_handle_.get().value()) { |
293 // The Mojo EDK is shutting down. The ThreadQuitHelper task in | 323 // The Mojo EDK is shutting down. We can't just quit the message pump |
294 // base::Thread won't get run since the control pipe depends on the | 324 // because that may cause the thread to quit, which causes the |
295 // EDK staying alive. So quit manually to avoid this thread hanging. | 325 // thread's MessageLoop to be destroyed, which races with any use of |
296 Quit(); | 326 // |Thread::task_runner()|. So instead, we enter a "dumb" mode which |
| 327 // bypasses Mojo and just acts like a trivial message pump. That way, |
| 328 // we can wait for the usual thread exiting mechanism to happen. |
| 329 // The dumb mode is indicated by releasing the control pipe's read |
| 330 // handle. |
| 331 read_handle_.reset(); |
297 } else { | 332 } else { |
298 RemoveInvalidHandle(handle_results[i], handle); | 333 RemoveInvalidHandle(handle_results[i], handle); |
299 } | 334 } |
300 break; | 335 break; |
301 case MOJO_RESULT_OK: | 336 case MOJO_RESULT_OK: |
302 if (handle.value() == read_handle_.get().value()) { | 337 if (handle.value() == read_handle_.get().value()) { |
303 DVLOG(1) << "Signaled control pipe"; | 338 DVLOG(1) << "Signaled control pipe"; |
304 // Control pipe was written to. | 339 // Control pipe was written to. |
305 ReadMessageRaw(read_handle_.get(), nullptr, nullptr, nullptr, nullptr, | 340 ReadMessageRaw(read_handle_.get(), nullptr, nullptr, nullptr, nullptr, |
306 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | 341 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 } | 403 } |
369 return removed; | 404 return removed; |
370 } | 405 } |
371 | 406 |
372 void MessagePumpMojo::SignalControlPipe() { | 407 void MessagePumpMojo::SignalControlPipe() { |
373 const MojoResult result = | 408 const MojoResult result = |
374 WriteMessageRaw(write_handle_.get(), NULL, 0, NULL, 0, | 409 WriteMessageRaw(write_handle_.get(), NULL, 0, NULL, 0, |
375 MOJO_WRITE_MESSAGE_FLAG_NONE); | 410 MOJO_WRITE_MESSAGE_FLAG_NONE); |
376 if (result == MOJO_RESULT_FAILED_PRECONDITION) { | 411 if (result == MOJO_RESULT_FAILED_PRECONDITION) { |
377 // Mojo EDK is shutting down. | 412 // Mojo EDK is shutting down. |
| 413 event_.Signal(); |
378 return; | 414 return; |
379 } | 415 } |
380 | 416 |
381 // If we can't write we likely won't wake up the thread and there is a strong | 417 // If we can't write we likely won't wake up the thread and there is a strong |
382 // chance we'll deadlock. | 418 // chance we'll deadlock. |
383 CHECK_EQ(MOJO_RESULT_OK, result); | 419 CHECK_EQ(MOJO_RESULT_OK, result); |
384 } | 420 } |
385 | 421 |
386 MojoDeadline MessagePumpMojo::GetDeadlineForWait( | 422 MojoDeadline MessagePumpMojo::GetDeadlineForWait( |
387 const RunState& run_state) const { | 423 const RunState& run_state) const { |
(...skipping 19 matching lines...) Expand all Loading... |
407 void MessagePumpMojo::WillSignalHandler() { | 443 void MessagePumpMojo::WillSignalHandler() { |
408 FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler()); | 444 FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler()); |
409 } | 445 } |
410 | 446 |
411 void MessagePumpMojo::DidSignalHandler() { | 447 void MessagePumpMojo::DidSignalHandler() { |
412 FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler()); | 448 FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler()); |
413 } | 449 } |
414 | 450 |
415 } // namespace common | 451 } // namespace common |
416 } // namespace mojo | 452 } // namespace mojo |
OLD | NEW |