| Index: mojo/message_pump/message_pump_mojo.cc
|
| diff --git a/mojo/message_pump/message_pump_mojo.cc b/mojo/message_pump/message_pump_mojo.cc
|
| index 3f60dd7116d9744411263ad6452563e148ee0990..d160d7268a055c7e50ff422a13cda871cd21974f 100644
|
| --- a/mojo/message_pump/message_pump_mojo.cc
|
| +++ b/mojo/message_pump/message_pump_mojo.cc
|
| @@ -15,6 +15,7 @@
|
| #include "base/lazy_instance.h"
|
| #include "base/logging.h"
|
| #include "base/threading/thread_local.h"
|
| +#include "base/threading/thread_restrictions.h"
|
| #include "base/time/time.h"
|
| #include "mojo/message_pump/message_pump_mojo_handler.h"
|
| #include "mojo/message_pump/time_helper.h"
|
| @@ -48,7 +49,8 @@ struct MessagePumpMojo::RunState {
|
| bool should_quit;
|
| };
|
|
|
| -MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) {
|
| +MessagePumpMojo::MessagePumpMojo()
|
| + : run_state_(NULL), next_handler_id_(0), event_(false, false) {
|
| DCHECK(!current())
|
| << "There is already a MessagePumpMojo instance on this thread.";
|
| g_tls_current_pump.Pointer()->Set(this);
|
| @@ -170,7 +172,11 @@ void MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) {
|
| bool more_work_is_plausible = true;
|
| for (;;) {
|
| const bool block = !more_work_is_plausible;
|
| - more_work_is_plausible = DoInternalWork(*run_state, block);
|
| + if (read_handle_.is_valid()) {
|
| + more_work_is_plausible = DoInternalWork(*run_state, block);
|
| + } else {
|
| + more_work_is_plausible = DoNonMojoWork(*run_state, block);
|
| + }
|
|
|
| if (run_state->should_quit)
|
| break;
|
| @@ -209,6 +215,30 @@ bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) {
|
| return did_work;
|
| }
|
|
|
| +bool MessagePumpMojo::DoNonMojoWork(const RunState& run_state, bool block) {
|
| + bool did_work = block;
|
| + if (block) {
|
| + const MojoDeadline deadline = GetDeadlineForWait(run_state);
|
| + // Stolen from base/message_loop/message_pump_default.cc
|
| + base::ThreadRestrictions::ScopedAllowWait allow_wait;
|
| + if (deadline == MOJO_DEADLINE_INDEFINITE) {
|
| + event_.Wait();
|
| + } else {
|
| + if (deadline > 0) {
|
| + event_.TimedWait(base::TimeDelta::FromMicroseconds(deadline));
|
| + } else {
|
| + did_work = false;
|
| + }
|
| + }
|
| + // Since event_ is auto-reset, we don't need to do anything special here
|
| + // other than service each delegate method.
|
| + }
|
| +
|
| + did_work |= RemoveExpiredHandles();
|
| +
|
| + return did_work;
|
| +}
|
| +
|
| bool MessagePumpMojo::WaitForReadyHandles(const RunState& run_state) const {
|
| const MojoDeadline deadline = GetDeadlineForWait(run_state);
|
| const MojoResult wait_result = Wait(
|
| @@ -290,10 +320,15 @@ bool MessagePumpMojo::ProcessReadyHandles() {
|
| DVLOG(1) << "Error: " << handle_results[i]
|
| << " handle: " << handle.value();
|
| if (handle.value() == read_handle_.get().value()) {
|
| - // The Mojo EDK is shutting down. The ThreadQuitHelper task in
|
| - // base::Thread won't get run since the control pipe depends on the
|
| - // EDK staying alive. So quit manually to avoid this thread hanging.
|
| - Quit();
|
| + // The Mojo EDK is shutting down. We can't just quit the message pump
|
| + // because that may cause the thread to quit, which causes the
|
| + // thread's MessageLoop to be destroyed, which races with any use of
|
| + // |Thread::task_runner()|. So instead, we enter a "dumb" mode which
|
| + // bypasses Mojo and just acts like a trivial message pump. That way,
|
| + // we can wait for the usual thread exiting mechanism to happen.
|
| + // The dumb mode is indicated by releasing the control pipe's read
|
| + // handle.
|
| + read_handle_.reset();
|
| } else {
|
| RemoveInvalidHandle(handle_results[i], handle);
|
| }
|
| @@ -375,6 +410,7 @@ void MessagePumpMojo::SignalControlPipe() {
|
| MOJO_WRITE_MESSAGE_FLAG_NONE);
|
| if (result == MOJO_RESULT_FAILED_PRECONDITION) {
|
| // Mojo EDK is shutting down.
|
| + event_.Signal();
|
| return;
|
| }
|
|
|
|
|