| OLD | NEW | 
|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "core/mojo/MojoWatcher.h" | 5 #include "core/mojo/MojoWatcher.h" | 
| 6 | 6 | 
| 7 #include "bindings/core/v8/MojoWatchCallback.h" | 7 #include "bindings/core/v8/MojoWatchCallback.h" | 
| 8 #include "bindings/core/v8/ScriptState.h" | 8 #include "bindings/core/v8/ScriptState.h" | 
| 9 #include "core/dom/ExecutionContext.h" | 9 #include "core/dom/ExecutionContext.h" | 
| 10 #include "core/dom/ExecutionContextTask.h" | 10 #include "core/dom/ExecutionContextTask.h" | 
| 11 #include "core/dom/TaskRunnerHelper.h" | 11 #include "core/dom/TaskRunnerHelper.h" | 
| 12 #include "core/mojo/MojoHandleSignals.h" | 12 #include "core/mojo/MojoHandleSignals.h" | 
| 13 #include "platform/WebTaskRunner.h" | 13 #include "platform/WebTaskRunner.h" | 
| 14 | 14 | 
| 15 namespace blink { | 15 namespace blink { | 
| 16 | 16 | 
| 17 static void runWatchCallback(MojoWatchCallback* callback, | 17 static void runWatchCallback(MojoWatchCallback* callback, | 
| 18                              ScriptWrappable* wrappable, | 18                              ScriptWrappable* wrappable, | 
| 19                              MojoResult result) { | 19                              MojoResult result) { | 
| 20   callback->call(wrappable, result); | 20   callback->call(wrappable, result); | 
| 21 } | 21 } | 
| 22 | 22 | 
|  | 23 // static | 
| 23 MojoWatcher* MojoWatcher::create(mojo::Handle handle, | 24 MojoWatcher* MojoWatcher::create(mojo::Handle handle, | 
| 24                                  const MojoHandleSignals& signalsDict, | 25                                  const MojoHandleSignals& signalsDict, | 
| 25                                  MojoWatchCallback* callback, | 26                                  MojoWatchCallback* callback, | 
| 26                                  ExecutionContext* context) { | 27                                  ExecutionContext* context) { | 
| 27   MojoWatcher* watcher = new MojoWatcher(context, callback); | 28   MojoWatcher* watcher = new MojoWatcher(context, callback); | 
| 28   MojoResult result = watcher->watch(handle, signalsDict); | 29   MojoResult result = watcher->watch(handle, signalsDict); | 
| 29   // TODO(alokp): Consider raising an exception. | 30   // TODO(alokp): Consider raising an exception. | 
| 30   // Current clients expect to recieve the initial error returned by MojoWatch | 31   // Current clients expect to recieve the initial error returned by | 
| 31   // via watch callback. | 32   // MojoRegisterWatcher via watch callback. | 
| 32   // | 33   // | 
| 33   // Note that the usage of wrapPersistent is intentional so that the intial | 34   // Note that the usage of wrapPersistent is intentional so that the intial | 
| 34   // error is guaranteed to be reported to the client in case where the given | 35   // error is guaranteed to be reported to the client in case where the given | 
| 35   // handle is invalid and garbage collection happens before the callback | 36   // handle is invalid and garbage collection happens before the callback | 
| 36   // is scheduled. | 37   // is scheduled. | 
| 37   if (result != MOJO_RESULT_OK) { | 38   if (result != MOJO_RESULT_OK) { | 
| 38     watcher->m_taskRunner->postTask( | 39     watcher->m_taskRunner->postTask( | 
| 39         BLINK_FROM_HERE, WTF::bind(&runWatchCallback, wrapPersistent(callback), | 40         BLINK_FROM_HERE, WTF::bind(&runWatchCallback, wrapPersistent(callback), | 
| 40                                    wrapPersistent(watcher), result)); | 41                                    wrapPersistent(watcher), result)); | 
| 41   } | 42   } | 
|  | 43 | 
| 42   return watcher; | 44   return watcher; | 
| 43 } | 45 } | 
| 44 | 46 | 
| 45 MojoWatcher::MojoWatcher(ExecutionContext* context, MojoWatchCallback* callback) |  | 
| 46     : ContextLifecycleObserver(context), |  | 
| 47       m_taskRunner(TaskRunnerHelper::get(TaskType::UnspecedTimer, context)), |  | 
| 48       m_callback(this, callback) {} |  | 
| 49 |  | 
| 50 MojoWatcher::~MojoWatcher() { | 47 MojoWatcher::~MojoWatcher() { | 
| 51   DCHECK(!m_handle.is_valid()); | 48   DCHECK(!m_handle.is_valid()); | 
| 52 } | 49 } | 
| 53 | 50 | 
| 54 MojoResult MojoWatcher::watch(mojo::Handle handle, | 51 MojoResult MojoWatcher::cancel() { | 
| 55                               const MojoHandleSignals& signalsDict) { | 52   if (!m_watcherHandle.is_valid()) | 
| 56   ::MojoHandleSignals signals = MOJO_HANDLE_SIGNAL_NONE; | 53     return MOJO_RESULT_INVALID_ARGUMENT; | 
| 57   if (signalsDict.readable()) |  | 
| 58     signals |= MOJO_HANDLE_SIGNAL_READABLE; |  | 
| 59   if (signalsDict.writable()) |  | 
| 60     signals |= MOJO_HANDLE_SIGNAL_WRITABLE; |  | 
| 61   if (signalsDict.peerClosed()) |  | 
| 62     signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; |  | 
| 63 | 54 | 
| 64   MojoResult result = | 55   m_watcherHandle.reset(); | 
| 65       MojoWatch(handle.value(), signals, &MojoWatcher::onHandleReady, |  | 
| 66                 reinterpret_cast<uintptr_t>(this)); |  | 
| 67   if (result == MOJO_RESULT_OK) { |  | 
| 68     m_handle = handle; |  | 
| 69   } |  | 
| 70   return result; |  | 
| 71 } |  | 
| 72 |  | 
| 73 MojoResult MojoWatcher::cancel() { |  | 
| 74   if (!m_handle.is_valid()) |  | 
| 75     return MOJO_RESULT_OK; |  | 
| 76 |  | 
| 77   MojoResult result = |  | 
| 78       MojoCancelWatch(m_handle.value(), reinterpret_cast<uintptr_t>(this)); |  | 
| 79   m_handle = mojo::Handle(); | 56   m_handle = mojo::Handle(); | 
| 80   return result; | 57   return MOJO_RESULT_OK; | 
| 81 } | 58 } | 
| 82 | 59 | 
| 83 DEFINE_TRACE(MojoWatcher) { | 60 DEFINE_TRACE(MojoWatcher) { | 
| 84   visitor->trace(m_callback); | 61   visitor->trace(m_callback); | 
| 85   ContextLifecycleObserver::trace(visitor); | 62   ContextLifecycleObserver::trace(visitor); | 
| 86 } | 63 } | 
| 87 | 64 | 
| 88 DEFINE_TRACE_WRAPPERS(MojoWatcher) { | 65 DEFINE_TRACE_WRAPPERS(MojoWatcher) { | 
| 89   visitor->traceWrappers(m_callback); | 66   visitor->traceWrappers(m_callback); | 
| 90 } | 67 } | 
| 91 | 68 | 
| 92 bool MojoWatcher::hasPendingActivity() const { | 69 bool MojoWatcher::hasPendingActivity() const { | 
| 93   return m_handle.is_valid(); | 70   return !!m_context; | 
| 94 } | 71 } | 
| 95 | 72 | 
| 96 void MojoWatcher::contextDestroyed(ExecutionContext*) { | 73 void MojoWatcher::contextDestroyed(ExecutionContext*) { | 
| 97   cancel(); | 74   cancel(); | 
| 98 } | 75 } | 
| 99 | 76 | 
|  | 77 MojoWatcher::MojoWatcher(ExecutionContext* context, MojoWatchCallback* callback) | 
|  | 78     : ContextLifecycleObserver(context), | 
|  | 79       m_taskRunner(TaskRunnerHelper::get(TaskType::UnspecedTimer, context)), | 
|  | 80       m_callback(this, callback) {} | 
|  | 81 | 
|  | 82 MojoResult MojoWatcher::watch(mojo::Handle handle, | 
|  | 83                               const MojoHandleSignals& signalsDict) { | 
|  | 84   ::MojoHandleSignals signals = MOJO_HANDLE_SIGNAL_NONE; | 
|  | 85   if (signalsDict.readable()) | 
|  | 86     signals |= MOJO_HANDLE_SIGNAL_READABLE; | 
|  | 87   if (signalsDict.writable()) | 
|  | 88     signals |= MOJO_HANDLE_SIGNAL_WRITABLE; | 
|  | 89   if (signalsDict.peerClosed()) | 
|  | 90     signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; | 
|  | 91 | 
|  | 92   m_handle = handle; | 
|  | 93 | 
|  | 94   MojoResult rv = | 
|  | 95       mojo::CreateWatcher(&MojoWatcher::onHandleReady, &m_watcherHandle); | 
|  | 96   DCHECK_EQ(MOJO_RESULT_OK, rv); | 
|  | 97 | 
|  | 98   m_context.reset(new CrossThreadPersistent<MojoWatcher>(this)); | 
|  | 99   rv = MojoWatch(m_watcherHandle.get().value(), m_handle.value(), signals, | 
|  | 100                  reinterpret_cast<uintptr_t>(m_context.get())); | 
|  | 101   if (rv != MOJO_RESULT_OK) { | 
|  | 102     m_context.reset(); | 
|  | 103     return rv; | 
|  | 104   } | 
|  | 105 | 
|  | 106   MojoResult readyResult; | 
|  | 107   rv = arm(&readyResult); | 
|  | 108   if (rv == MOJO_RESULT_OK) | 
|  | 109     return rv; | 
|  | 110 | 
|  | 111   // We couldn't arm the watcher because the handle is already ready to | 
|  | 112   // trigger a success notification. Post a notification manually. | 
|  | 113   DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); | 
|  | 114   m_taskRunner->postTask(BLINK_FROM_HERE, | 
|  | 115                          WTF::bind(&MojoWatcher::runReadyCallback, | 
|  | 116                                    wrapPersistent(this), readyResult)); | 
|  | 117   return MOJO_RESULT_OK; | 
|  | 118 } | 
|  | 119 | 
|  | 120 MojoResult MojoWatcher::arm(MojoResult* readyResult) { | 
|  | 121   // Nothing to do if the watcher is inactive. | 
|  | 122   if (!m_handle.is_valid()) | 
|  | 123     return MOJO_RESULT_OK; | 
|  | 124 | 
|  | 125   uint32_t numReadyContexts = 1; | 
|  | 126   uintptr_t readyContext; | 
|  | 127   MojoResult localReadyResult; | 
|  | 128   MojoHandleSignalsState readySignals; | 
|  | 129   MojoResult rv = | 
|  | 130       MojoArmWatcher(m_watcherHandle.get().value(), &numReadyContexts, | 
|  | 131                      &readyContext, &localReadyResult, &readySignals); | 
|  | 132   if (rv == MOJO_RESULT_OK) | 
|  | 133     return MOJO_RESULT_OK; | 
|  | 134 | 
|  | 135   DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); | 
|  | 136   DCHECK_EQ(1u, numReadyContexts); | 
|  | 137   DCHECK_EQ(reinterpret_cast<uintptr_t>(m_context.get()), readyContext); | 
|  | 138   *readyResult = localReadyResult; | 
|  | 139   return rv; | 
|  | 140 } | 
|  | 141 | 
| 100 void MojoWatcher::onHandleReady(uintptr_t context, | 142 void MojoWatcher::onHandleReady(uintptr_t context, | 
| 101                                 MojoResult result, | 143                                 MojoResult result, | 
| 102                                 MojoHandleSignalsState, | 144                                 MojoHandleSignalsState, | 
| 103                                 MojoWatchNotificationFlags) { | 145                                 MojoWatcherNotificationFlags) { | 
| 104   // It is safe to assume the MojoWatcher still exists because this | 146   auto* watcher = | 
| 105   // callback will never be run after MojoWatcher destructor, | 147       reinterpret_cast<CrossThreadPersistent<MojoWatcher>*>(context); | 
| 106   // which cancels the watch. | 148   (*watcher)->m_taskRunner->postTask( | 
| 107   MojoWatcher* watcher = reinterpret_cast<MojoWatcher*>(context); |  | 
| 108   watcher->m_taskRunner->postTask( |  | 
| 109       BLINK_FROM_HERE, | 149       BLINK_FROM_HERE, | 
| 110       crossThreadBind(&MojoWatcher::runReadyCallback, | 150       crossThreadBind(&MojoWatcher::runReadyCallback, *watcher, result)); | 
| 111                       wrapCrossThreadWeakPersistent(watcher), result)); |  | 
| 112 } | 151 } | 
| 113 | 152 | 
| 114 void MojoWatcher::runReadyCallback(MojoResult result) { | 153 void MojoWatcher::runReadyCallback(MojoResult result) { | 
| 115   // Ignore callbacks if not watching. | 154   // Ignore callbacks if not watching. | 
| 116   if (!m_handle.is_valid()) | 155   if (!m_handle.is_valid()) | 
| 117     return; | 156     return; | 
| 118 | 157 | 
| 119   // MOJO_RESULT_CANCELLED indicates that the handle has been closed, in which | 158   // MOJO_RESULT_CANCELLED indicates that the watch has been cancelled, either | 
| 120   // case watch has been implicitly cancelled. There is no need to explicitly | 159   // explicitly or implicitly due to handle closure. The context object can be | 
| 121   // cancel the watch. | 160   // safely deleted at this point. | 
| 122   if (result == MOJO_RESULT_CANCELLED) | 161   if (result == MOJO_RESULT_CANCELLED) { | 
| 123     m_handle = mojo::Handle(); | 162     m_handle = mojo::Handle(); | 
|  | 163     m_context.reset(); | 
|  | 164 | 
|  | 165     // If cancellation was due to an explicit |cancel()|, don't run the watch | 
|  | 166     // callback for this notification. | 
|  | 167     if (!m_watcherHandle.is_valid()) | 
|  | 168       return; | 
|  | 169 | 
|  | 170     m_watcherHandle.reset(); | 
|  | 171     runWatchCallback(m_callback, this, MOJO_RESULT_CANCELLED); | 
|  | 172     return; | 
|  | 173   } | 
| 124 | 174 | 
| 125   runWatchCallback(m_callback, this, result); | 175   runWatchCallback(m_callback, this, result); | 
|  | 176 | 
|  | 177   // Rearm the watcher so another notification can fire. | 
|  | 178   // | 
|  | 179   // TODO(rockot): MojoWatcher should expose some better approximation of the | 
|  | 180   // new watcher API, including explicit add and removal of handles from the | 
|  | 181   // watcher, as well as explicit arming. | 
|  | 182   MojoResult readyResult; | 
|  | 183   MojoResult rv = arm(&readyResult); | 
|  | 184   if (rv == MOJO_RESULT_OK) | 
|  | 185     return; | 
|  | 186 | 
|  | 187   DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); | 
|  | 188 | 
|  | 189   m_taskRunner->postTask(BLINK_FROM_HERE, | 
|  | 190                          WTF::bind(&MojoWatcher::runReadyCallback, | 
|  | 191                                    wrapPersistent(this), readyResult)); | 
| 126 } | 192 } | 
| 127 | 193 | 
| 128 }  // namespace blink | 194 }  // namespace blink | 
| OLD | NEW | 
|---|