WorkerRunnable.h (20267B)
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 #ifndef mozilla_dom_workers_workerrunnable_h__ 8 #define mozilla_dom_workers_workerrunnable_h__ 9 10 #include <utility> 11 12 #include "MainThreadUtils.h" 13 #include "mozilla/RefPtr.h" 14 #include "mozilla/dom/WorkerPrivate.h" 15 #include "mozilla/dom/WorkerRef.h" 16 #include "mozilla/dom/WorkerStatus.h" 17 #include "mozilla/dom/quota/CheckedUnsafePtr.h" 18 #include "nsCOMPtr.h" 19 #include "nsIRunnable.h" 20 #include "nsISupports.h" 21 #include "nsStringFwd.h" 22 #include "nsThreadUtils.h" 23 #include "nscore.h" 24 25 struct JSContext; 26 class nsIEventTarget; 27 class nsIGlobalObject; 28 29 namespace mozilla { 30 31 class ErrorResult; 32 33 namespace dom { 34 35 class Worker; 36 37 class WorkerRunnable : public nsIRunnable 38 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY 39 , 40 public nsINamed 41 #endif 42 { 43 protected: 44 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY 45 const char* mName = nullptr; 46 #endif 47 48 public: 49 NS_DECL_THREADSAFE_ISUPPORTS 50 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY 51 NS_DECL_NSINAMED 52 #endif 53 54 virtual nsresult Cancel() = 0; 55 56 // The return value is true if and only if both PreDispatch and 57 // DispatchInternal return true. 58 virtual bool Dispatch(WorkerPrivate* aWorkerPrivate); 59 60 // True if this runnable is handled by running JavaScript in some global that 61 // could possibly be a debuggee, and thus needs to be deferred when the target 62 // is paused in the debugger, until the JavaScript invocation in progress has 63 // run to completion. Examples are MessageEventRunnable and 64 // ReportErrorRunnable. These runnables are segregated into separate 65 // ThrottledEventQueues, which the debugger pauses. 66 // 67 // Note that debugger runnables do not fall in this category, since we don't 68 // support debugging the debugger server at the moment. 69 virtual bool IsDebuggeeRunnable() const { return false; } 70 71 // True if this runnable needs to be dispatched to 72 // WorkerPrivate::mControlEventTareget. 73 virtual bool IsControlRunnable() const { return false; } 74 75 // True if this runnable should be dispatched to the debugger queue, 76 // and false otherwise. 77 virtual bool IsDebuggerRunnable() const { return false; } 78 79 static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable); 80 81 protected: 82 explicit WorkerRunnable(const char* aName = "WorkerRunnable") 83 #ifdef DEBUG 84 ; 85 #else 86 # ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY 87 : mName(aName) 88 # endif 89 { 90 } 91 #endif 92 93 // This class is reference counted. 94 virtual ~WorkerRunnable() = default; 95 96 // Calling Run() directly is not supported. Just call Dispatch() and 97 // WorkerRun() will be called on the correct thread automatically. 98 NS_DECL_NSIRUNNABLE 99 100 // By default asserts that Dispatch() is being called on the right thread 101 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) = 0; 102 103 // By default asserts that Dispatch() is being called on the right thread 104 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 105 bool aDispatchResult) = 0; 106 107 virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) = 0; 108 109 // May be implemented by subclasses if desired if they need to do some sort of 110 // setup before we try to set up our JSContext and compartment for real. 111 // Typically the only thing that should go in here is creation of the worker's 112 // global. 113 // 114 // If false is returned, WorkerRun will not be called at all. PostRun will 115 // still be called, with false passed for aRunResult. 116 virtual bool PreRun(WorkerPrivate* aWorkerPrivate) = 0; 117 118 // Must be implemented by subclasses. Called on the target thread. The return 119 // value will be passed to PostRun(). The JSContext passed in here comes from 120 // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. 121 // 122 // If the runnable is for parent thread, aCx is in the compartment of 123 // mWorkerPrivate's reflector (i.e. the worker object in the parent thread), 124 // unless that reflector is null, in which case it's in the compartment of the 125 // parent global (which is the compartment reflector would have been in), or 126 // in the null compartment if there is no parent global. 127 // 128 // For runnables on the worker thread, aCx is in whatever 129 // compartment GetCurrentWorkerThreadJSContext() was in when 130 // nsIRunnable::Run() got called. This is actually important for cases when a 131 // runnable spins a syncloop and wants everything that happens during the 132 // syncloop to happen in the compartment that runnable set up (which may, for 133 // example, be a debugger sandbox compartment!). If aCx wasn't in a 134 // compartment to start with, aCx will be in either the debugger global's 135 // compartment or the worker's global's compartment depending on whether 136 // IsDebuggerRunnable() is true. 137 // 138 // Immediately after WorkerRun returns, the caller will assert that either it 139 // returns false or there is no exception pending on aCx. Then it will report 140 // any pending exceptions on aCx. 141 virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0; 142 143 // By default asserts that Run() (and WorkerRun()) were called on the correct 144 // thread. 145 // 146 // The aCx passed here is the same one as was passed to WorkerRun and is 147 // still in the same compartment. PostRun implementations must NOT leave an 148 // exception on the JSContext and must not run script, because the incoming 149 // JSContext may be in the null compartment. 150 virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 151 bool aRunResult) = 0; 152 }; 153 154 class WorkerParentThreadRunnable : public WorkerRunnable { 155 public: 156 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentThreadRunnable, 157 WorkerRunnable) 158 159 virtual nsresult Cancel() override; 160 161 protected: 162 explicit WorkerParentThreadRunnable( 163 const char* aName = "WorkerParentThreadRunnable"); 164 165 // This class is reference counted. 166 virtual ~WorkerParentThreadRunnable(); 167 168 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override; 169 170 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 171 bool aDispatchResult) override; 172 173 virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override; 174 175 virtual bool WorkerRun(JSContext* aCx, 176 WorkerPrivate* aWorkerPrivate) override = 0; 177 178 virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 179 bool aRunResult) override; 180 181 virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final; 182 183 // Calling Run() directly is not supported. Just call Dispatch() and 184 // WorkerRun() will be called on the correct thread automatically. 185 NS_DECL_NSIRUNNABLE 186 187 private: 188 RefPtr<WorkerParentRef> mWorkerParentRef; 189 }; 190 191 class WorkerParentControlRunnable : public WorkerParentThreadRunnable { 192 friend class WorkerPrivate; 193 194 protected: 195 explicit WorkerParentControlRunnable( 196 const char* aName = "WorkerParentControlRunnable"); 197 198 virtual ~WorkerParentControlRunnable(); 199 200 nsresult Cancel() override; 201 202 public: 203 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentControlRunnable, 204 WorkerParentThreadRunnable) 205 206 private: 207 bool IsControlRunnable() const override { return true; } 208 209 // Should only be called by WorkerPrivate::DoRunLoop. 210 using WorkerParentThreadRunnable::Cancel; 211 }; 212 213 class WorkerParentDebuggeeRunnable : public WorkerParentThreadRunnable { 214 protected: 215 explicit WorkerParentDebuggeeRunnable( 216 const char* aName = "WorkerParentDebuggeeRunnable") 217 : WorkerParentThreadRunnable(aName) {} 218 219 private: 220 // This override is deliberately private: it doesn't make sense to call it if 221 // we know statically that we are a WorkerDebuggeeRunnable. 222 bool IsDebuggeeRunnable() const override { return true; } 223 }; 224 225 class WorkerThreadRunnable : public WorkerRunnable { 226 friend class WorkerPrivate; 227 228 public: 229 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerThreadRunnable, WorkerRunnable) 230 231 virtual nsresult Cancel() override; 232 233 protected: 234 explicit WorkerThreadRunnable(const char* aName = "WorkerThreadRunnable"); 235 236 // This class is reference counted. 237 virtual ~WorkerThreadRunnable() = default; 238 239 nsIGlobalObject* DefaultGlobalObject(WorkerPrivate* aWorkerPrivate) const; 240 241 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override; 242 243 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 244 bool aDispatchResult) override; 245 246 virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override; 247 248 virtual bool WorkerRun(JSContext* aCx, 249 WorkerPrivate* aWorkerPrivate) override = 0; 250 251 virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, 252 bool aRunResult) override; 253 254 virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override; 255 256 // Calling Run() directly is not supported. Just call Dispatch() and 257 // WorkerRun() will be called on the correct thread automatically. 258 NS_DECL_NSIRUNNABLE 259 260 // Whether or not Cancel() is currently being called from inside the Run() 261 // method. Avoids infinite recursion when a subclass calls Run() from inside 262 // Cancel(). Only checked and modified on the target thread. 263 bool mCallingCancelWithinRun; 264 265 bool mCleanPreStartDispatching{false}; 266 }; 267 268 // This runnable is used to send a message to a worker debugger. 269 class WorkerDebuggerRunnable : public WorkerThreadRunnable { 270 protected: 271 explicit WorkerDebuggerRunnable(const char* aName = "WorkerDebuggerRunnable") 272 : WorkerThreadRunnable(aName) {} 273 274 virtual ~WorkerDebuggerRunnable() = default; 275 276 private: 277 virtual bool IsDebuggerRunnable() const override { return true; } 278 279 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 280 AssertIsOnMainThread(); 281 282 return true; 283 } 284 285 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 286 bool aDispatchResult) override; 287 }; 288 289 // This runnable is used to send a message directly to a worker's sync loop. 290 class WorkerSyncRunnable : public WorkerThreadRunnable { 291 protected: 292 nsCOMPtr<nsIEventTarget> mSyncLoopTarget; 293 294 // Passing null for aSyncLoopTarget is allowed and will result in the behavior 295 // of a normal WorkerThreadRunnable. 296 explicit WorkerSyncRunnable(nsIEventTarget* aSyncLoopTarget, 297 const char* aName = "WorkerSyncRunnable"); 298 299 explicit WorkerSyncRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, 300 const char* aName = "WorkerSyncRunnable"); 301 302 virtual ~WorkerSyncRunnable(); 303 304 virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override; 305 }; 306 307 // This runnable is identical to WorkerSyncRunnable except it is meant to be 308 // created on and dispatched from the main thread only. Its WorkerRun/PostRun 309 // will run on the worker thread. 310 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable { 311 protected: 312 // Passing null for aSyncLoopTarget is allowed and will result in the behavior 313 // of a normal WorkerThreadRunnable. 314 explicit MainThreadWorkerSyncRunnable( 315 nsIEventTarget* aSyncLoopTarget, 316 const char* aName = "MainThreadWorkerSyncRunnable") 317 : WorkerSyncRunnable(aSyncLoopTarget, aName) { 318 AssertIsOnMainThread(); 319 } 320 321 explicit MainThreadWorkerSyncRunnable( 322 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, 323 const char* aName = "MainThreadWorkerSyncRunnable") 324 : WorkerSyncRunnable(std::move(aSyncLoopTarget), aName) { 325 AssertIsOnMainThread(); 326 } 327 328 virtual ~MainThreadWorkerSyncRunnable() = default; 329 330 private: 331 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 332 AssertIsOnMainThread(); 333 return true; 334 } 335 336 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 337 bool aDispatchResult) override; 338 }; 339 340 // This runnable is processed as soon as it is received by the worker, 341 // potentially running before previously queued runnables and perhaps even with 342 // other JS code executing on the stack. These runnables must not alter the 343 // state of the JS runtime and should only twiddle state values. 344 class WorkerControlRunnable : public WorkerThreadRunnable { 345 friend class WorkerPrivate; 346 347 protected: 348 explicit WorkerControlRunnable(const char* aName = "WorkerControlRunnable"); 349 350 virtual ~WorkerControlRunnable() = default; 351 352 nsresult Cancel() override; 353 354 public: 355 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, 356 WorkerThreadRunnable) 357 358 private: 359 bool IsControlRunnable() const override { return true; } 360 361 // Should only be called by WorkerPrivate::DoRunLoop. 362 using WorkerThreadRunnable::Cancel; 363 }; 364 365 // A convenience class for WorkerThreadRunnables that are originated on the main 366 // thread. 367 class MainThreadWorkerRunnable : public WorkerThreadRunnable { 368 protected: 369 explicit MainThreadWorkerRunnable( 370 const char* aName = "MainThreadWorkerRunnable") 371 : WorkerThreadRunnable(aName) { 372 AssertIsOnMainThread(); 373 } 374 375 virtual ~MainThreadWorkerRunnable() = default; 376 377 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 378 AssertIsOnMainThread(); 379 return true; 380 } 381 382 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 383 bool aDispatchResult) override { 384 AssertIsOnMainThread(); 385 } 386 }; 387 388 // A convenience class for WorkerControlRunnables that originate on the main 389 // thread. 390 class MainThreadWorkerControlRunnable : public WorkerControlRunnable { 391 protected: 392 explicit MainThreadWorkerControlRunnable( 393 const char* aName = "MainThreadWorkerControlRunnable") 394 : WorkerControlRunnable(aName) {} 395 396 virtual ~MainThreadWorkerControlRunnable() = default; 397 398 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { 399 AssertIsOnMainThread(); 400 return true; 401 } 402 403 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 404 bool aDispatchResult) override { 405 AssertIsOnMainThread(); 406 } 407 }; 408 409 // A WorkerThreadRunnable that should be dispatched from the worker to itself 410 // for async tasks. 411 // 412 // Async tasks will almost always want to use this since 413 // a WorkerSameThreadRunnable keeps the Worker from being GCed. 414 class WorkerSameThreadRunnable : public WorkerThreadRunnable { 415 protected: 416 explicit WorkerSameThreadRunnable( 417 const char* aName = "WorkerSameThreadRunnable") 418 : WorkerThreadRunnable(aName) {} 419 420 virtual ~WorkerSameThreadRunnable() = default; 421 422 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override; 423 424 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 425 bool aDispatchResult) override; 426 427 // We just delegate PostRun to WorkerThreadRunnable, since it does exactly 428 // what we want. 429 }; 430 431 // Base class for the runnable objects, which makes a synchronous call to 432 // dispatch the tasks from the worker thread to the main thread. 433 // 434 // Note that the derived class must override MainThreadRun. 435 class WorkerMainThreadRunnable : public Runnable { 436 protected: 437 RefPtr<ThreadSafeWorkerRef> mWorkerRef; 438 nsCOMPtr<nsISerialEventTarget> mSyncLoopTarget; 439 const nsCString mTelemetryKey; 440 const char* mName; 441 442 explicit WorkerMainThreadRunnable( 443 WorkerPrivate* aWorkerPrivate, const nsACString& aTelemetryKey, 444 const char* aName = "WorkerMainThreadRunnable"); 445 446 ~WorkerMainThreadRunnable(); 447 448 virtual bool MainThreadRun() = 0; 449 450 public: 451 // Dispatch the runnable to the main thread. If dispatch to main thread 452 // fails, or if the worker is in a state equal or greater of aFailStatus, an 453 // error will be reported on aRv. Normally you want to use 'Canceling' for 454 // aFailStatus, except if you want an infallible runnable. In this case, use 455 // 'Killing'. 456 // In that case the error MUST be propagated out to script. 457 void Dispatch(WorkerPrivate* aWorkerPrivate, WorkerStatus aFailStatus, 458 ErrorResult& aRv); 459 460 private: 461 NS_IMETHOD Run() override; 462 }; 463 464 // This runnable is an helper class for dispatching something from a worker 465 // thread to the main-thread and back to the worker-thread. During this 466 // operation, this class will keep the worker alive. 467 // The purpose of RunBackOnWorkerThreadForCleanup() must be used, as the name 468 // says, only to release resources, no JS has to be executed, no timers, or 469 // other things. The reason of such limitations is that, in order to execute 470 // this method in any condition (also when the worker is shutting down), a 471 // Control Runnable is used, and, this could generate a reordering of existing 472 // runnables. 473 class WorkerProxyToMainThreadRunnable : public Runnable { 474 protected: 475 WorkerProxyToMainThreadRunnable(); 476 477 virtual ~WorkerProxyToMainThreadRunnable(); 478 479 // First this method is called on the main-thread. 480 virtual void RunOnMainThread(WorkerPrivate* aWorkerPrivate) = 0; 481 482 // After this second method is called on the worker-thread. 483 virtual void RunBackOnWorkerThreadForCleanup( 484 WorkerPrivate* aWorkerPrivate) = 0; 485 486 public: 487 bool Dispatch(WorkerPrivate* aWorkerPrivate); 488 489 virtual bool ForMessaging() const { return false; } 490 491 private: 492 NS_IMETHOD Run() override; 493 494 void PostDispatchOnMainThread(); 495 496 void ReleaseWorker(); 497 498 RefPtr<ThreadSafeWorkerRef> mWorkerRef; 499 }; 500 501 // This runnable is used to stop a sync loop and it's meant to be used on the 502 // main-thread only. 503 class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable { 504 nsresult mResult; 505 506 public: 507 // Passing null for aSyncLoopTarget is not allowed. 508 MainThreadStopSyncLoopRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, 509 nsresult aResult); 510 511 // By default StopSyncLoopRunnables cannot be canceled since they could leave 512 // a sync loop spinning forever. 513 nsresult Cancel() override; 514 515 protected: 516 virtual ~MainThreadStopSyncLoopRunnable() = default; 517 518 private: 519 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final { 520 AssertIsOnMainThread(); 521 return true; 522 } 523 524 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, 525 bool aDispatchResult) override; 526 527 virtual bool WorkerRun(JSContext* aCx, 528 WorkerPrivate* aWorkerPrivate) override; 529 530 bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final; 531 }; 532 533 // Runnables handled by content JavaScript (MessageEventRunnable, JavaScript 534 // error reports, and so on) must not be delivered while that content is in the 535 // midst of being debugged; the debuggee must be allowed to complete its current 536 // JavaScript invocation and return to its own event loop. Only then is it 537 // prepared for messages sent from the worker. 538 // 539 // Runnables that need to be deferred in this way should inherit from this 540 // class. They will be routed to mMainThreadDebuggeeEventTarget, which is paused 541 // while the window is suspended, as it is whenever the debugger spins its 542 // nested event loop. When the debugger leaves its nested event loop, it resumes 543 // the window, so that mMainThreadDebuggeeEventTarget will resume delivering 544 // runnables from the worker when control returns to the main event loop. 545 // 546 // When a page enters the bfcache, it freezes all its workers. Since a frozen 547 // worker processes only control runnables, it doesn't take any special 548 // consideration to prevent WorkerDebuggeeRunnables sent from child to parent 549 // workers from running; they'll never run anyway. But WorkerDebuggeeRunnables 550 // from a top-level frozen worker to its parent window must not be delivered 551 // either, even as the main thread event loop continues to spin. Thus, freezing 552 // a top-level worker also pauses mMainThreadDebuggeeEventTarget. 553 class WorkerDebuggeeRunnable : public WorkerThreadRunnable { 554 protected: 555 explicit WorkerDebuggeeRunnable(const char* aName = "WorkerDebuggeeRunnable") 556 : WorkerThreadRunnable(aName) {} 557 558 private: 559 // This override is deliberately private: it doesn't make sense to call it if 560 // we know statically that we are a WorkerDebuggeeRunnable. 561 bool IsDebuggeeRunnable() const override { return true; } 562 }; 563 564 } // namespace dom 565 } // namespace mozilla 566 567 #endif // mozilla_dom_workers_workerrunnable_h__