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 804536d40d710b92a73294c1b43e30129550f58e..2175d06ca7899b0c915eef13c811fea95380d79c 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, |
@@ -27,8 +28,8 @@ MojoWatcher* MojoWatcher::create(mojo::Handle handle, |
MojoWatcher* watcher = new MojoWatcher(context, callback); |
MojoResult result = watcher->watch(handle, signalsDict); |
// TODO(alokp): Consider raising an exception. |
- // Current clients expect to recieve the initial error returned by MojoWatch |
- // via watch callback. |
+ // Current clients expect to recieve the initial error returned by |
+ // MojoRegisterWatcher via watch callback. |
// |
// Note that the usage of wrapPersistent is intentional so that the intial |
// error is guaranteed to be reported to the client in case where the given |
@@ -39,45 +40,21 @@ MojoWatcher* MojoWatcher::create(mojo::Handle handle, |
BLINK_FROM_HERE, WTF::bind(&runWatchCallback, wrapPersistent(callback), |
wrapPersistent(watcher), result)); |
} |
+ |
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_watcherHandle.reset(); |
m_handle = mojo::Handle(); |
- return result; |
+ return MOJO_RESULT_OK; |
} |
DEFINE_TRACE(MojoWatcher) { |
@@ -90,25 +67,87 @@ DEFINE_TRACE_WRAPPERS(MojoWatcher) { |
} |
bool MojoWatcher::hasPendingActivity() const { |
- return m_handle.is_valid(); |
+ return !!m_context; |
} |
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; |
+ |
+ m_handle = handle; |
+ |
+ MojoResult rv = |
+ mojo::CreateWatcher(&MojoWatcher::onHandleReady, &m_watcherHandle); |
+ DCHECK_EQ(MOJO_RESULT_OK, rv); |
+ |
+ m_context.reset(new CrossThreadPersistent<MojoWatcher>(this)); |
+ rv = MojoWatch(m_watcherHandle.get().value(), m_handle.value(), signals, |
+ reinterpret_cast<uintptr_t>(m_context.get())); |
+ if (rv != MOJO_RESULT_OK) { |
+ m_context.reset(); |
+ return rv; |
+ } |
+ |
+ MojoResult readyResult; |
+ rv = arm(&readyResult); |
+ if (rv == MOJO_RESULT_OK) |
+ return rv; |
+ |
+ // 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, rv); |
+ 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 rv = |
+ MojoArmWatcher(m_watcherHandle.get().value(), &numReadyContexts, |
+ &readyContext, &localReadyResult, &readySignals); |
+ if (rv == MOJO_RESULT_OK) |
+ return MOJO_RESULT_OK; |
+ |
+ DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); |
+ DCHECK_EQ(1u, numReadyContexts); |
+ DCHECK_EQ(reinterpret_cast<uintptr_t>(m_context.get()), readyContext); |
+ *readyResult = localReadyResult; |
+ return rv; |
+} |
+ |
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. |
- MojoWatcher* watcher = reinterpret_cast<MojoWatcher*>(context); |
- watcher->m_taskRunner->postTask( |
+ MojoWatcherNotificationFlags) { |
+ auto* watcher = |
+ reinterpret_cast<CrossThreadPersistent<MojoWatcher>*>(context); |
+ (*watcher)->m_taskRunner->postTask( |
BLINK_FROM_HERE, |
- crossThreadBind(&MojoWatcher::runReadyCallback, |
- wrapCrossThreadWeakPersistent(watcher), result)); |
+ crossThreadBind(&MojoWatcher::runReadyCallback, *watcher, result)); |
} |
void MojoWatcher::runReadyCallback(MojoResult result) { |
@@ -116,13 +155,40 @@ void MojoWatcher::runReadyCallback(MojoResult result) { |
if (!m_handle.is_valid()) |
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) |
+ // MOJO_RESULT_CANCELLED indicates that the watch has been cancelled, either |
+ // explicitly or implicitly due to handle closure. The context object can be |
+ // safely deleted at this point. |
+ if (result == MOJO_RESULT_CANCELLED) { |
m_handle = mojo::Handle(); |
+ m_context.reset(); |
+ |
+ // If cancellation was due to an explicit |cancel()|, don't run the watch |
+ // callback for this notification. |
+ if (!m_watcherHandle.is_valid()) |
+ return; |
+ |
+ m_watcherHandle.reset(); |
+ runWatchCallback(m_callback, this, MOJO_RESULT_CANCELLED); |
+ 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 rv = arm(&readyResult); |
+ if (rv == MOJO_RESULT_OK) |
+ return; |
+ |
+ DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); |
+ |
+ m_taskRunner->postTask(BLINK_FROM_HERE, |
+ WTF::bind(&MojoWatcher::runReadyCallback, |
+ wrapPersistent(this), readyResult)); |
} |
} // namespace blink |