WorkerEventTarget.cpp (8138B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "WorkerEventTarget.h" 8 9 #include "WorkerPrivate.h" 10 #include "WorkerRunnable.h" 11 #include "mozilla/Logging.h" 12 #include "mozilla/dom/ReferrerInfo.h" 13 14 namespace mozilla::dom { 15 16 static mozilla::LazyLogModule sWorkerEventTargetLog("WorkerEventTarget"); 17 18 #ifdef LOG 19 # undef LOG 20 #endif 21 #ifdef LOGV 22 # undef LOGV 23 #endif 24 #define LOG(args) MOZ_LOG(sWorkerEventTargetLog, LogLevel::Debug, args); 25 #define LOGV(args) MOZ_LOG(sWorkerEventTargetLog, LogLevel::Verbose, args); 26 27 namespace { 28 29 class WrappedControlRunnable final : public WorkerControlRunnable { 30 nsCOMPtr<nsIRunnable> mInner; 31 32 ~WrappedControlRunnable() = default; 33 34 public: 35 WrappedControlRunnable(WorkerPrivate* aWorkerPrivate, 36 nsCOMPtr<nsIRunnable>&& aInner) 37 : WorkerControlRunnable("WrappedControlRunnable"), 38 mInner(std::move(aInner)) {} 39 40 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 41 // Silence bad assertions, this can be dispatched from any thread. 42 return true; 43 } 44 45 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 46 bool aDispatchResult) override { 47 // Silence bad assertions, this can be dispatched from any thread. 48 } 49 50 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { 51 mInner->Run(); 52 return true; 53 } 54 55 nsresult Cancel() override { 56 nsCOMPtr<nsICancelableRunnable> cr = do_QueryInterface(mInner); 57 58 // If the inner runnable is not cancellable, then just do the normal 59 // WorkerControlRunnable thing. This will end up calling Run(). 60 if (!cr) { 61 return Run(); 62 } 63 64 // Otherwise call the inner runnable's Cancel() and treat this like 65 // a WorkerRunnable cancel. We can't call WorkerControlRunnable::Cancel() 66 // in this case since that would result in both Run() and the inner 67 // Cancel() being called. 68 return cr->Cancel(); 69 } 70 71 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY 72 NS_IMETHOD GetName(nsACString& aName) override { 73 aName.AssignLiteral("WrappedControlRunnable("); 74 if (nsCOMPtr<nsINamed> named = do_QueryInterface(mInner)) { 75 nsAutoCString containedName; 76 named->GetName(containedName); 77 aName.Append(containedName); 78 } else { 79 aName.AppendLiteral("?"); 80 } 81 aName.AppendLiteral(")"); 82 return NS_OK; 83 } 84 #endif 85 }; 86 87 class WrappedDebuggerRunnable final : public WorkerDebuggerRunnable { 88 nsCOMPtr<nsIRunnable> mInner; 89 90 ~WrappedDebuggerRunnable() = default; 91 92 public: 93 WrappedDebuggerRunnable(WorkerPrivate* aWorkerPrivate, 94 nsCOMPtr<nsIRunnable>&& aInner) 95 : WorkerDebuggerRunnable("WrappedDebuggerRunnable"), 96 mInner(std::move(aInner)) {} 97 98 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 99 // Silence bad assertions, this can be dispatched from any thread. 100 return true; 101 } 102 103 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 104 bool aDispatchResult) override { 105 // Silence bad assertions, this can be dispatched from any thread. 106 } 107 108 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { 109 mInner->Run(); 110 return true; 111 } 112 113 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY 114 NS_IMETHOD GetName(nsACString& aName) override { 115 aName.AssignLiteral("WrappedDebuggerRunnable("); 116 if (nsCOMPtr<nsINamed> named = do_QueryInterface(mInner)) { 117 nsAutoCString containedName; 118 named->GetName(containedName); 119 aName.Append(containedName); 120 } else { 121 aName.AppendLiteral("?"); 122 } 123 aName.AppendLiteral(")"); 124 return NS_OK; 125 } 126 #endif 127 }; 128 129 } // anonymous namespace 130 131 NS_IMPL_ISUPPORTS(WorkerEventTarget, nsIEventTarget, nsISerialEventTarget) 132 133 WorkerEventTarget::WorkerEventTarget(WorkerPrivate* aWorkerPrivate, 134 Behavior aBehavior) 135 : mMutex("WorkerEventTarget"), 136 mWorkerPrivate(aWorkerPrivate), 137 mBehavior(aBehavior) { 138 LOG(("WorkerEventTarget::WorkerEventTarget [%p] aBehavior: %u", this, 139 (uint8_t)aBehavior)); 140 MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate); 141 } 142 143 void WorkerEventTarget::ForgetWorkerPrivate(WorkerPrivate* aWorkerPrivate) { 144 LOG(("WorkerEventTarget::ForgetWorkerPrivate [%p] aWorkerPrivate: %p", this, 145 aWorkerPrivate)); 146 MutexAutoLock lock(mMutex); 147 MOZ_DIAGNOSTIC_ASSERT(!mWorkerPrivate || mWorkerPrivate == aWorkerPrivate); 148 mWorkerPrivate = nullptr; 149 } 150 151 NS_IMETHODIMP 152 WorkerEventTarget::DispatchFromScript(nsIRunnable* aRunnable, 153 DispatchFlags aFlags) { 154 LOGV(("WorkerEventTarget::DispatchFromScript [%p] aRunnable: %p", this, 155 aRunnable)); 156 return Dispatch(do_AddRef(aRunnable), aFlags); 157 } 158 159 NS_IMETHODIMP 160 WorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable, 161 DispatchFlags aFlags) { 162 // NOTE: This dispatch implementation does not leak even if 163 // `NS_DISPATCH_FALLIBLE` is not set. 164 nsCOMPtr<nsIRunnable> runnable(aRunnable); 165 LOGV( 166 ("WorkerEventTarget::Dispatch [%p] aRunnable: %p", this, runnable.get())); 167 168 MutexAutoLock lock(mMutex); 169 170 if (!mWorkerPrivate) { 171 return NS_ERROR_FAILURE; 172 } 173 174 if (mBehavior == Behavior::DebuggerOnly) { 175 RefPtr<WorkerDebuggerRunnable> r = 176 new WrappedDebuggerRunnable(mWorkerPrivate, std::move(runnable)); 177 LOGV( 178 ("WorkerEventTarget::Dispatch [%p] Wrapped runnable as debugger " 179 "runnable(%p)", 180 this, r.get())); 181 if (!r->Dispatch(mWorkerPrivate)) { 182 LOGV( 183 ("WorkerEventTarget::Dispatch [%p] Dispatch as debugger runnable(%p) " 184 "fail", 185 this, r.get())); 186 return NS_ERROR_FAILURE; 187 } 188 return NS_OK; 189 } 190 191 if (mBehavior == Behavior::Hybrid) { 192 LOGV(("WorkerEventTarget::Dispatch [%p] Dispatch as normal runnable(%p)", 193 this, runnable.get())); 194 195 RefPtr<WorkerRunnable> r = 196 mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget()); 197 if (r->Dispatch(mWorkerPrivate)) { 198 return NS_OK; 199 } 200 runnable = std::move(r); 201 LOGV(( 202 "WorkerEventTarget::Dispatch [%p] Dispatch as normal runnable(%p) fail", 203 this, runnable.get())); 204 } 205 206 RefPtr<WorkerControlRunnable> r = 207 new WrappedControlRunnable(mWorkerPrivate, std::move(runnable)); 208 LOGV( 209 ("WorkerEventTarget::Dispatch [%p] Wrapped runnable as control " 210 "runnable(%p)", 211 this, r.get())); 212 if (!r->Dispatch(mWorkerPrivate)) { 213 LOGV( 214 ("WorkerEventTarget::Dispatch [%p] Dispatch as control runnable(%p) " 215 "fail", 216 this, r.get())); 217 return NS_ERROR_FAILURE; 218 } 219 220 return NS_OK; 221 } 222 223 NS_IMETHODIMP 224 WorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) { 225 return NS_ERROR_NOT_IMPLEMENTED; 226 } 227 228 NS_IMETHODIMP 229 WorkerEventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) { 230 NS_ENSURE_ARG(aTask); 231 232 MutexAutoLock lock(mMutex); 233 234 // If mWorkerPrivate is gone, the event target is already late during 235 // shutdown, return NS_ERROR_UNEXPECTED as documented in `nsIEventTarget.idl`. 236 if (!mWorkerPrivate) { 237 return NS_ERROR_UNEXPECTED; 238 } 239 240 return mWorkerPrivate->RegisterShutdownTask(aTask); 241 } 242 243 NS_IMETHODIMP 244 WorkerEventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) { 245 NS_ENSURE_ARG(aTask); 246 247 MutexAutoLock lock(mMutex); 248 249 if (!mWorkerPrivate) { 250 return NS_ERROR_UNEXPECTED; 251 } 252 253 return mWorkerPrivate->UnregisterShutdownTask(aTask); 254 } 255 256 NS_IMETHODIMP_(bool) 257 WorkerEventTarget::IsOnCurrentThreadInfallible() { 258 MutexAutoLock lock(mMutex); 259 260 if (!mWorkerPrivate) { 261 return false; 262 } 263 264 return mWorkerPrivate->IsOnCurrentThread(); 265 } 266 267 NS_IMETHODIMP 268 WorkerEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) { 269 MOZ_ASSERT(aIsOnCurrentThread); 270 *aIsOnCurrentThread = IsOnCurrentThreadInfallible(); 271 return NS_OK; 272 } 273 274 } // namespace mozilla::dom