Index: content/common/message_port.cc |
diff --git a/content/common/message_port.cc b/content/common/message_port.cc |
index c89d7b5a0d0cc313290329602fedc13e6dff9150..b7a77645d1f2faf7f32d9de2c39a74a0880b18a1 100644 |
--- a/content/common/message_port.cc |
+++ b/content/common/message_port.cc |
@@ -4,7 +4,9 @@ |
#include "content/common/message_port.h" |
+#include "base/bind.h" |
#include "base/logging.h" |
+#include "base/threading/thread_task_runner_handle.h" |
namespace content { |
@@ -31,7 +33,7 @@ const mojo::ScopedMessagePipeHandle& MessagePort::GetHandle() const { |
} |
mojo::ScopedMessagePipeHandle MessagePort::ReleaseHandle() const { |
- state_->CancelWatch(); |
+ state_->UnregisterWatcher(); |
return std::move(state_->handle_); |
} |
@@ -126,13 +128,13 @@ bool MessagePort::GetMessage(base::string16* encoded_message, |
} |
void MessagePort::SetCallback(const base::Closure& callback) { |
- state_->CancelWatch(); |
+ state_->UnregisterWatcher(); |
state_->callback_ = callback; |
- state_->AddWatch(); |
+ state_->RegisterWatcher(); |
} |
void MessagePort::ClearCallback() { |
- state_->CancelWatch(); |
+ state_->UnregisterWatcher(); |
state_->callback_.Reset(); |
} |
@@ -143,44 +145,77 @@ MessagePort::State::State(mojo::ScopedMessagePipeHandle handle) |
: handle_(std::move(handle)) { |
} |
-void MessagePort::State::AddWatch() { |
+void MessagePort::State::RegisterWatcher() { |
if (!callback_) |
return; |
// NOTE: An HTML MessagePort does not receive an event to tell it when the |
// peer has gone away, so we only watch for readability here. |
- MojoResult rv = MojoWatch(handle_.get().value(), |
- MOJO_HANDLE_SIGNAL_READABLE, |
- &MessagePort::State::OnHandleReady, |
- reinterpret_cast<uintptr_t>(this)); |
- if (rv != MOJO_RESULT_OK) |
- DVLOG(1) << this << " MojoWatch failed: " << rv; |
+ MojoResult rv = |
+ MojoRegisterWatcher(handle_.get().value(), MOJO_HANDLE_SIGNAL_READABLE, |
+ &MessagePort::State::CallOnHandleReady, |
+ reinterpret_cast<uintptr_t>(this)); |
+ if (rv != MOJO_RESULT_OK) { |
+ DVLOG(1) << this << " MojoRegisterWatcher failed: " << rv; |
+ return; |
+ } |
+ |
+ ArmWatcher(); |
} |
-void MessagePort::State::CancelWatch() { |
+void MessagePort::State::UnregisterWatcher() { |
if (!callback_) |
return; |
// NOTE: This synchronizes with the thread where OnHandleReady runs so we are |
// sure to not be racing with it. |
- MojoCancelWatch(handle_.get().value(), reinterpret_cast<uintptr_t>(this)); |
+ MojoUnregisterWatcher(handle_.get().value(), |
+ reinterpret_cast<uintptr_t>(this)); |
} |
-// static |
-void MessagePort::State::OnHandleReady( |
- uintptr_t context, |
- MojoResult result, |
- MojoHandleSignalsState signals_state, |
- MojoWatchNotificationFlags flags) { |
+MessagePort::State::~State() { |
+ UnregisterWatcher(); |
+} |
+ |
+void MessagePort::State::ArmWatcher() { |
+ if (!callback_) |
+ return; |
+ |
+ MojoResult rv = |
+ MojoArmWatcher(handle_.get().value(), reinterpret_cast<uintptr_t>(this)); |
+ if (rv == MOJO_RESULT_OK) |
+ return; |
+ |
+ if (rv == MOJO_RESULT_ALREADY_EXISTS) { |
+ // The handle is already signalled, so we trigger a callback immediately. |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&State::OnHandleReady, this, MOJO_RESULT_OK)); |
+ return; |
+ } |
+ |
+ if (rv == MOJO_RESULT_FAILED_PRECONDITION) { |
+ DVLOG(1) << this << " MojoArmWatcher failed because of a broken pipe."; |
+ return; |
+ } |
+ |
+ NOTREACHED(); |
+} |
+ |
+void MessagePort::State::OnHandleReady(MojoResult result) { |
if (result == MOJO_RESULT_OK) { |
- reinterpret_cast<MessagePort::State*>(context)->callback_.Run(); |
+ callback_.Run(); |
+ ArmWatcher(); |
} else { |
// And now his watch is ended. |
} |
} |
-MessagePort::State::~State() { |
- CancelWatch(); |
+// static |
+void MessagePort::State::CallOnHandleReady(uintptr_t context, |
+ MojoResult result, |
+ MojoHandleSignalsState signals_state, |
+ MojoWatchNotificationFlags flags) { |
+ reinterpret_cast<State*>(context)->OnHandleReady(result); |
} |
} // namespace content |