WorkerPrivate.h (61211B)
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_workerprivate_h__ 8 #define mozilla_dom_workers_workerprivate_h__ 9 10 #include <bitset> 11 12 #include "FontVisibilityProvider.h" 13 #include "MainThreadUtils.h" 14 #include "ScriptLoader.h" 15 #include "js/ContextOptions.h" 16 #include "mozilla/Atomics.h" 17 #include "mozilla/Attributes.h" 18 #include "mozilla/AutoRestore.h" 19 #include "mozilla/BasePrincipal.h" 20 #include "mozilla/CondVar.h" 21 #include "mozilla/DOMEventTargetHelper.h" 22 #include "mozilla/Maybe.h" 23 #include "mozilla/MozPromise.h" 24 #include "mozilla/OriginTrials.h" 25 #include "mozilla/RelativeTimeline.h" 26 #include "mozilla/Result.h" 27 #include "mozilla/StaticPrefs_extensions.h" 28 #include "mozilla/StorageAccess.h" 29 #include "mozilla/TargetShutdownTaskSet.h" 30 #include "mozilla/ThreadBound.h" 31 #include "mozilla/UniquePtr.h" 32 #include "mozilla/UseCounter.h" 33 #include "mozilla/dom/ClientSource.h" 34 #include "mozilla/dom/FlippedOnce.h" 35 #include "mozilla/dom/JSExecutionManager.h" 36 #include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h" 37 #include "mozilla/dom/RemoteWorkerTypes.h" 38 #include "mozilla/dom/Timeout.h" 39 #include "mozilla/dom/Worker.h" 40 #include "mozilla/dom/WorkerBinding.h" 41 #include "mozilla/dom/WorkerCommon.h" 42 #include "mozilla/dom/WorkerLoadInfo.h" 43 #include "mozilla/dom/WorkerStatus.h" 44 #include "mozilla/dom/quota/CheckedUnsafePtr.h" 45 #include "mozilla/dom/workerinternals/JSSettings.h" 46 #include "mozilla/dom/workerinternals/Queue.h" 47 #include "mozilla/ipc/Endpoint.h" 48 #include "mozilla/net/NeckoChannelParams.h" 49 #include "nsContentUtils.h" 50 #include "nsIChannel.h" 51 #include "nsIContentPolicy.h" 52 #include "nsID.h" 53 #include "nsIEventTarget.h" 54 #include "nsILoadInfo.h" 55 #include "nsRFPService.h" 56 #include "nsTObserverArray.h" 57 #include "stdint.h" 58 59 class nsIContentSecurityPolicy; 60 class nsIThreadInternal; 61 62 namespace JS { 63 struct RuntimeStats; 64 class Dispatchable; 65 } // namespace JS 66 67 namespace mozilla { 68 class ThrottledEventQueue; 69 namespace dom { 70 71 class PRemoteWorkerDebuggerChild; 72 class PRemoteWorkerDebuggerParent; 73 class RemoteWorkerChild; 74 class RemoteWorkerDebuggerChild; 75 class RemoteWorkerNonLifeCycleOpControllerChild; 76 77 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs 78 // to be updated too. And histograms enum for worker use counters uses the same 79 // order of worker kind. Please also update dom/base/usecounters.py. 80 enum WorkerKind : uint8_t { 81 WorkerKindDedicated, 82 WorkerKindShared, 83 WorkerKindService 84 }; 85 86 class ClientInfo; 87 class ClientSource; 88 class Function; 89 class JSExecutionManager; 90 class MessagePort; 91 class UniqueMessagePortId; 92 class PerformanceStorage; 93 class StrongWorkerRef; 94 class TimeoutHandler; 95 class WorkerControlRunnable; 96 class WorkerCSPEventListener; 97 class WorkerDebugger; 98 class WorkerDebuggerGlobalScope; 99 class WorkerErrorReport; 100 class WorkerEventTarget; 101 class WorkerGlobalScope; 102 class WorkerParentRef; 103 class WorkerRef; 104 class WorkerRunnable; 105 class WorkerDebuggeeRunnable; 106 class WorkerThread; 107 class WorkerThreadRunnable; 108 109 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex 110 // object. It exists to avoid changing a lot of code to use Mutex* instead of 111 // Mutex&. 112 class MOZ_CAPABILITY("mutex") SharedMutex { 113 using Mutex = mozilla::Mutex; 114 115 class MOZ_CAPABILITY("mutex") RefCountedMutex final : public Mutex { 116 public: 117 explicit RefCountedMutex(const char* aName) : Mutex(aName) {} 118 119 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex) 120 121 private: 122 ~RefCountedMutex() = default; 123 }; 124 125 const RefPtr<RefCountedMutex> mMutex; 126 127 public: 128 explicit SharedMutex(const char* aName) 129 : mMutex(new RefCountedMutex(aName)) {} 130 131 SharedMutex(const SharedMutex& aOther) = default; 132 133 operator Mutex&() MOZ_RETURN_CAPABILITY(this) { return *mMutex; } 134 135 operator const Mutex&() const MOZ_RETURN_CAPABILITY(this) { return *mMutex; } 136 137 // We need these to make thread-safety analysis work 138 void Lock() MOZ_CAPABILITY_ACQUIRE() { mMutex->Lock(); } 139 void Unlock() MOZ_CAPABILITY_RELEASE() { mMutex->Unlock(); } 140 141 // We can assert we own 'this', but we can't assert we hold mMutex 142 void AssertCurrentThreadOwns() const 143 MOZ_ASSERT_CAPABILITY(this) MOZ_NO_THREAD_SAFETY_ANALYSIS { 144 mMutex->AssertCurrentThreadOwns(); 145 } 146 }; 147 148 nsString ComputeWorkerPrivateId(); 149 150 class WorkerPrivate final 151 : public RelativeTimeline, 152 public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>>, 153 public FontVisibilityProvider { 154 public: 155 // Callback invoked on the parent thread when the worker's cancellation is 156 // about to be requested. This covers both calls to 157 // WorkerPrivate::Cancel() by the owner as well as self-initiated cancellation 158 // due to top-level script evaluation failing or close() being invoked on the 159 // global scope for Dedicated and Shared workers, but not Service Workers as 160 // they do not expose a close() method. 161 // 162 // ### Parent-Initiated Cancellation 163 // 164 // When WorkerPrivate::Cancel is invoked on the parent thread (by the binding 165 // exposed Worker::Terminate), this callback is invoked synchronously inside 166 // that call. 167 // 168 // ### Worker Self-Cancellation 169 // 170 // When a worker initiates self-cancellation, the worker's notification to the 171 // parent thread is a non-blocking, async mechanism triggered by 172 // `WorkerPrivate::DispatchCancelingRunnable`. 173 // 174 // Self-cancellation races a normally scheduled runnable against a timer that 175 // is scheduled against the parent. The 2 paths initiated by 176 // DispatchCancelingRunnable are: 177 // 178 // 1. A CancelingRunnable is dispatched at the worker's normal event target to 179 // wait for the event loop to be clear of runnables. When the 180 // CancelingRunnable runs it will dispatch a CancelingOnParentRunnable to 181 // its parent which is a normal, non-control WorkerDebuggeeRunnable to 182 // ensure that any postMessages to the parent or similar events get a 183 // chance to be processed prior to cancellation. The timer scheduled in 184 // the next bullet will not be canceled unless 185 // 186 // 2. A CancelingWithTimeoutOnParentRunnable control runnable is dispatched 187 // to the parent to schedule a timer which will (also) fire on the parent 188 // thread. This handles the case where the worker does not yield 189 // control-flow, and so the normal runnable scheduled above does not get to 190 // run in a timely fashion. Because this is a control runnable, if the 191 // parent is a worker then the runnable will be processed with urgency. 192 // However, if the worker is top-level, then the control-like throttled 193 // WorkerPrivate::mMainThreadEventTarget will end up getting used which is 194 // nsIRunnablePriority::PRIORITY_MEDIUMHIGH and distinct from the 195 // mMainThreadDebuggeeEventTarget which most runnables (like postMessage) 196 // use. 197 // 198 // The timer will explicitly use the control event target if the parent is 199 // a worker and the implicit event target (via `NS_NewTimer()`) otherwise. 200 // The callback is CancelingTimerCallback which just calls 201 // WorkerPrivate::Cancel. 202 using CancellationCallback = std::function<void(bool aEverRan)>; 203 204 // Callback invoked on the parent just prior to dropping the worker thread's 205 // strong reference that keeps the WorkerPrivate alive while the worker thread 206 // is running. This does not provide a guarantee that the underlying thread 207 // has fully shutdown, just that the worker logic has fully shutdown. 208 // 209 // ### Details 210 // 211 // The last thing the worker thread's WorkerThreadPrimaryRunnable does before 212 // initiating the shutdown of the underlying thread is call ScheduleDeletion. 213 // ScheduleDeletion dispatches a runnable to the parent to notify it that the 214 // worker has completed its work and will never touch the WorkerPrivate again 215 // and that the strong self-reference can be dropped. 216 // 217 // For parents that are themselves workers, this will be done by 218 // WorkerFinishedRunnable which is a WorkerControlRunnable, ensuring that this 219 // is processed in a timely fashion. For main-thread parents, 220 // TopLevelWorkerFinishedRunnable will be used and sent via 221 // mMainThreadEventTargetForMessaging which is a weird ThrottledEventQueue 222 // which does not provide any ordering guarantees relative to 223 // mMainThreadDebuggeeEventTarget, so if you want those, you need to enhance 224 // things. 225 using TerminationCallback = std::function<void(void)>; 226 227 struct LocationInfo { 228 nsCString mHref; 229 nsCString mProtocol; 230 nsCString mHost; 231 nsCString mHostname; 232 nsCString mPort; 233 nsCString mPathname; 234 nsCString mSearch; 235 nsCString mHash; 236 nsString mOrigin; 237 }; 238 239 NS_INLINE_DECL_REFCOUNTING(WorkerPrivate) 240 241 FONT_VISIBILITY_PROVIDER_IMPL 242 243 static already_AddRefed<WorkerPrivate> Constructor( 244 JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker, 245 WorkerKind aWorkerKind, RequestCredentials aRequestCredentials, 246 const WorkerType aWorkerType, const nsAString& aWorkerName, 247 const nsACString& aServiceWorkerScope, WorkerLoadInfo* aLoadInfo, 248 ErrorResult& aRv, nsString aId = u""_ns, 249 CancellationCallback&& aCancellationCallback = {}, 250 TerminationCallback&& aTerminationCallback = {}, 251 mozilla::ipc::Endpoint< 252 PRemoteWorkerNonLifeCycleOpControllerChild>&& aChildEp = 253 mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>()); 254 255 enum LoadGroupBehavior { InheritLoadGroup, OverrideLoadGroup }; 256 257 static nsresult GetLoadInfo( 258 JSContext* aCx, nsPIDOMWindowInner* aWindow, WorkerPrivate* aParent, 259 const nsAString& aScriptURL, const enum WorkerType& aWorkerType, 260 const RequestCredentials& aCredentials, bool aIsChromeWorker, 261 LoadGroupBehavior aLoadGroupBehavior, WorkerKind aWorkerKind, 262 WorkerLoadInfo* aLoadInfo); 263 264 void Traverse(nsCycleCollectionTraversalCallback& aCb); 265 266 void ClearSelfAndParentEventTargetRef() { 267 AssertIsOnParentThread(); 268 MOZ_ASSERT(mSelfRef); 269 270 if (mTerminationCallback) { 271 mTerminationCallback(); 272 mTerminationCallback = nullptr; 273 } 274 275 mParentEventTargetRef = nullptr; 276 mSelfRef = nullptr; 277 } 278 279 // May be called on any thread... 280 bool Start(); 281 282 // Called on the parent thread. 283 bool Notify(WorkerStatus aStatus); 284 285 bool Cancel() { return Notify(Canceling); } 286 287 bool Close() MOZ_REQUIRES(mMutex); 288 289 // The passed principal must be the Worker principal in case of a 290 // ServiceWorker and the loading principal for any other type. 291 static void OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo, 292 nsIPrincipal* aPrincipal); 293 294 bool IsDebuggerRegistered() MOZ_NO_THREAD_SAFETY_ANALYSIS { 295 AssertIsOnMainThread(); 296 297 // No need to lock here since this is only ever modified by the same thread. 298 return mDebuggerRegistered; // would give a thread-safety warning 299 } 300 301 bool ExtensionAPIAllowed() { 302 return ( 303 StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup() && 304 mExtensionAPIAllowed); 305 } 306 307 void SetIsDebuggerRegistered(bool aDebuggerRegistered) { 308 AssertIsOnMainThread(); 309 310 MutexAutoLock lock(mMutex); 311 312 MOZ_ASSERT(mDebuggerRegistered != aDebuggerRegistered); 313 mDebuggerRegistered = aDebuggerRegistered; 314 315 mCondVar.Notify(); 316 } 317 318 // Mark worker private as running in the background tab 319 // for further throttling 320 void SetIsRunningInBackground(); 321 void SetIsPlayingAudio(bool aIsPlayingAudio); 322 323 bool IsPlayingAudio() { 324 AssertIsOnWorkerThread(); 325 return mIsPlayingAudio; 326 } 327 328 bool HasActivePeerConnections() { 329 AssertIsOnWorkerThread(); 330 return mHasActivePeerConnections; 331 } 332 333 void SetActivePeerConnections(bool aHasPeerConnections); 334 335 void SetIsRunningInForeground(); 336 337 bool ChangeBackgroundStateInternal(bool aIsBackground); 338 bool ChangePlaybackStateInternal(bool aIsPlayingAudio); 339 bool ChangePeerConnectionsInternal(bool aHasPeerConnections); 340 341 // returns true, if worker is running in the background tab 342 bool IsRunningInBackground() const { return mIsInBackground; } 343 344 void WaitForIsDebuggerRegistered(bool aDebuggerRegistered) { 345 AssertIsOnParentThread(); 346 347 // Yield so that the main thread won't be blocked. 348 AutoYieldJSThreadExecution yield; 349 350 MOZ_ASSERT(!NS_IsMainThread()); 351 352 MutexAutoLock lock(mMutex); 353 354 while (mDebuggerRegistered != aDebuggerRegistered) { 355 mCondVar.Wait(); 356 } 357 } 358 359 nsresult SetIsDebuggerReady(bool aReady); 360 361 WorkerDebugger* Debugger() const { 362 AssertIsOnMainThread(); 363 364 MOZ_ASSERT(mDebugger); 365 return mDebugger; 366 } 367 368 const OriginTrials& Trials() const { return mLoadInfo.mTrials; } 369 370 void SetDebugger(WorkerDebugger* aDebugger) { 371 AssertIsOnMainThread(); 372 373 MOZ_ASSERT(mDebugger != aDebugger); 374 mDebugger = aDebugger; 375 } 376 377 JS::UniqueChars AdoptDefaultLocale() { 378 MOZ_ASSERT(mDefaultLocale, 379 "the default locale must have been successfully set for anyone " 380 "to be trying to adopt it"); 381 return std::move(mDefaultLocale); 382 } 383 384 /** 385 * Invoked by WorkerThreadPrimaryRunnable::Run if it already called 386 * SetWorkerPrivateInWorkerThread but has to bail out on initialization before 387 * calling DoRunLoop because PBackground failed to initialize or something 388 * like that. Note that there's currently no point earlier than this that 389 * failure can be reported. 390 * 391 * When this happens, the worker will need to be deleted, plus the call to 392 * SetWorkerPrivateInWorkerThread will have scheduled all the 393 * mPreStartRunnables which need to be cleaned up after, as well as any 394 * scheduled control runnables. We're somewhat punting on debugger runnables 395 * for now, which may leak, but the intent is to moot this whole scenario via 396 * shutdown blockers, so we don't want the extra complexity right now. 397 */ 398 void RunLoopNeverRan(); 399 400 MOZ_CAN_RUN_SCRIPT 401 void DoRunLoop(JSContext* aCx); 402 403 void UnrootGlobalScopes(); 404 405 MOZ_CAN_RUN_SCRIPT bool InterruptCallback(JSContext* aCx); 406 407 bool IsOnCurrentThread(); 408 409 void CloseInternal(); 410 411 bool FreezeInternal(); 412 413 bool ThawInternal(); 414 415 void PropagateStorageAccessPermissionGrantedInternal(); 416 417 void TraverseTimeouts(nsCycleCollectionTraversalCallback& aCallback); 418 419 void UnlinkTimeouts(); 420 421 bool AddChildWorker(WorkerPrivate& aChildWorker); 422 423 void RemoveChildWorker(WorkerPrivate& aChildWorker); 424 425 void PostMessageToParent(JSContext* aCx, JS::Handle<JS::Value> aMessage, 426 const Sequence<JSObject*>& aTransferable, 427 ErrorResult& aRv); 428 429 void PostMessageToParentMessagePort(JSContext* aCx, 430 JS::Handle<JS::Value> aMessage, 431 const Sequence<JSObject*>& aTransferable, 432 ErrorResult& aRv); 433 434 MOZ_CAN_RUN_SCRIPT void EnterDebuggerEventLoop(); 435 436 void LeaveDebuggerEventLoop(); 437 438 void PostMessageToDebugger(const nsAString& aMessage); 439 440 void SetDebuggerImmediate(Function& aHandler, ErrorResult& aRv); 441 442 void ReportErrorToDebugger(const nsACString& aFilename, uint32_t aLineno, 443 const nsAString& aMessage); 444 445 bool NotifyInternal(WorkerStatus aStatus); 446 447 void ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, 448 JSErrorReport* aReport); 449 450 static void ReportErrorToConsole( 451 uint32_t aErrorFlags, const nsCString& aCategory, 452 nsContentUtils::PropertiesFile aFile, const nsCString& aMessageName, 453 const nsTArray<nsString>& aParams = nsTArray<nsString>(), 454 const mozilla::SourceLocation& aLocation = 455 mozilla::JSCallingLocation::Get()); 456 457 int32_t SetTimeout(JSContext* aCx, TimeoutHandler* aHandler, int32_t aTimeout, 458 bool aIsInterval, Timeout::Reason aReason, 459 ErrorResult& aRv); 460 461 void ClearTimeout(int32_t aId, Timeout::Reason aReason); 462 463 void UpdateContextOptionsInternal(JSContext* aCx, 464 const JS::ContextOptions& aContextOptions); 465 466 void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages); 467 468 void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, 469 Maybe<uint32_t> aValue); 470 471 enum WorkerRanOrNot { WorkerNeverRan = 0, WorkerRan }; 472 473 void ScheduleDeletion(WorkerRanOrNot aRanOrNot); 474 475 bool CollectRuntimeStats(JS::RuntimeStats* aRtStats, bool aAnonymize); 476 477 #ifdef JS_GC_ZEAL 478 void UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal, 479 uint32_t aFrequency); 480 #endif 481 482 void SetLowMemoryStateInternal(JSContext* aCx, bool aState); 483 484 void GarbageCollectInternal(JSContext* aCx, bool aShrinking, 485 bool aCollectChildren); 486 487 void CycleCollectInternal(bool aCollectChildren); 488 489 void OfflineStatusChangeEventInternal(bool aIsOffline); 490 491 void MemoryPressureInternal(); 492 493 typedef MozPromise<uint64_t, nsresult, true> JSMemoryUsagePromise; 494 RefPtr<JSMemoryUsagePromise> GetJSMemoryUsage(); 495 496 void SetFetchHandlerWasAdded() { 497 MOZ_ASSERT(IsServiceWorker()); 498 AssertIsOnWorkerThread(); 499 mFetchHandlerWasAdded = true; 500 } 501 502 bool FetchHandlerWasAdded() const { 503 MOZ_ASSERT(IsServiceWorker()); 504 AssertIsOnWorkerThread(); 505 return mFetchHandlerWasAdded; 506 } 507 508 JSContext* GetJSContext() const MOZ_NO_THREAD_SAFETY_ANALYSIS { 509 // mJSContext is only modified on the worker thread, so workerthread code 510 // can safely read it without a lock 511 AssertIsOnWorkerThread(); 512 return mJSContext; 513 } 514 515 WorkerGlobalScope* GlobalScope() const { 516 auto data = mWorkerThreadAccessible.Access(); 517 return data->mScope; 518 } 519 520 WorkerDebuggerGlobalScope* DebuggerGlobalScope() const { 521 auto data = mWorkerThreadAccessible.Access(); 522 return data->mDebuggerScope; 523 } 524 525 // Get the global associated with the current nested event loop. Will return 526 // null if we're not in a nested event loop or that nested event loop does not 527 // have an associated global. 528 nsIGlobalObject* GetCurrentEventLoopGlobal() const { 529 auto data = mWorkerThreadAccessible.Access(); 530 return data->mCurrentEventLoopGlobal; 531 } 532 533 nsICSPEventListener* CSPEventListener() const; 534 535 void SetThread(WorkerThread* aThread); 536 537 void SetWorkerPrivateInWorkerThread(WorkerThread* aThread); 538 539 void ResetWorkerPrivateInWorkerThread(); 540 541 bool IsOnWorkerThread() const; 542 543 void AssertIsOnWorkerThread() const 544 #ifdef DEBUG 545 ; 546 #else 547 { 548 } 549 #endif 550 551 // This may block! 552 void BeginCTypesCall(); 553 554 // This may block! 555 void EndCTypesCall(); 556 557 void BeginCTypesCallback(); 558 559 void EndCTypesCallback(); 560 561 bool ConnectMessagePort(JSContext* aCx, UniqueMessagePortId& aIdentifier); 562 563 WorkerGlobalScope* GetOrCreateGlobalScope(JSContext* aCx); 564 565 WorkerDebuggerGlobalScope* CreateDebuggerGlobalScope(JSContext* aCx); 566 567 bool RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal); 568 569 bool RegisterDebuggerBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal); 570 571 bool OnLine() const { 572 auto data = mWorkerThreadAccessible.Access(); 573 return data->mOnLine; 574 } 575 576 void StopSyncLoop(nsIEventTarget* aSyncLoopTarget, nsresult aResult); 577 578 bool MaybeStopSyncLoop(nsIEventTarget* aSyncLoopTarget, nsresult aResult); 579 580 void ShutdownModuleLoader(); 581 582 void ClearPreStartRunnables(); 583 584 MOZ_CAN_RUN_SCRIPT void ProcessSingleDebuggerRunnable(); 585 void ClearDebuggerEventQueue(); 586 587 void OnProcessNextEvent(); 588 589 void AfterProcessNextEvent(); 590 591 void AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget) 592 #ifdef DEBUG 593 ; 594 #else 595 { 596 } 597 #endif 598 599 void AssertIsNotPotentiallyLastGCCCRunning() { 600 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 601 auto data = mWorkerThreadAccessible.Access(); 602 MOZ_DIAGNOSTIC_ASSERT(!data->mIsPotentiallyLastGCCCRunning); 603 #endif 604 } 605 606 void SetWorkerScriptExecutedSuccessfully() { 607 AssertIsOnWorkerThread(); 608 // Should only be called once! 609 MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully); 610 mWorkerScriptExecutedSuccessfully = true; 611 } 612 613 // Only valid after CompileScriptRunnable has finished running! 614 bool WorkerScriptExecutedSuccessfully() const { 615 AssertIsOnWorkerThread(); 616 return mWorkerScriptExecutedSuccessfully; 617 } 618 619 // Get the event target to use when dispatching to the main thread 620 // from this Worker thread. This may be the main thread itself or 621 // a ThrottledEventQueue to the main thread. 622 nsISerialEventTarget* MainThreadEventTargetForMessaging(); 623 624 nsresult DispatchToMainThreadForMessaging( 625 nsIRunnable* aRunnable, 626 nsIEventTarget::DispatchFlags aFlags = NS_DISPATCH_NORMAL); 627 628 nsresult DispatchToMainThreadForMessaging( 629 already_AddRefed<nsIRunnable> aRunnable, 630 nsIEventTarget::DispatchFlags aFlags = NS_DISPATCH_NORMAL); 631 632 nsISerialEventTarget* MainThreadEventTarget(); 633 634 nsresult DispatchToMainThread( 635 nsIRunnable* aRunnable, 636 nsIEventTarget::DispatchFlags aFlags = NS_DISPATCH_NORMAL); 637 638 nsresult DispatchToMainThread( 639 already_AddRefed<nsIRunnable> aRunnable, 640 nsIEventTarget::DispatchFlags aFlags = NS_DISPATCH_NORMAL); 641 642 nsresult DispatchDebuggeeToMainThread( 643 already_AddRefed<WorkerRunnable> aRunnable, 644 nsIEventTarget::DispatchFlags aFlags = NS_DISPATCH_NORMAL); 645 646 // Get an event target that will dispatch runnables as control runnables on 647 // the worker thread. Implement nsICancelableRunnable if you wish to take 648 // action on cancelation. 649 nsISerialEventTarget* ControlEventTarget(); 650 651 // Get an event target that will attempt to dispatch a normal WorkerRunnable, 652 // but if that fails will then fall back to a control runnable. 653 nsISerialEventTarget* HybridEventTarget(); 654 655 void DumpCrashInformation(nsACString& aString); 656 657 ClientType GetClientType() const; 658 659 bool EnsureCSPEventListener(); 660 661 void EnsurePerformanceStorage(); 662 663 bool GetExecutionGranted() const; 664 void SetExecutionGranted(bool aGranted); 665 666 void ScheduleTimeSliceExpiration(uint32_t aDelay); 667 void CancelTimeSliceExpiration(); 668 669 JSExecutionManager* GetExecutionManager() const; 670 void SetExecutionManager(JSExecutionManager* aManager); 671 672 void ExecutionReady(); 673 674 PerformanceStorage* GetPerformanceStorage(); 675 676 bool IsAcceptingEvents() MOZ_EXCLUDES(mMutex) { 677 AssertIsOnParentThread(); 678 679 MutexAutoLock lock(mMutex); 680 return mParentStatus < Canceling; 681 } 682 683 // This method helps know if the Worker is already at Dead status. 684 // Note that it is racy. The status may change after the function returns. 685 bool IsDead() MOZ_EXCLUDES(mMutex) { 686 MutexAutoLock lock(mMutex); 687 return mStatus == Dead; 688 } 689 690 WorkerStatus ParentStatusProtected() { 691 AssertIsOnParentThread(); 692 MutexAutoLock lock(mMutex); 693 return mParentStatus; 694 } 695 696 WorkerStatus ParentStatus() const MOZ_REQUIRES(mMutex) { 697 mMutex.AssertCurrentThreadOwns(); 698 return mParentStatus; 699 } 700 701 Worker* ParentEventTargetRef() const { 702 MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef); 703 return mParentEventTargetRef; 704 } 705 706 void SetParentEventTargetRef(Worker* aParentEventTargetRef) { 707 MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef); 708 MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef); 709 mParentEventTargetRef = aParentEventTargetRef; 710 } 711 712 // Check whether this worker is a secure context. For use from the parent 713 // thread only; the canonical "is secure context" boolean is stored on the 714 // compartment of the worker global. The only reason we don't 715 // AssertIsOnParentThread() here is so we can assert that this value matches 716 // the one on the compartment, which has to be done from the worker thread. 717 bool IsSecureContext() const { return mIsSecureContext; } 718 719 // Check whether we're running in automation. 720 bool IsInAutomation() const { return mIsInAutomation; } 721 722 bool IsPrivilegedAddonGlobal() const { return mIsPrivilegedAddonGlobal; } 723 724 TimeStamp CreationTimeStamp() const { return mCreationTimeStamp; } 725 726 DOMHighResTimeStamp CreationTime() const { return mCreationTimeHighRes; } 727 728 DOMHighResTimeStamp TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const { 729 MOZ_ASSERT(!aTimeStamp.IsNull()); 730 TimeDuration duration = aTimeStamp - mCreationTimeStamp; 731 return duration.ToMilliseconds(); 732 } 733 734 LocationInfo& GetLocationInfo() { return mLocationInfo; } 735 736 void CopyJSSettings(workerinternals::JSSettings& aSettings) { 737 mozilla::MutexAutoLock lock(mMutex); 738 aSettings = mJSSettings; 739 } 740 741 void CopyJSRealmOptions(JS::RealmOptions& aOptions) { 742 mozilla::MutexAutoLock lock(mMutex); 743 aOptions = IsChromeWorker() ? mJSSettings.chromeRealmOptions 744 : mJSSettings.contentRealmOptions; 745 } 746 747 // The ability to be a chrome worker is orthogonal to the type of 748 // worker [Dedicated|Shared|Service]. 749 bool IsChromeWorker() const { return mIsChromeWorker; } 750 751 // TODO: Invariants require that the parent worker out-live any child 752 // worker, so WorkerPrivate* should be safe in the moment of calling. 753 // We would like to have stronger type-system annotated/enforced handling. 754 WorkerPrivate* GetParent() const { return mParent; } 755 756 // Returns the top level worker. It can be the current worker if it's the top 757 // level one. 758 WorkerPrivate* GetTopLevelWorker() const { 759 WorkerPrivate const* wp = this; 760 while (wp->GetParent()) { 761 wp = wp->GetParent(); 762 } 763 return const_cast<WorkerPrivate*>(wp); 764 } 765 766 bool IsFrozen() const; 767 768 bool IsFrozenForWorkerThread() const; 769 770 bool IsParentWindowPaused() const { 771 AssertIsOnParentThread(); 772 return mParentWindowPaused; 773 } 774 775 // When we debug a worker, we want to disconnect the window and the worker 776 // communication. This happens calling this method. 777 // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead. 778 void ParentWindowPaused(); 779 780 void ParentWindowResumed(); 781 782 const nsString& ScriptURL() const { return mScriptURL; } 783 784 const nsString& WorkerName() const { return mWorkerName; } 785 RequestCredentials WorkerCredentials() const { return mCredentialsMode; } 786 enum WorkerType WorkerType() const { return mWorkerType; } 787 788 WorkerKind Kind() const { return mWorkerKind; } 789 790 bool IsDedicatedWorker() const { return mWorkerKind == WorkerKindDedicated; } 791 792 bool IsSharedWorker() const { return mWorkerKind == WorkerKindShared; } 793 794 bool IsServiceWorker() const { return mWorkerKind == WorkerKindService; } 795 796 nsContentPolicyType ContentPolicyType() const { 797 return ContentPolicyType(mWorkerKind); 798 } 799 800 static nsContentPolicyType ContentPolicyType(WorkerKind aWorkerKind) { 801 switch (aWorkerKind) { 802 case WorkerKindDedicated: 803 return nsIContentPolicy::TYPE_INTERNAL_WORKER; 804 case WorkerKindShared: 805 return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER; 806 case WorkerKindService: 807 return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER; 808 default: 809 MOZ_ASSERT_UNREACHABLE("Invalid worker type"); 810 return nsIContentPolicy::TYPE_INVALID; 811 } 812 } 813 814 nsIScriptContext* GetScriptContext() const { 815 AssertIsOnMainThread(); 816 return mLoadInfo.mScriptContext; 817 } 818 819 const nsCString& Domain() const { return mLoadInfo.mDomain; } 820 821 bool IsFromWindow() const { return mLoadInfo.mFromWindow; } 822 823 nsLoadFlags GetLoadFlags() const { return mLoadInfo.mLoadFlags; } 824 825 uint64_t WindowID() const { return mLoadInfo.mWindowID; } 826 827 uint64_t AssociatedBrowsingContextID() const { 828 return mLoadInfo.mAssociatedBrowsingContextID; 829 } 830 831 uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); } 832 833 const nsCString& ServiceWorkerScope() const { 834 return GetServiceWorkerDescriptor().Scope(); 835 } 836 837 // This value should never change after the script load completes. Before 838 // then, it may only be called on the main thread. 839 nsIURI* GetBaseURI() const { return mLoadInfo.mBaseURI; } 840 841 void SetBaseURI(nsIURI* aBaseURI); 842 843 nsIURI* GetResolvedScriptURI() const { return mLoadInfo.mResolvedScriptURI; } 844 845 const nsString& ServiceWorkerCacheName() const { 846 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 847 AssertIsOnMainThread(); 848 return mLoadInfo.mServiceWorkerCacheName; 849 } 850 851 const ServiceWorkerDescriptor& GetServiceWorkerDescriptor() const { 852 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 853 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome()); 854 return mLoadInfo.mServiceWorkerDescriptor.ref(); 855 } 856 857 const ServiceWorkerRegistrationDescriptor& 858 GetServiceWorkerRegistrationDescriptor() const { 859 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 860 MOZ_DIAGNOSTIC_ASSERT( 861 mLoadInfo.mServiceWorkerRegistrationDescriptor.isSome()); 862 return mLoadInfo.mServiceWorkerRegistrationDescriptor.ref(); 863 } 864 865 const ClientInfo& GetSourceInfo() const { 866 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 867 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mSourceInfo.isSome()); 868 return mLoadInfo.mSourceInfo.ref(); 869 } 870 871 void UpdateServiceWorkerState(ServiceWorkerState aState) { 872 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 873 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome()); 874 return mLoadInfo.mServiceWorkerDescriptor.ref().SetState(aState); 875 } 876 877 void UpdateIsOnContentBlockingAllowList(bool aOnContentBlockingAllowList); 878 879 const Maybe<ServiceWorkerDescriptor>& GetParentController() const { 880 return mLoadInfo.mParentController; 881 } 882 883 const ChannelInfo& GetChannelInfo() const { return mLoadInfo.mChannelInfo; } 884 885 void SetChannelInfo(const ChannelInfo& aChannelInfo) { 886 AssertIsOnMainThread(); 887 MOZ_ASSERT(!mLoadInfo.mChannelInfo.IsInitialized()); 888 MOZ_ASSERT(aChannelInfo.IsInitialized()); 889 mLoadInfo.mChannelInfo = aChannelInfo; 890 } 891 892 void InitChannelInfo(nsIChannel* aChannel) { 893 mLoadInfo.mChannelInfo.InitFromChannel(aChannel); 894 } 895 896 void InitChannelInfo(const ChannelInfo& aChannelInfo) { 897 mLoadInfo.mChannelInfo = aChannelInfo; 898 } 899 900 nsIPrincipal* GetPrincipal() const { return mLoadInfo.mPrincipal; } 901 902 nsIPrincipal* GetLoadingPrincipal() const { 903 return mLoadInfo.mLoadingPrincipal; 904 } 905 906 nsIPrincipal* GetPartitionedPrincipal() const { 907 return mLoadInfo.mPartitionedPrincipal; 908 } 909 910 nsIPrincipal* GetEffectiveStoragePrincipal() const; 911 912 nsILoadGroup* GetLoadGroup() const { 913 AssertIsOnMainThread(); 914 return mLoadInfo.mLoadGroup; 915 } 916 917 bool UsesSystemPrincipal() const { 918 return GetPrincipal()->IsSystemPrincipal(); 919 } 920 bool UsesAddonOrExpandedAddonPrincipal() const { 921 return GetPrincipal()->GetIsAddonOrExpandedAddonPrincipal(); 922 } 923 924 const mozilla::ipc::PrincipalInfo& GetPrincipalInfo() const { 925 return *mLoadInfo.mPrincipalInfo; 926 } 927 928 const mozilla::ipc::PrincipalInfo& GetPartitionedPrincipalInfo() const { 929 return *mLoadInfo.mPartitionedPrincipalInfo; 930 } 931 932 const mozilla::ipc::PrincipalInfo& GetEffectiveStoragePrincipalInfo() const; 933 934 already_AddRefed<nsIChannel> ForgetWorkerChannel() { 935 AssertIsOnMainThread(); 936 return mLoadInfo.mChannel.forget(); 937 } 938 939 nsPIDOMWindowInner* GetWindow() const { 940 AssertIsOnMainThread(); 941 return mLoadInfo.mWindow; 942 } 943 944 nsPIDOMWindowInner* GetAncestorWindow() const; 945 946 void EvictFromBFCache(); 947 948 nsIContentSecurityPolicy* GetCsp() const { 949 AssertIsOnMainThread(); 950 return mLoadInfo.mCSP; 951 } 952 953 nsresult SetCsp(nsIContentSecurityPolicy* aCSP); 954 955 nsresult SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue, 956 const nsACString& aCSPReportOnlyHeaderValue); 957 958 void StoreCSPOnClient(); 959 960 const mozilla::ipc::CSPInfo& GetCSPInfo() const { 961 return mLoadInfo.mCSPContext->CSPInfo(); 962 } 963 964 WorkerCSPContext* GetCSPContext() const { 965 return mLoadInfo.mCSPContext.get(); 966 } 967 968 void UpdateReferrerInfoFromHeader( 969 const nsACString& aReferrerPolicyHeaderValue); 970 971 nsIReferrerInfo* GetReferrerInfo() const { return mLoadInfo.mReferrerInfo; } 972 973 ReferrerPolicy GetReferrerPolicy() const { 974 return mLoadInfo.mReferrerInfo->ReferrerPolicy(); 975 } 976 977 void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) { 978 mLoadInfo.mReferrerInfo = aReferrerInfo; 979 } 980 981 bool XHRParamsAllowed() const { return mLoadInfo.mXHRParamsAllowed; } 982 983 void SetXHRParamsAllowed(bool aAllowed) { 984 mLoadInfo.mXHRParamsAllowed = aAllowed; 985 } 986 987 mozilla::StorageAccess StorageAccess() const { 988 AssertIsOnWorkerThread(); 989 if (mLoadInfo.mUsingStorageAccess) { 990 return mozilla::StorageAccess::eAllow; 991 } 992 993 return mLoadInfo.mStorageAccess; 994 } 995 996 bool UseRegularPrincipal() const { 997 AssertIsOnWorkerThread(); 998 return mLoadInfo.mUseRegularPrincipal; 999 } 1000 1001 bool UsingStorageAccess() const { 1002 AssertIsOnWorkerThread(); 1003 return mLoadInfo.mUsingStorageAccess; 1004 } 1005 1006 nsICookieJarSettings* CookieJarSettings() const { 1007 // Any thread. 1008 MOZ_ASSERT(mLoadInfo.mCookieJarSettings); 1009 return mLoadInfo.mCookieJarSettings; 1010 } 1011 1012 const net::CookieJarSettingsArgs& CookieJarSettingsArgs() const { 1013 MOZ_ASSERT(mLoadInfo.mCookieJarSettings); 1014 return mLoadInfo.mCookieJarSettingsArgs; 1015 } 1016 1017 const OriginAttributes& GetOriginAttributes() const { 1018 return mLoadInfo.mOriginAttributes; 1019 } 1020 1021 // Determine if the SW testing per-window flag is set by devtools 1022 bool ServiceWorkersTestingInWindow() const { 1023 return mLoadInfo.mServiceWorkersTestingInWindow; 1024 } 1025 1026 // Determine if the worker was created under a third-party context. 1027 bool IsThirdPartyContext() const { return mLoadInfo.mIsThirdPartyContext; } 1028 1029 bool IsWatchedByDevTools() const { return mLoadInfo.mWatchedByDevTools; } 1030 1031 const Maybe<RFPTargetSet>& GetOverriddenFingerprintingSettings() const { 1032 return mLoadInfo.mOverriddenFingerprintingSettings; 1033 } 1034 1035 bool IsOn3PCBExceptionList() const { 1036 return mLoadInfo.mIsOn3PCBExceptionList; 1037 } 1038 1039 RemoteWorkerChild* GetRemoteWorkerController(); 1040 1041 void SetRemoteWorkerController(RemoteWorkerChild* aController); 1042 1043 RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag(); 1044 1045 // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw 1046 // as these are only used for globals going in and out of the bfcache. 1047 bool Freeze(const nsPIDOMWindowInner* aWindow); 1048 1049 bool Thaw(const nsPIDOMWindowInner* aWindow); 1050 1051 void PropagateStorageAccessPermissionGranted(); 1052 1053 void NotifyStorageKeyUsed(); 1054 1055 void EnableDebugger(); 1056 1057 void DisableDebugger(); 1058 1059 void BindRemoteWorkerDebuggerChild(); 1060 1061 void CreateRemoteDebuggerEndpoints(); 1062 1063 void SetIsRemoteDebuggerRegistered(const bool& aRegistered); 1064 1065 void SetIsRemoteDebuggerReady(const bool& aReady); 1066 1067 void EnableRemoteDebugger(); 1068 1069 void DisableRemoteDebugger(); 1070 1071 void DisableRemoteDebuggerOnWorkerThread(const bool& aForShutdown = false); 1072 1073 void SetIsQueued(const bool& aQueued); 1074 1075 bool IsQueued() const; 1076 1077 void UpdateWindowIDToDebugger(const uint64_t& aWindowID, const bool& aIsAdd); 1078 1079 already_AddRefed<WorkerRunnable> MaybeWrapAsWorkerRunnable( 1080 already_AddRefed<nsIRunnable> aRunnable); 1081 1082 bool ProxyReleaseMainThreadObjects(); 1083 1084 void SetLowMemoryState(bool aState); 1085 1086 void GarbageCollect(bool aShrinking); 1087 1088 void CycleCollect(); 1089 1090 nsresult SetPrincipalsAndCSPOnMainThread(nsIPrincipal* aPrincipal, 1091 nsIPrincipal* aPartitionedPrincipal, 1092 nsILoadGroup* aLoadGroup, 1093 nsIContentSecurityPolicy* aCsp); 1094 1095 nsresult SetPrincipalsAndCSPFromChannel(nsIChannel* aChannel); 1096 1097 bool FinalChannelPrincipalIsValid(nsIChannel* aChannel); 1098 1099 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 1100 bool PrincipalURIMatchesScriptURL(); 1101 #endif 1102 1103 void UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup); 1104 1105 void WorkerScriptLoaded(); 1106 1107 Document* GetDocument() const; 1108 1109 void MemoryPressure(); 1110 1111 void UpdateContextOptions(const JS::ContextOptions& aContextOptions); 1112 1113 void UpdateLanguages(const nsTArray<nsString>& aLanguages); 1114 1115 void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value); 1116 1117 #ifdef JS_GC_ZEAL 1118 void UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency); 1119 #endif 1120 1121 void OfflineStatusChangeEvent(bool aIsOffline); 1122 1123 nsresult Dispatch(already_AddRefed<WorkerRunnable> aRunnable, 1124 nsIEventTarget* aSyncLoopTarget = nullptr); 1125 1126 nsresult DispatchControlRunnable( 1127 already_AddRefed<WorkerRunnable> aWorkerRunnable); 1128 1129 nsresult DispatchDebuggerRunnable( 1130 already_AddRefed<WorkerRunnable> aDebuggerRunnable); 1131 1132 nsresult DispatchToParent(already_AddRefed<WorkerRunnable> aRunnable); 1133 1134 bool IsOnParentThread() const; 1135 void DebuggerInterruptRequest(); 1136 1137 #ifdef DEBUG 1138 void AssertIsOnParentThread() const; 1139 1140 void AssertInnerWindowIsCorrect() const; 1141 #else 1142 void AssertIsOnParentThread() const {} 1143 1144 void AssertInnerWindowIsCorrect() const {} 1145 #endif 1146 1147 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 1148 bool PrincipalIsValid() const; 1149 #endif 1150 1151 void StartCancelingTimer(); 1152 1153 const nsString& Id(); 1154 1155 const nsID& AgentClusterId() const { return mAgentClusterId; } 1156 1157 bool IsSharedMemoryAllowed() const; 1158 1159 // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated 1160 bool CrossOriginIsolated() const; 1161 1162 void SetUseCounter(UseCounterWorker aUseCounter) { 1163 MOZ_ASSERT(!mReportedUseCounters); 1164 MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown); 1165 AssertIsOnWorkerThread(); 1166 mUseCounters[static_cast<size_t>(aUseCounter)] = true; 1167 } 1168 1169 /** 1170 * COEP Methods 1171 * 1172 * If browser.tabs.remote.useCrossOriginEmbedderPolicy=false, these methods 1173 * will, depending on the return type, return a value that will avoid 1174 * assertion failures or a value that won't block loads. 1175 */ 1176 nsILoadInfo::CrossOriginEmbedderPolicy GetEmbedderPolicy() const; 1177 1178 // Fails if a policy has already been set or if `aPolicy` violates the owner's 1179 // policy, if an owner exists. 1180 mozilla::Result<Ok, nsresult> SetEmbedderPolicy( 1181 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy); 1182 1183 // `aRequest` is the request loading the worker and must be QI-able to 1184 // `nsIChannel*`. It's used to verify that the worker can indeed inherit its 1185 // owner's COEP (when an owner exists). 1186 // 1187 // TODO: remove `aRequest`; currently, it's required because instances may not 1188 // always know its final, resolved script URL or have access internally to 1189 // `aRequest`. 1190 void InheritOwnerEmbedderPolicyOrNull(nsIRequest* aRequest); 1191 1192 // Requires a policy to already have been set. 1193 bool MatchEmbedderPolicy( 1194 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) const; 1195 1196 nsILoadInfo::CrossOriginEmbedderPolicy GetOwnerEmbedderPolicy() const; 1197 1198 void SetCCCollectedAnything(bool collectedAnything); 1199 bool isLastCCCollectedAnything(); 1200 1201 uint32_t GetCurrentTimerNestingLevel() const; 1202 1203 void IncreaseTopLevelWorkerFinishedRunnableCount() { 1204 ++mTopLevelWorkerFinishedRunnableCount; 1205 } 1206 void DecreaseTopLevelWorkerFinishedRunnableCount() { 1207 --mTopLevelWorkerFinishedRunnableCount; 1208 } 1209 void IncreaseWorkerFinishedRunnableCount() { ++mWorkerFinishedRunnableCount; } 1210 void DecreaseWorkerFinishedRunnableCount() { --mWorkerFinishedRunnableCount; } 1211 1212 void JSAsyncTaskStarted(JS::Dispatchable* aDispatchable); 1213 void JSAsyncTaskFinished(JS::Dispatchable* aDispatchable); 1214 1215 void RunShutdownTasks(); 1216 1217 bool CancelBeforeWorkerScopeConstructed() const { 1218 auto data = mWorkerThreadAccessible.Access(); 1219 return data->mCancelBeforeWorkerScopeConstructed; 1220 } 1221 1222 enum class CCFlag : uint8_t { 1223 EligibleForWorkerRef, 1224 IneligibleForWorkerRef, 1225 EligibleForChildWorker, 1226 IneligibleForChildWorker, 1227 EligibleForTimeout, 1228 IneligibleForTimeout, 1229 CheckBackgroundActors, 1230 }; 1231 1232 // When create/release a StrongWorkerRef, child worker, and timeout, this 1233 // method is used to setup if mParentEventTargetRef can get into 1234 // cycle-collection. 1235 // When this method is called, it will also checks if any background actor 1236 // should block the mParentEventTargetRef cycle-collection when there is no 1237 // StrongWorkerRef/ChildWorker/Timeout. 1238 // Worker thread only. 1239 void UpdateCCFlag(const CCFlag); 1240 1241 // This is used in WorkerPrivate::Traverse() to checking if 1242 // mParentEventTargetRef should get into cycle-collection. 1243 // Parent thread only method. 1244 bool IsEligibleForCC(); 1245 1246 // A method which adjusts the count of background actors which should not 1247 // block WorkerPrivate::mParentEventTargetRef cycle-collection. 1248 // Worker thread only. 1249 void AdjustNonblockingCCBackgroundActorCount(int32_t aCount); 1250 1251 RefPtr<WorkerParentRef> GetWorkerParentRef() const; 1252 1253 bool MayContinueRunning() { 1254 AssertIsOnWorkerThread(); 1255 1256 WorkerStatus status; 1257 { 1258 MutexAutoLock lock(mMutex); 1259 status = mStatus; 1260 } 1261 1262 if (status < Canceling) { 1263 return true; 1264 } 1265 1266 return false; 1267 } 1268 1269 private: 1270 WorkerPrivate( 1271 WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, 1272 WorkerKind aWorkerKind, RequestCredentials aRequestCredentials, 1273 enum WorkerType aWorkerType, const nsAString& aWorkerName, 1274 const nsACString& aServiceWorkerScope, WorkerLoadInfo& aLoadInfo, 1275 nsString&& aId, const nsID& aAgentClusterId, 1276 const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy, 1277 CancellationCallback&& aCancellationCallback, 1278 TerminationCallback&& aTerminationCallback, 1279 mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&& 1280 aChildEp); 1281 1282 ~WorkerPrivate(); 1283 1284 struct AgentClusterIdAndCoop { 1285 nsID mId; 1286 nsILoadInfo::CrossOriginOpenerPolicy mCoop; 1287 }; 1288 1289 static AgentClusterIdAndCoop ComputeAgentClusterIdAndCoop( 1290 WorkerPrivate* aParent, WorkerKind aWorkerKind, WorkerLoadInfo* aLoadInfo, 1291 bool aIsChromeWorker); 1292 1293 void CancelAllTimeouts(); 1294 1295 enum class ProcessAllControlRunnablesResult { 1296 // We did not process anything. 1297 Nothing, 1298 // We did process something, states may have changed, but we can keep 1299 // executing script. 1300 MayContinue, 1301 // We did process something, and should not continue executing script. 1302 Abort 1303 }; 1304 1305 ProcessAllControlRunnablesResult ProcessAllControlRunnables() { 1306 MutexAutoLock lock(mMutex); 1307 return ProcessAllControlRunnablesLocked(); 1308 } 1309 1310 ProcessAllControlRunnablesResult ProcessAllControlRunnablesLocked() 1311 MOZ_REQUIRES(mMutex); 1312 1313 void EnableMemoryReporter(); 1314 1315 void DisableMemoryReporter(); 1316 1317 void WaitForWorkerEvents() MOZ_REQUIRES(mMutex); 1318 1319 // If the worker shutdown status is equal or greater then aFailStatus, this 1320 // operation will fail and nullptr will be returned. See WorkerStatus.h for 1321 // more information about the correct value to use. 1322 already_AddRefed<nsISerialEventTarget> CreateNewSyncLoop( 1323 WorkerStatus aFailStatus); 1324 1325 nsresult RunCurrentSyncLoop(); 1326 1327 nsresult DestroySyncLoop(uint32_t aLoopIndex); 1328 1329 void InitializeGCTimers(); 1330 1331 enum GCTimerMode { PeriodicTimer = 0, IdleTimer, NoTimer }; 1332 1333 void SetGCTimerMode(GCTimerMode aMode); 1334 1335 public: 1336 void CancelGCTimers() { SetGCTimerMode(NoTimer); } 1337 1338 private: 1339 void ShutdownGCTimers(); 1340 1341 friend class WorkerRef; 1342 1343 bool AddWorkerRef(WorkerRef* aWorkerRefer, WorkerStatus aFailStatus); 1344 1345 void RemoveWorkerRef(WorkerRef* aWorkerRef); 1346 1347 void NotifyWorkerRefs(WorkerStatus aStatus); 1348 1349 bool HasActiveWorkerRefs(); 1350 1351 friend class WorkerEventTarget; 1352 1353 nsresult RegisterShutdownTask(nsITargetShutdownTask* aTask); 1354 1355 nsresult UnregisterShutdownTask(nsITargetShutdownTask* aTask); 1356 1357 // Internal logic to dispatch a runnable. This is separate from Dispatch() 1358 // to allow runnables to be atomically dispatched in bulk. 1359 nsresult DispatchLockHeld(already_AddRefed<WorkerRunnable> aRunnable, 1360 nsIEventTarget* aSyncLoopTarget, 1361 const MutexAutoLock& aProofOfLock) 1362 MOZ_REQUIRES(mMutex); 1363 1364 // This method dispatches a simple runnable that starts the shutdown procedure 1365 // after a self.close(). This method is called after a ClearMainEventQueue() 1366 // to be sure that the canceling runnable is the only one in the queue. We 1367 // need this async operation to be sure that all the current JS code is 1368 // executed. 1369 void DispatchCancelingRunnable(); 1370 1371 bool GetUseCounter(UseCounterWorker aUseCounter) { 1372 MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown); 1373 AssertIsOnWorkerThread(); 1374 return mUseCounters[static_cast<size_t>(aUseCounter)]; 1375 } 1376 1377 void ReportUseCounters(); 1378 1379 UniquePtr<ClientSource> CreateClientSource(); 1380 1381 // This method is called when corresponding script loader processes the COEP 1382 // header for the worker. 1383 // This method should be called only once in the main thread. 1384 // After this method is called the COEP value owner(window/parent worker) is 1385 // cached in mOwnerEmbedderPolicy such that it can be accessed in other 1386 // threads, i.e. WorkerThread. 1387 void EnsureOwnerEmbedderPolicy(); 1388 1389 class EventTarget; 1390 friend class EventTarget; 1391 friend class AutoSyncLoopHolder; 1392 1393 class MemoryReporter; 1394 friend class MemoryReporter; 1395 1396 friend class mozilla::dom::WorkerThread; 1397 1398 SharedMutex mMutex; 1399 mozilla::CondVar mCondVar MOZ_GUARDED_BY(mMutex); 1400 1401 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate 1402 // our static assert 1403 MOZ_NON_OWNING_REF WorkerPrivate* const mParent; 1404 1405 const nsString mScriptURL; 1406 1407 // This is the worker name for shared workers and dedicated workers. 1408 const nsString mWorkerName; 1409 const RequestCredentials mCredentialsMode; 1410 enum WorkerType mWorkerType; 1411 1412 const WorkerKind mWorkerKind; 1413 1414 // The worker is owned by its thread, which is represented here. This is set 1415 // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally 1416 // traversed by the cycle collector if no other things preventing shutdown. 1417 // 1418 // There are 4 ways a worker can be terminated: 1419 // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to 1420 // traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed 1421 // Worker webidl object. Doing this, CC will be able to detect a cycle and 1422 // Unlink is called. In Unlink, Worker calls Cancel(). 1423 // 2. Worker::Cancel() is called - the shutdown procedure starts immediately. 1424 // 3. WorkerScope::Close() is called - Similar to point 2. 1425 // 4. xpcom-shutdown notification - We call Kill(). 1426 RefPtr<Worker> mParentEventTargetRef; 1427 RefPtr<WorkerPrivate> mSelfRef; 1428 1429 CancellationCallback mCancellationCallback; 1430 1431 // The termination callback is passed into the constructor on the parent 1432 // thread and invoked by `ClearSelfAndParentEventTargetRef` just before it 1433 // drops its self-ref. 1434 TerminationCallback mTerminationCallback; 1435 1436 // The lifetime of these objects within LoadInfo is managed explicitly; 1437 // they do not need to be cycle collected. 1438 WorkerLoadInfo mLoadInfo; 1439 LocationInfo mLocationInfo; 1440 1441 // Protected by mMutex. 1442 workerinternals::JSSettings mJSSettings MOZ_GUARDED_BY(mMutex); 1443 1444 WorkerDebugger* mDebugger; 1445 1446 workerinternals::Queue<WorkerRunnable*, 4> mControlQueue; 1447 workerinternals::Queue<WorkerRunnable*, 4> mDebuggerQueue 1448 MOZ_GUARDED_BY(mMutex); 1449 1450 // This counts the numbers of dispatching WorkerControlRunnables. 1451 // This is used to decouple the lock sequence between WorkerPrivate::mMutex 1452 // and FutexThread::Lock. If this count is not zero, it means there are some 1453 // WorkerControlRunnables are dispatching, and WorkerControlRunables might 1454 // unlock WorkerPrivate::mMutex to request JS execution interrupt on the 1455 // Worker thread. 1456 // When a Worker starts shutdown, before releasing mJSContext, this value must 1457 // be ensured to be zero. 1458 uint32_t mDispatchingControlRunnables MOZ_GUARDED_BY(mMutex); 1459 1460 // Touched on multiple threads, protected with mMutex. Only modified on the 1461 // worker thread 1462 JSContext* mJSContext MOZ_GUARDED_BY(mMutex); 1463 // mThread is only modified on the Worker thread, before calling DoRunLoop 1464 RefPtr<WorkerThread> mThread MOZ_GUARDED_BY(mMutex); 1465 // mPRThread is only modified on another thread in ScheduleWorker(), and is 1466 // constant for the duration of DoRunLoop. Static mutex analysis doesn't help 1467 // here 1468 PRThread* mPRThread; 1469 1470 // Accessed from main thread 1471 RefPtr<ThrottledEventQueue> mMainThreadEventTargetForMessaging; 1472 RefPtr<ThrottledEventQueue> mMainThreadEventTarget; 1473 1474 // Accessed from worker thread and destructing thread 1475 RefPtr<WorkerEventTarget> mWorkerControlEventTarget; 1476 RefPtr<WorkerEventTarget> mWorkerHybridEventTarget; 1477 1478 // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread. 1479 // See WorkerDebuggeeRunnable for details. 1480 RefPtr<ThrottledEventQueue> mMainThreadDebuggeeEventTarget; 1481 1482 struct SyncLoopInfo { 1483 explicit SyncLoopInfo(EventTarget* aEventTarget); 1484 1485 RefPtr<EventTarget> mEventTarget; 1486 nsresult mResult; 1487 bool mCompleted; 1488 #ifdef DEBUG 1489 bool mHasRun; 1490 #endif 1491 }; 1492 1493 // This is only modified on the worker thread, but in DEBUG builds 1494 // AssertValidSyncLoop function iterates it on other threads. Therefore 1495 // modifications are done with mMutex held *only* in DEBUG builds. 1496 nsTArray<UniquePtr<SyncLoopInfo>> mSyncLoopStack; 1497 1498 nsCOMPtr<nsITimer> mCancelingTimer; 1499 1500 // fired on the main thread if the worker script fails to load 1501 nsCOMPtr<nsIRunnable> mLoadFailedRunnable; 1502 1503 RefPtr<PerformanceStorage> mPerformanceStorage; 1504 1505 RefPtr<WorkerCSPEventListener> mCSPEventListener; 1506 1507 // Protected by mMutex. 1508 nsTArray<RefPtr<WorkerThreadRunnable>> mPreStartRunnables 1509 MOZ_GUARDED_BY(mMutex); 1510 1511 // Only touched on the parent thread. Used for both SharedWorker and 1512 // ServiceWorker RemoteWorkers. 1513 RefPtr<RemoteWorkerChild> mRemoteWorkerController; 1514 1515 // Only touched on the worker thread. Used for both SharedWorker and 1516 // ServiceWorker RemoteWorkers. 1517 RefPtr<RemoteWorkerNonLifeCycleOpControllerChild> 1518 mRemoteWorkerNonLifeCycleOpController; 1519 1520 mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild> mChildEp; 1521 1522 RefPtr<RemoteWorkerDebuggerChild> mRemoteDebugger; 1523 mozilla::ipc::Endpoint<PRemoteWorkerDebuggerChild> mDebuggerChildEp; 1524 mozilla::ipc::Endpoint<PRemoteWorkerDebuggerParent> mDebuggerParentEp; 1525 bool mRemoteDebuggerRegistered MOZ_GUARDED_BY(mMutex); 1526 bool mRemoteDebuggerReady MOZ_GUARDED_BY(mMutex); 1527 bool mIsQueued; // Should only touched on parent thread. 1528 mozilla::CondVar mDebuggerBindingCondVar MOZ_GUARDED_BY(mMutex); 1529 RefPtr<WorkerEventTarget> mWorkerDebuggerEventTarget; 1530 1531 JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init 1532 TimeStamp mKillTime; 1533 WorkerStatus mParentStatus MOZ_GUARDED_BY(mMutex); 1534 WorkerStatus mStatus MOZ_GUARDED_BY(mMutex); 1535 1536 TimeStamp mCreationTimeStamp; 1537 DOMHighResTimeStamp mCreationTimeHighRes; 1538 1539 // Flags for use counters used directly by this worker. 1540 static_assert(sizeof(UseCounterWorker) <= sizeof(size_t), 1541 "UseCounterWorker is too big"); 1542 static_assert(UseCounterWorker::Count >= static_cast<UseCounterWorker>(0), 1543 "Should be non-negative value and safe to cast to unsigned"); 1544 std::bitset<static_cast<size_t>(UseCounterWorker::Count)> mUseCounters; 1545 bool mReportedUseCounters; 1546 1547 // This is created while creating the WorkerPrivate, so it's safe to be 1548 // touched on any thread. 1549 const nsID mAgentClusterId; 1550 1551 // Things touched on worker thread only. 1552 struct WorkerThreadAccessible { 1553 explicit WorkerThreadAccessible(WorkerPrivate* aParent); 1554 1555 RefPtr<WorkerGlobalScope> mScope; 1556 RefPtr<WorkerDebuggerGlobalScope> mDebuggerScope; 1557 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate 1558 // our static assert 1559 nsTArray<WorkerPrivate*> mChildWorkers; 1560 nsTObserverArray<WorkerRef*> mWorkerRefs; 1561 1562 nsCOMPtr<nsITimer> mPeriodicGCTimer; 1563 nsCOMPtr<nsITimer> mIdleGCTimer; 1564 1565 RefPtr<MemoryReporter> mMemoryReporter; 1566 1567 // While running a nested event loop, whether a sync loop or a debugger 1568 // event loop we want to keep track of which global is running it, if any, 1569 // so runnables that run off that event loop can get at that information. In 1570 // practice this only matters for various worker debugger runnables running 1571 // against sandboxes, because all other runnables know which globals they 1572 // belong to already. We could also address this by threading the relevant 1573 // global through the chains of runnables involved, but we'd need to thread 1574 // it through some runnables that run on the main thread, and that would 1575 // require some care to make sure things get released on the correct thread, 1576 // which we'd rather avoid. This member is only accessed on the worker 1577 // thread. 1578 nsCOMPtr<nsIGlobalObject> mCurrentEventLoopGlobal; 1579 1580 // Timer that triggers an interrupt on expiration of the current time slice 1581 nsCOMPtr<nsITimer> mTSTimer; 1582 1583 // Execution manager used to regulate execution for this worker. 1584 RefPtr<JSExecutionManager> mExecutionManager; 1585 1586 // Used to relinguish clearance for CTypes Callbacks. 1587 nsTArray<AutoYieldJSThreadExecution> mYieldJSThreadExecution; 1588 1589 uint32_t mNumWorkerRefsPreventingShutdownStart; 1590 uint32_t mDebuggerEventLoopLevel; 1591 1592 // This is the count of background actors that binding with IPCWorkerRefs. 1593 // This count would be used in WorkerPrivate::UpdateCCFlag for checking if 1594 // CC should be blocked by background actors. 1595 uint32_t mNonblockingCCBackgroundActorCount; 1596 1597 uint32_t mErrorHandlerRecursionCount; 1598 1599 bool mFrozen; 1600 1601 // This flag is set by the debugger interrupt control runnable to indicate 1602 // that we want to process debugger runnables as part of control runnable 1603 // processing, which is something we don't normally want to do. The flag is 1604 // cleared after processing the debugger runnables. 1605 bool mDebuggerInterruptRequested; 1606 1607 bool mRunningExpiredTimeouts; 1608 bool mPeriodicGCTimerRunning; 1609 bool mIdleGCTimerRunning; 1610 bool mOnLine; 1611 bool mJSThreadExecutionGranted; 1612 bool mCCCollectedAnything; 1613 FlippedOnce<false> mDeletionScheduled; 1614 FlippedOnce<false> mCancelBeforeWorkerScopeConstructed; 1615 FlippedOnce<false> mPerformedShutdownAfterLastContentTaskExecuted; 1616 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 1617 bool mIsPotentiallyLastGCCCRunning = false; 1618 #endif 1619 }; 1620 ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible; 1621 1622 class MOZ_RAII AutoPushEventLoopGlobal { 1623 public: 1624 AutoPushEventLoopGlobal(WorkerPrivate* aWorkerPrivate, JSContext* aCx); 1625 ~AutoPushEventLoopGlobal(); 1626 1627 private: 1628 nsCOMPtr<nsIGlobalObject> mOldEventLoopGlobal; 1629 1630 #ifdef DEBUG 1631 // This is used to checking if we are on the right stack while push the 1632 // mOldEventLoopGlobal back. 1633 nsCOMPtr<nsIGlobalObject> mNewEventLoopGlobal; 1634 #endif 1635 }; 1636 friend class AutoPushEventLoopGlobal; 1637 1638 uint32_t mPostSyncLoopOperations; 1639 1640 // List of operations to do at the end of the last sync event loop. 1641 enum { 1642 eDispatchCancelingRunnable = 0x02, 1643 }; 1644 1645 bool mParentWindowPaused; 1646 1647 bool mWorkerScriptExecutedSuccessfully; 1648 bool mFetchHandlerWasAdded; 1649 bool mMainThreadObjectsForgotten; 1650 bool mIsChromeWorker; 1651 bool mParentFrozen; 1652 1653 // In order to ensure that the debugger can interrupt a busy worker, 1654 // including when atomics are used, we reuse the worker's existing 1655 // JS Interrupt facility used by control runnables. 1656 // Rather that triggering an interrupt immediately when a debugger runnable 1657 // is dispatched, we instead start a timer that will fire if we haven't 1658 // already processed the runnable, targeting the timer's callback at the 1659 // control event target. This allows existing runnables that were going to 1660 // finish in a timely fashion to finish. 1661 nsCOMPtr<nsITimer> mDebuggerInterruptTimer MOZ_GUARDED_BY(mMutex); 1662 1663 // mIsSecureContext is set once in our constructor; after that it can be read 1664 // from various threads. 1665 // 1666 // It's a bit unfortunate that we have to have an out-of-band boolean for 1667 // this, but we need access to this state from the parent thread, and we can't 1668 // use our global object's secure state there. 1669 const bool mIsSecureContext; 1670 1671 bool mDebuggerRegistered MOZ_GUARDED_BY(mMutex); 1672 mozilla::Atomic<bool> mIsInBackground; 1673 bool mIsPlayingAudio{}; 1674 bool mHasActivePeerConnections{}; 1675 1676 // During registration, this worker may be marked as not being ready to 1677 // execute debuggee runnables or content. 1678 // 1679 // Protected by mMutex. 1680 bool mDebuggerReady; 1681 nsTArray<RefPtr<WorkerRunnable>> mDelayedDebuggeeRunnables; 1682 1683 // Whether this worker should have access to the WebExtension API bindings 1684 // (currently only the Extension Background ServiceWorker declared in the 1685 // extension manifest is allowed to access any WebExtension API bindings). 1686 // This default to false, and it is eventually set to true by 1687 // RemoteWorkerChild::ExecWorkerOnMainThread if the needed conditions 1688 // are met. 1689 bool mExtensionAPIAllowed; 1690 1691 // mIsInAutomation is true when we're running in test automation. 1692 // We expose some extra testing functions in that case. 1693 bool mIsInAutomation; 1694 1695 nsString mId; 1696 1697 // This is used to check if it's allowed to share the memory across the agent 1698 // cluster. 1699 const nsILoadInfo::CrossOriginOpenerPolicy mAgentClusterOpenerPolicy; 1700 1701 // Member variable of this class rather than the worker global scope because 1702 // it's received on the main thread, but the global scope is thread-bound 1703 // to the worker thread, so storing the value in the global scope would 1704 // involve sacrificing the thread-bound-ness or using a WorkerRunnable, and 1705 // there isn't a strong reason to store it on the global scope other than 1706 // better consistency with the COEP spec. 1707 Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mEmbedderPolicy; 1708 Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mOwnerEmbedderPolicy; 1709 1710 /* Privileged add-on flag extracted from the AddonPolicy on the nsIPrincipal 1711 * on the main thread when constructing a top-level worker. The flag is 1712 * propagated to nested workers. The flag is only allowed to take effect in 1713 * extension processes and is forbidden in content scripts in content 1714 * processes. The flag may be read on either the parent/owner thread as well 1715 * as on the worker thread itself. When bug 1443925 is fixed allowing 1716 * nsIPrincipal to be used OMT, it may be possible to remove this flag. */ 1717 bool mIsPrivilegedAddonGlobal; 1718 1719 Atomic<uint32_t> mTopLevelWorkerFinishedRunnableCount; 1720 Atomic<uint32_t> mWorkerFinishedRunnableCount; 1721 1722 // A set of active JS async tasks that should prevent idle shutdown. 1723 HashMap<JS::Dispatchable*, RefPtr<StrongWorkerRef>> mPendingJSAsyncTasks; 1724 1725 TargetShutdownTaskSet mShutdownTasks MOZ_GUARDED_BY(mMutex); 1726 bool mShutdownTasksRun MOZ_GUARDED_BY(mMutex) = false; 1727 1728 bool mCCFlagSaysEligible MOZ_GUARDED_BY(mMutex){true}; 1729 1730 // The flag indicates if the worke is idle for events in the main event loop. 1731 bool mWorkerLoopIsIdle MOZ_GUARDED_BY(mMutex){false}; 1732 1733 // This flag is used to ensure we only call NotifyStorageKeyUsed once per 1734 // global. 1735 bool hasNotifiedStorageKeyUsed{false}; 1736 1737 RefPtr<WorkerParentRef> mParentRef; 1738 1739 FontVisibility mFontVisibility; 1740 }; 1741 1742 class AutoSyncLoopHolder { 1743 RefPtr<StrongWorkerRef> mWorkerRef; 1744 nsCOMPtr<nsISerialEventTarget> mTarget; 1745 uint32_t mIndex; 1746 1747 public: 1748 // See CreateNewSyncLoop() for more information about the correct value to use 1749 // for aFailStatus. 1750 AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate, WorkerStatus aFailStatus, 1751 const char* const aName = "AutoSyncLoopHolder"); 1752 1753 ~AutoSyncLoopHolder(); 1754 1755 nsresult Run(); 1756 1757 nsISerialEventTarget* GetSerialEventTarget() const; 1758 }; 1759 1760 /** 1761 * WorkerParentRef is a RefPtr<WorkerPrivate> wrapper for cross-thread access. 1762 * WorkerPrivate needs to be accessed in multiple threads; for example, 1763 * in WorkerParentThreadRunnable, the associated WorkerPrivate must be accessed 1764 * in the worker thread when creating/dispatching and in the parent thread when 1765 * executing. Unfortunately, RefPtr can not be used on this WorkerPrivate since 1766 * it is not a thread-safe ref-counted object. 1767 * 1768 * Instead of using a raw pointer and a complicated mechanism to ensure the 1769 * WorkerPrivate's accessibility. WorkerParentRef is used to resolve the 1770 * problem. WorkerParentRef has a RefPtr<WorkerPrivate> mWorkerPrivate 1771 * initialized on the parent thread when WorkerPrivate::Constructor(). 1772 * WorkerParentRef is a thread-safe ref-counted object that can be copied at 1773 * any thread by WorkerPrivate::GetWorkerParentRef() and propagated to other 1774 * threads. In the target thread, call WorkerParentRef::Private() to get the 1775 * reference for WorkerPrivate or get a nullptr if the Worker has shut down. 1776 * 1777 * Since currently usage cases, WorkerParentRef::Private() will assert to be on 1778 * the parent thread. 1779 */ 1780 class WorkerParentRef final { 1781 public: 1782 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerParentRef); 1783 1784 explicit WorkerParentRef(RefPtr<WorkerPrivate>& aWorkerPrivate); 1785 1786 const RefPtr<WorkerPrivate>& Private() const; 1787 1788 void DropWorkerPrivate(); 1789 1790 private: 1791 ~WorkerParentRef(); 1792 1793 RefPtr<WorkerPrivate> mWorkerPrivate; 1794 }; 1795 1796 } // namespace dom 1797 } // namespace mozilla 1798 1799 #endif /* mozilla_dom_workers_workerprivate_h__ */