Index: third_party/WebKit/Source/core/mojo/MojoWatcher.cpp |
diff --git a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp |
index f178e9943ea99f96ee71b13db681f8ae721d1fe0..51d4b2a00ebf41bbb6d1f45401bfe6bf3c7116a2 100644 |
--- a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp |
+++ b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp |
@@ -20,6 +20,7 @@ static void runWatchCallback(MojoWatchCallback* callback, |
callback->call(wrappable, result); |
} |
+// static |
MojoWatcher* MojoWatcher::create(mojo::Handle handle, |
const MojoHandleSignals& signalsDict, |
MojoWatchCallback* callback, |
@@ -42,42 +43,16 @@ MojoWatcher* MojoWatcher::create(mojo::Handle handle, |
return watcher; |
} |
-MojoWatcher::MojoWatcher(ExecutionContext* context, MojoWatchCallback* callback) |
- : ContextLifecycleObserver(context), |
- m_taskRunner(TaskRunnerHelper::get(TaskType::UnspecedTimer, context)), |
- m_callback(this, callback) {} |
- |
MojoWatcher::~MojoWatcher() { |
DCHECK(!m_handle.is_valid()); |
} |
-MojoResult MojoWatcher::watch(mojo::Handle handle, |
- const MojoHandleSignals& signalsDict) { |
- ::MojoHandleSignals signals = MOJO_HANDLE_SIGNAL_NONE; |
- if (signalsDict.readable()) |
- signals |= MOJO_HANDLE_SIGNAL_READABLE; |
- if (signalsDict.writable()) |
- signals |= MOJO_HANDLE_SIGNAL_WRITABLE; |
- if (signalsDict.peerClosed()) |
- signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; |
- |
- MojoResult result = |
- MojoWatch(handle.value(), signals, &MojoWatcher::onHandleReady, |
- reinterpret_cast<uintptr_t>(this)); |
- if (result == MOJO_RESULT_OK) { |
- m_handle = handle; |
- } |
- return result; |
-} |
- |
MojoResult MojoWatcher::cancel() { |
- if (!m_handle.is_valid()) |
- return MOJO_RESULT_OK; |
+ if (!m_watcherHandle.is_valid()) |
+ return MOJO_RESULT_INVALID_ARGUMENT; |
- MojoResult result = |
- MojoCancelWatch(m_handle.value(), reinterpret_cast<uintptr_t>(this)); |
- m_handle = mojo::Handle(); |
- return result; |
+ m_watcherHandle.reset(); |
+ return MOJO_RESULT_OK; |
} |
DEFINE_TRACE(MojoWatcher) { |
@@ -97,13 +72,76 @@ void MojoWatcher::contextDestroyed(ExecutionContext*) { |
cancel(); |
} |
+MojoWatcher::MojoWatcher(ExecutionContext* context, MojoWatchCallback* callback) |
+ : ContextLifecycleObserver(context), |
+ m_taskRunner(TaskRunnerHelper::get(TaskType::UnspecedTimer, context)), |
+ m_callback(this, callback) {} |
+ |
+MojoResult MojoWatcher::watch(mojo::Handle handle, |
+ const MojoHandleSignals& signalsDict) { |
+ ::MojoHandleSignals signals = MOJO_HANDLE_SIGNAL_NONE; |
+ if (signalsDict.readable()) |
+ signals |= MOJO_HANDLE_SIGNAL_READABLE; |
+ if (signalsDict.writable()) |
+ signals |= MOJO_HANDLE_SIGNAL_WRITABLE; |
+ if (signalsDict.peerClosed()) |
+ signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; |
+ |
+ MojoResult result = |
+ mojo::CreateWatcher(&MojoWatcher::onHandleReady, &m_watcherHandle); |
+ DCHECK_EQ(MOJO_RESULT_OK, result); |
+ |
+ result = MojoWatch(m_watcherHandle.get().value(), handle.value(), signals, |
+ reinterpret_cast<uintptr_t>(this)); |
+ if (result != MOJO_RESULT_OK) |
+ return result; |
+ |
+ m_handle = handle; |
+ |
+ MojoResult readyResult; |
+ result = arm(&readyResult); |
+ if (result == MOJO_RESULT_OK) |
+ return result; |
+ |
+ // We couldn't arm the watcher because the handle is already ready to |
+ // trigger a success notification. Post a notification manually. |
+ DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); |
+ m_taskRunner->postTask(BLINK_FROM_HERE, |
+ WTF::bind(&MojoWatcher::runReadyCallback, |
+ wrapPersistent(this), readyResult)); |
+ return MOJO_RESULT_OK; |
+} |
+ |
+MojoResult MojoWatcher::arm(MojoResult* readyResult) { |
+ // Nothing to do if the watcher is inactive. |
+ if (!m_handle.is_valid()) |
+ return MOJO_RESULT_OK; |
+ |
+ uint32_t numReadyContexts = 1; |
+ uintptr_t readyContext; |
+ MojoResult localReadyResult; |
+ MojoHandleSignalsState readySignals; |
+ MojoResult result = |
+ MojoArmWatcher(m_watcherHandle.get().value(), &numReadyContexts, |
+ &readyContext, &localReadyResult, &readySignals); |
+ if (result == MOJO_RESULT_OK) |
+ return MOJO_RESULT_OK; |
+ |
+ DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); |
+ DCHECK_EQ(1u, numReadyContexts); |
+ DCHECK_EQ(reinterpret_cast<uintptr_t>(this), readyContext); |
+ *readyResult = localReadyResult; |
+ return result; |
+} |
+ |
void MojoWatcher::onHandleReady(uintptr_t context, |
MojoResult result, |
MojoHandleSignalsState, |
- MojoWatchNotificationFlags) { |
- // It is safe to assume the MojoWatcher still exists because this |
- // callback will never be run after MojoWatcher destructor, |
- // which cancels the watch. |
+ MojoWatcherNotificationFlags) { |
+ // It is safe to assume the MojoWatcher still exists. It stays alive at least |
+ // as long as |m_handle| is valid, and |m_handle| is only reset after we |
+ // dispatch a |MOJO_RESULT_CANCELLED| notification. That is always the last |
+ // notification received by this callback. |
MojoWatcher* watcher = reinterpret_cast<MojoWatcher*>(context); |
watcher->m_taskRunner->postTask( |
BLINK_FROM_HERE, |
@@ -112,17 +150,41 @@ void MojoWatcher::onHandleReady(uintptr_t context, |
} |
void MojoWatcher::runReadyCallback(MojoResult result) { |
- // Ignore callbacks if not watching. |
- if (!m_handle.is_valid()) |
+ if (result == MOJO_RESULT_CANCELLED) { |
+ // Last notification. |
+ m_handle = mojo::Handle(); |
+ |
+ // Only dispatch to the callback if this cancellation was implicit due to |
+ // |m_handle| closure. If it was explicit, |m_watcherHandle| has already |
+ // been reset. |
+ if (m_watcherHandle.is_valid()) { |
+ m_watcherHandle.reset(); |
+ runWatchCallback(m_callback, this, result); |
+ } |
return; |
+ } |
- // MOJO_RESULT_CANCELLED indicates that the handle has been closed, in which |
- // case watch has been implicitly cancelled. There is no need to explicitly |
- // cancel the watch. |
- if (result == MOJO_RESULT_CANCELLED) |
- m_handle = mojo::Handle(); |
+ // Ignore callbacks if not watching. |
+ if (!m_watcherHandle.is_valid()) |
+ return; |
runWatchCallback(m_callback, this, result); |
+ |
+ // Rearm the watcher so another notification can fire. |
+ // |
+ // TODO(rockot): MojoWatcher should expose some better approximation of the |
+ // new watcher API, including explicit add and removal of handles from the |
+ // watcher, as well as explicit arming. |
+ MojoResult readyResult; |
+ MojoResult armResult = arm(&readyResult); |
+ if (armResult == MOJO_RESULT_OK) |
+ return; |
+ |
+ DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, armResult); |
+ |
+ m_taskRunner->postTask(BLINK_FROM_HERE, |
+ WTF::bind(&MojoWatcher::runReadyCallback, |
+ wrapWeakPersistent(this), readyResult)); |
} |
} // namespace blink |