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/. */
7 #ifndef mozilla_dom_workers_workerprivate_h__
8 #define mozilla_dom_workers_workerprivate_h__
11 #include "MainThreadUtils.h"
12 #include "ScriptLoader.h"
13 #include "js/ContextOptions.h"
14 #include "mozilla/Atomics.h"
15 #include "mozilla/Attributes.h"
16 #include "mozilla/AutoRestore.h"
17 #include "mozilla/BasePrincipal.h"
18 #include "mozilla/CondVar.h"
19 #include "mozilla/DOMEventTargetHelper.h"
20 #include "mozilla/Maybe.h"
21 #include "mozilla/MozPromise.h"
22 #include "mozilla/OriginTrials.h"
23 #include "mozilla/RelativeTimeline.h"
24 #include "mozilla/Result.h"
25 #include "mozilla/StorageAccess.h"
26 #include "mozilla/ThreadBound.h"
27 #include "mozilla/ThreadSafeWeakPtr.h"
28 #include "mozilla/UniquePtr.h"
29 #include "mozilla/UseCounter.h"
30 #include "mozilla/dom/ClientSource.h"
31 #include "mozilla/dom/FlippedOnce.h"
32 #include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h"
33 #include "mozilla/dom/RemoteWorkerTypes.h"
34 #include "mozilla/dom/Timeout.h"
35 #include "mozilla/dom/quota/CheckedUnsafePtr.h"
36 #include "mozilla/dom/Worker.h"
37 #include "mozilla/dom/WorkerBinding.h"
38 #include "mozilla/dom/WorkerCommon.h"
39 #include "mozilla/dom/WorkerLoadInfo.h"
40 #include "mozilla/dom/WorkerStatus.h"
41 #include "mozilla/dom/workerinternals/JSSettings.h"
42 #include "mozilla/dom/workerinternals/Queue.h"
43 #include "mozilla/dom/JSExecutionManager.h"
44 #include "mozilla/ipc/Endpoint.h"
45 #include "mozilla/net/NeckoChannelParams.h"
46 #include "mozilla/StaticPrefs_extensions.h"
47 #include "nsContentUtils.h"
48 #include "nsIChannel.h"
49 #include "nsIContentPolicy.h"
51 #include "nsIEventTarget.h"
52 #include "nsILoadInfo.h"
53 #include "nsRFPService.h"
54 #include "nsTObserverArray.h"
57 class nsIContentSecurityPolicy
;
58 class nsIThreadInternal
;
65 class ThrottledEventQueue
;
68 class RemoteWorkerChild
;
69 class RemoteWorkerNonLifeCycleOpControllerChild
;
71 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
72 // to be updated too. And histograms enum for worker use counters uses the same
73 // order of worker kind. Please also update dom/base/usecounters.py.
74 enum WorkerKind
: uint8_t {
83 class JSExecutionManager
;
85 class UniqueMessagePortId
;
86 class PerformanceStorage
;
87 class StrongWorkerRef
;
89 class WorkerControlRunnable
;
90 class WorkerCSPEventListener
;
92 class WorkerDebuggerGlobalScope
;
93 class WorkerErrorReport
;
94 class WorkerEventTarget
;
95 class WorkerGlobalScope
;
96 class WorkerParentRef
;
99 class WorkerDebuggeeRunnable
;
101 class WorkerThreadRunnable
;
103 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
104 // object. It exists to avoid changing a lot of code to use Mutex* instead of
106 class MOZ_CAPABILITY("mutex") SharedMutex
{
107 using Mutex
= mozilla::Mutex
;
109 class MOZ_CAPABILITY("mutex") RefCountedMutex final
: public Mutex
{
111 explicit RefCountedMutex(const char* aName
) : Mutex(aName
) {}
113 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex
)
116 ~RefCountedMutex() = default;
119 const RefPtr
<RefCountedMutex
> mMutex
;
122 explicit SharedMutex(const char* aName
)
123 : mMutex(new RefCountedMutex(aName
)) {}
125 SharedMutex(const SharedMutex
& aOther
) = default;
127 operator Mutex
&() MOZ_RETURN_CAPABILITY(this) { return *mMutex
; }
129 operator const Mutex
&() const MOZ_RETURN_CAPABILITY(this) { return *mMutex
; }
131 // We need these to make thread-safety analysis work
132 void Lock() MOZ_CAPABILITY_ACQUIRE() { mMutex
->Lock(); }
133 void Unlock() MOZ_CAPABILITY_RELEASE() { mMutex
->Unlock(); }
135 // We can assert we own 'this', but we can't assert we hold mMutex
136 void AssertCurrentThreadOwns() const
137 MOZ_ASSERT_CAPABILITY(this) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
138 mMutex
->AssertCurrentThreadOwns();
142 nsString
ComputeWorkerPrivateId();
144 class WorkerPrivate final
145 : public RelativeTimeline
,
146 public SupportsCheckedUnsafePtr
<CheckIf
<DiagnosticAssertEnabled
>> {
148 // Callback invoked on the parent thread when the worker's cancellation is
149 // about to be requested. This covers both calls to
150 // WorkerPrivate::Cancel() by the owner as well as self-initiated cancellation
151 // due to top-level script evaluation failing or close() being invoked on the
152 // global scope for Dedicated and Shared workers, but not Service Workers as
153 // they do not expose a close() method.
155 // ### Parent-Initiated Cancellation
157 // When WorkerPrivate::Cancel is invoked on the parent thread (by the binding
158 // exposed Worker::Terminate), this callback is invoked synchronously inside
161 // ### Worker Self-Cancellation
163 // When a worker initiates self-cancellation, the worker's notification to the
164 // parent thread is a non-blocking, async mechanism triggered by
165 // `WorkerPrivate::DispatchCancelingRunnable`.
167 // Self-cancellation races a normally scheduled runnable against a timer that
168 // is scheduled against the parent. The 2 paths initiated by
169 // DispatchCancelingRunnable are:
171 // 1. A CancelingRunnable is dispatched at the worker's normal event target to
172 // wait for the event loop to be clear of runnables. When the
173 // CancelingRunnable runs it will dispatch a CancelingOnParentRunnable to
174 // its parent which is a normal, non-control WorkerDebuggeeRunnable to
175 // ensure that any postMessages to the parent or similar events get a
176 // chance to be processed prior to cancellation. The timer scheduled in
177 // the next bullet will not be canceled unless
179 // 2. A CancelingWithTimeoutOnParentRunnable control runnable is dispatched
180 // to the parent to schedule a timer which will (also) fire on the parent
181 // thread. This handles the case where the worker does not yield
182 // control-flow, and so the normal runnable scheduled above does not get to
183 // run in a timely fashion. Because this is a control runnable, if the
184 // parent is a worker then the runnable will be processed with urgency.
185 // However, if the worker is top-level, then the control-like throttled
186 // WorkerPrivate::mMainThreadEventTarget will end up getting used which is
187 // nsIRunnablePriority::PRIORITY_MEDIUMHIGH and distinct from the
188 // mMainThreadDebuggeeEventTarget which most runnables (like postMessage)
191 // The timer will explicitly use the control event target if the parent is
192 // a worker and the implicit event target (via `NS_NewTimer()`) otherwise.
193 // The callback is CancelingTimerCallback which just calls
194 // WorkerPrivate::Cancel.
195 using CancellationCallback
= std::function
<void(bool aEverRan
)>;
197 // Callback invoked on the parent just prior to dropping the worker thread's
198 // strong reference that keeps the WorkerPrivate alive while the worker thread
199 // is running. This does not provide a guarantee that the underlying thread
200 // has fully shutdown, just that the worker logic has fully shutdown.
204 // The last thing the worker thread's WorkerThreadPrimaryRunnable does before
205 // initiating the shutdown of the underlying thread is call ScheduleDeletion.
206 // ScheduleDeletion dispatches a runnable to the parent to notify it that the
207 // worker has completed its work and will never touch the WorkerPrivate again
208 // and that the strong self-reference can be dropped.
210 // For parents that are themselves workers, this will be done by
211 // WorkerFinishedRunnable which is a WorkerControlRunnable, ensuring that this
212 // is processed in a timely fashion. For main-thread parents,
213 // TopLevelWorkerFinishedRunnable will be used and sent via
214 // mMainThreadEventTargetForMessaging which is a weird ThrottledEventQueue
215 // which does not provide any ordering guarantees relative to
216 // mMainThreadDebuggeeEventTarget, so if you want those, you need to enhance
218 using TerminationCallback
= std::function
<void(void)>;
220 struct LocationInfo
{
232 NS_INLINE_DECL_REFCOUNTING(WorkerPrivate
)
234 static already_AddRefed
<WorkerPrivate
> Constructor(
235 JSContext
* aCx
, const nsAString
& aScriptURL
, bool aIsChromeWorker
,
236 WorkerKind aWorkerKind
, RequestCredentials aRequestCredentials
,
237 const WorkerType aWorkerType
, const nsAString
& aWorkerName
,
238 const nsACString
& aServiceWorkerScope
, WorkerLoadInfo
* aLoadInfo
,
239 ErrorResult
& aRv
, nsString aId
= u
""_ns
,
240 CancellationCallback
&& aCancellationCallback
= {},
241 TerminationCallback
&& aTerminationCallback
= {},
242 mozilla::ipc::Endpoint
<
243 PRemoteWorkerNonLifeCycleOpControllerChild
>&& aChildEp
=
244 mozilla::ipc::Endpoint
<PRemoteWorkerNonLifeCycleOpControllerChild
>());
246 enum LoadGroupBehavior
{ InheritLoadGroup
, OverrideLoadGroup
};
248 static nsresult
GetLoadInfo(
249 JSContext
* aCx
, nsPIDOMWindowInner
* aWindow
, WorkerPrivate
* aParent
,
250 const nsAString
& aScriptURL
, const enum WorkerType
& aWorkerType
,
251 const RequestCredentials
& aCredentials
, bool aIsChromeWorker
,
252 LoadGroupBehavior aLoadGroupBehavior
, WorkerKind aWorkerKind
,
253 WorkerLoadInfo
* aLoadInfo
);
255 void Traverse(nsCycleCollectionTraversalCallback
& aCb
);
257 void ClearSelfAndParentEventTargetRef() {
258 AssertIsOnParentThread();
259 MOZ_ASSERT(mSelfRef
);
261 if (mTerminationCallback
) {
262 mTerminationCallback();
263 mTerminationCallback
= nullptr;
266 mParentEventTargetRef
= nullptr;
270 // May be called on any thread...
273 // Called on the parent thread.
274 bool Notify(WorkerStatus aStatus
);
276 bool Cancel() { return Notify(Canceling
); }
278 bool Close() MOZ_REQUIRES(mMutex
);
280 // The passed principal must be the Worker principal in case of a
281 // ServiceWorker and the loading principal for any other type.
282 static void OverrideLoadInfoLoadGroup(WorkerLoadInfo
& aLoadInfo
,
283 nsIPrincipal
* aPrincipal
);
285 bool IsDebuggerRegistered() MOZ_NO_THREAD_SAFETY_ANALYSIS
{
286 AssertIsOnMainThread();
288 // No need to lock here since this is only ever modified by the same thread.
289 return mDebuggerRegistered
; // would give a thread-safety warning
292 bool ExtensionAPIAllowed() {
294 StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup() &&
295 mExtensionAPIAllowed
);
298 void SetIsDebuggerRegistered(bool aDebuggerRegistered
) {
299 AssertIsOnMainThread();
301 MutexAutoLock
lock(mMutex
);
303 MOZ_ASSERT(mDebuggerRegistered
!= aDebuggerRegistered
);
304 mDebuggerRegistered
= aDebuggerRegistered
;
309 // Mark worker private as running in the background tab
310 // for further throttling
311 void SetIsRunningInBackground();
313 void SetIsRunningInForeground();
315 bool ChangeBackgroundStateInternal(bool aIsBackground
);
317 // returns true, if worker is running in the background tab
318 bool IsRunningInBackground() const { return mIsInBackground
; }
320 void WaitForIsDebuggerRegistered(bool aDebuggerRegistered
) {
321 AssertIsOnParentThread();
323 // Yield so that the main thread won't be blocked.
324 AutoYieldJSThreadExecution yield
;
326 MOZ_ASSERT(!NS_IsMainThread());
328 MutexAutoLock
lock(mMutex
);
330 while (mDebuggerRegistered
!= aDebuggerRegistered
) {
335 nsresult
SetIsDebuggerReady(bool aReady
);
337 WorkerDebugger
* Debugger() const {
338 AssertIsOnMainThread();
340 MOZ_ASSERT(mDebugger
);
344 const OriginTrials
& Trials() const { return mLoadInfo
.mTrials
; }
346 void SetDebugger(WorkerDebugger
* aDebugger
) {
347 AssertIsOnMainThread();
349 MOZ_ASSERT(mDebugger
!= aDebugger
);
350 mDebugger
= aDebugger
;
353 JS::UniqueChars
AdoptDefaultLocale() {
354 MOZ_ASSERT(mDefaultLocale
,
355 "the default locale must have been successfully set for anyone "
356 "to be trying to adopt it");
357 return std::move(mDefaultLocale
);
361 * Invoked by WorkerThreadPrimaryRunnable::Run if it already called
362 * SetWorkerPrivateInWorkerThread but has to bail out on initialization before
363 * calling DoRunLoop because PBackground failed to initialize or something
364 * like that. Note that there's currently no point earlier than this that
365 * failure can be reported.
367 * When this happens, the worker will need to be deleted, plus the call to
368 * SetWorkerPrivateInWorkerThread will have scheduled all the
369 * mPreStartRunnables which need to be cleaned up after, as well as any
370 * scheduled control runnables. We're somewhat punting on debugger runnables
371 * for now, which may leak, but the intent is to moot this whole scenario via
372 * shutdown blockers, so we don't want the extra complexity right now.
374 void RunLoopNeverRan();
377 void DoRunLoop(JSContext
* aCx
);
379 void UnrootGlobalScopes();
381 MOZ_CAN_RUN_SCRIPT
bool InterruptCallback(JSContext
* aCx
);
383 bool IsOnCurrentThread();
385 void CloseInternal();
387 bool FreezeInternal();
391 void PropagateStorageAccessPermissionGrantedInternal();
393 void TraverseTimeouts(nsCycleCollectionTraversalCallback
& aCallback
);
395 void UnlinkTimeouts();
397 bool AddChildWorker(WorkerPrivate
& aChildWorker
);
399 void RemoveChildWorker(WorkerPrivate
& aChildWorker
);
401 void PostMessageToParent(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
402 const Sequence
<JSObject
*>& aTransferable
,
405 void PostMessageToParentMessagePort(JSContext
* aCx
,
406 JS::Handle
<JS::Value
> aMessage
,
407 const Sequence
<JSObject
*>& aTransferable
,
410 MOZ_CAN_RUN_SCRIPT
void EnterDebuggerEventLoop();
412 void LeaveDebuggerEventLoop();
414 void PostMessageToDebugger(const nsAString
& aMessage
);
416 void SetDebuggerImmediate(Function
& aHandler
, ErrorResult
& aRv
);
418 void ReportErrorToDebugger(const nsACString
& aFilename
, uint32_t aLineno
,
419 const nsAString
& aMessage
);
421 bool NotifyInternal(WorkerStatus aStatus
);
423 void ReportError(JSContext
* aCx
, JS::ConstUTF8CharsZ aToStringResult
,
424 JSErrorReport
* aReport
);
426 static void ReportErrorToConsole(
427 uint32_t aErrorFlags
, const nsCString
& aCategory
,
428 nsContentUtils::PropertiesFile aFile
, const nsCString
& aMessageName
,
429 const nsTArray
<nsString
>& aParams
= nsTArray
<nsString
>(),
430 const mozilla::SourceLocation
& aLocation
=
431 mozilla::JSCallingLocation::Get());
433 int32_t SetTimeout(JSContext
* aCx
, TimeoutHandler
* aHandler
, int32_t aTimeout
,
434 bool aIsInterval
, Timeout::Reason aReason
,
437 void ClearTimeout(int32_t aId
, Timeout::Reason aReason
);
439 MOZ_CAN_RUN_SCRIPT
bool RunExpiredTimeouts(JSContext
* aCx
);
441 bool RescheduleTimeoutTimer(JSContext
* aCx
);
443 void UpdateContextOptionsInternal(JSContext
* aCx
,
444 const JS::ContextOptions
& aContextOptions
);
446 void UpdateLanguagesInternal(const nsTArray
<nsString
>& aLanguages
);
448 void UpdateJSWorkerMemoryParameterInternal(JSContext
* aCx
, JSGCParamKey key
,
449 Maybe
<uint32_t> aValue
);
451 enum WorkerRanOrNot
{ WorkerNeverRan
= 0, WorkerRan
};
453 void ScheduleDeletion(WorkerRanOrNot aRanOrNot
);
455 bool CollectRuntimeStats(JS::RuntimeStats
* aRtStats
, bool aAnonymize
);
458 void UpdateGCZealInternal(JSContext
* aCx
, uint8_t aGCZeal
,
459 uint32_t aFrequency
);
462 void SetLowMemoryStateInternal(JSContext
* aCx
, bool aState
);
464 void GarbageCollectInternal(JSContext
* aCx
, bool aShrinking
,
465 bool aCollectChildren
);
467 void CycleCollectInternal(bool aCollectChildren
);
469 void OfflineStatusChangeEventInternal(bool aIsOffline
);
471 void MemoryPressureInternal();
473 typedef MozPromise
<uint64_t, nsresult
, true> JSMemoryUsagePromise
;
474 RefPtr
<JSMemoryUsagePromise
> GetJSMemoryUsage();
476 void SetFetchHandlerWasAdded() {
477 MOZ_ASSERT(IsServiceWorker());
478 AssertIsOnWorkerThread();
479 mFetchHandlerWasAdded
= true;
482 bool FetchHandlerWasAdded() const {
483 MOZ_ASSERT(IsServiceWorker());
484 AssertIsOnWorkerThread();
485 return mFetchHandlerWasAdded
;
488 JSContext
* GetJSContext() const MOZ_NO_THREAD_SAFETY_ANALYSIS
{
489 // mJSContext is only modified on the worker thread, so workerthread code
490 // can safely read it without a lock
491 AssertIsOnWorkerThread();
495 WorkerGlobalScope
* GlobalScope() const {
496 auto data
= mWorkerThreadAccessible
.Access();
500 WorkerDebuggerGlobalScope
* DebuggerGlobalScope() const {
501 auto data
= mWorkerThreadAccessible
.Access();
502 return data
->mDebuggerScope
;
505 // Get the global associated with the current nested event loop. Will return
506 // null if we're not in a nested event loop or that nested event loop does not
507 // have an associated global.
508 nsIGlobalObject
* GetCurrentEventLoopGlobal() const {
509 auto data
= mWorkerThreadAccessible
.Access();
510 return data
->mCurrentEventLoopGlobal
;
513 nsICSPEventListener
* CSPEventListener() const;
515 void SetThread(WorkerThread
* aThread
);
517 void SetWorkerPrivateInWorkerThread(WorkerThread
* aThread
);
519 void ResetWorkerPrivateInWorkerThread();
521 bool IsOnWorkerThread() const;
523 void AssertIsOnWorkerThread() const
532 void BeginCTypesCall();
535 void EndCTypesCall();
537 void BeginCTypesCallback();
539 void EndCTypesCallback();
541 bool ConnectMessagePort(JSContext
* aCx
, UniqueMessagePortId
& aIdentifier
);
543 WorkerGlobalScope
* GetOrCreateGlobalScope(JSContext
* aCx
);
545 WorkerDebuggerGlobalScope
* CreateDebuggerGlobalScope(JSContext
* aCx
);
547 bool RegisterBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
549 bool RegisterDebuggerBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
551 bool OnLine() const {
552 auto data
= mWorkerThreadAccessible
.Access();
553 return data
->mOnLine
;
556 void StopSyncLoop(nsIEventTarget
* aSyncLoopTarget
, nsresult aResult
);
558 bool MaybeStopSyncLoop(nsIEventTarget
* aSyncLoopTarget
, nsresult aResult
);
560 void ShutdownModuleLoader();
562 void ClearPreStartRunnables();
564 MOZ_CAN_RUN_SCRIPT
void ProcessSingleDebuggerRunnable();
565 void ClearDebuggerEventQueue();
567 void OnProcessNextEvent();
569 void AfterProcessNextEvent();
571 void AssertValidSyncLoop(nsIEventTarget
* aSyncLoopTarget
)
579 void AssertIsNotPotentiallyLastGCCCRunning() {
580 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
581 auto data
= mWorkerThreadAccessible
.Access();
582 MOZ_DIAGNOSTIC_ASSERT(!data
->mIsPotentiallyLastGCCCRunning
);
586 void SetWorkerScriptExecutedSuccessfully() {
587 AssertIsOnWorkerThread();
588 // Should only be called once!
589 MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully
);
590 mWorkerScriptExecutedSuccessfully
= true;
593 // Only valid after CompileScriptRunnable has finished running!
594 bool WorkerScriptExecutedSuccessfully() const {
595 AssertIsOnWorkerThread();
596 return mWorkerScriptExecutedSuccessfully
;
599 // Get the event target to use when dispatching to the main thread
600 // from this Worker thread. This may be the main thread itself or
601 // a ThrottledEventQueue to the main thread.
602 nsISerialEventTarget
* MainThreadEventTargetForMessaging();
604 nsresult
DispatchToMainThreadForMessaging(
605 nsIRunnable
* aRunnable
, uint32_t aFlags
= NS_DISPATCH_NORMAL
);
607 nsresult
DispatchToMainThreadForMessaging(
608 already_AddRefed
<nsIRunnable
> aRunnable
,
609 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
611 nsISerialEventTarget
* MainThreadEventTarget();
613 nsresult
DispatchToMainThread(nsIRunnable
* aRunnable
,
614 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
616 nsresult
DispatchToMainThread(already_AddRefed
<nsIRunnable
> aRunnable
,
617 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
619 nsresult
DispatchDebuggeeToMainThread(
620 already_AddRefed
<WorkerRunnable
> aRunnable
,
621 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
623 // Get an event target that will dispatch runnables as control runnables on
624 // the worker thread. Implement nsICancelableRunnable if you wish to take
625 // action on cancelation.
626 nsISerialEventTarget
* ControlEventTarget();
628 // Get an event target that will attempt to dispatch a normal WorkerRunnable,
629 // but if that fails will then fall back to a control runnable.
630 nsISerialEventTarget
* HybridEventTarget();
632 void DumpCrashInformation(nsACString
& aString
);
634 ClientType
GetClientType() const;
636 bool EnsureCSPEventListener();
638 void EnsurePerformanceStorage();
640 bool GetExecutionGranted() const;
641 void SetExecutionGranted(bool aGranted
);
643 void ScheduleTimeSliceExpiration(uint32_t aDelay
);
644 void CancelTimeSliceExpiration();
646 JSExecutionManager
* GetExecutionManager() const;
647 void SetExecutionManager(JSExecutionManager
* aManager
);
649 void ExecutionReady();
651 PerformanceStorage
* GetPerformanceStorage();
653 bool IsAcceptingEvents() MOZ_EXCLUDES(mMutex
) {
654 AssertIsOnParentThread();
656 MutexAutoLock
lock(mMutex
);
657 return mParentStatus
< Canceling
;
660 // This method helps know if the Worker is already at Dead status.
661 // Note that it is racy. The status may change after the function returns.
662 bool IsDead() MOZ_EXCLUDES(mMutex
) {
663 MutexAutoLock
lock(mMutex
);
664 return mStatus
== Dead
;
667 WorkerStatus
ParentStatusProtected() {
668 AssertIsOnParentThread();
669 MutexAutoLock
lock(mMutex
);
670 return mParentStatus
;
673 WorkerStatus
ParentStatus() const MOZ_REQUIRES(mMutex
) {
674 mMutex
.AssertCurrentThreadOwns();
675 return mParentStatus
;
678 Worker
* ParentEventTargetRef() const {
679 MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef
);
680 return mParentEventTargetRef
;
683 void SetParentEventTargetRef(Worker
* aParentEventTargetRef
) {
684 MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef
);
685 MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef
);
686 mParentEventTargetRef
= aParentEventTargetRef
;
689 // Check whether this worker is a secure context. For use from the parent
690 // thread only; the canonical "is secure context" boolean is stored on the
691 // compartment of the worker global. The only reason we don't
692 // AssertIsOnParentThread() here is so we can assert that this value matches
693 // the one on the compartment, which has to be done from the worker thread.
694 bool IsSecureContext() const { return mIsSecureContext
; }
696 // Check whether we're running in automation.
697 bool IsInAutomation() const { return mIsInAutomation
; }
699 bool IsPrivilegedAddonGlobal() const { return mIsPrivilegedAddonGlobal
; }
701 TimeStamp
CreationTimeStamp() const { return mCreationTimeStamp
; }
703 DOMHighResTimeStamp
CreationTime() const { return mCreationTimeHighRes
; }
705 DOMHighResTimeStamp
TimeStampToDOMHighRes(const TimeStamp
& aTimeStamp
) const {
706 MOZ_ASSERT(!aTimeStamp
.IsNull());
707 TimeDuration duration
= aTimeStamp
- mCreationTimeStamp
;
708 return duration
.ToMilliseconds();
711 LocationInfo
& GetLocationInfo() { return mLocationInfo
; }
713 void CopyJSSettings(workerinternals::JSSettings
& aSettings
) {
714 mozilla::MutexAutoLock
lock(mMutex
);
715 aSettings
= mJSSettings
;
718 void CopyJSRealmOptions(JS::RealmOptions
& aOptions
) {
719 mozilla::MutexAutoLock
lock(mMutex
);
720 aOptions
= IsChromeWorker() ? mJSSettings
.chromeRealmOptions
721 : mJSSettings
.contentRealmOptions
;
724 // The ability to be a chrome worker is orthogonal to the type of
725 // worker [Dedicated|Shared|Service].
726 bool IsChromeWorker() const { return mIsChromeWorker
; }
728 // TODO: Invariants require that the parent worker out-live any child
729 // worker, so WorkerPrivate* should be safe in the moment of calling.
730 // We would like to have stronger type-system annotated/enforced handling.
731 WorkerPrivate
* GetParent() const { return mParent
; }
733 // Returns the top level worker. It can be the current worker if it's the top
735 WorkerPrivate
* GetTopLevelWorker() const {
736 WorkerPrivate
const* wp
= this;
737 while (wp
->GetParent()) {
738 wp
= wp
->GetParent();
740 return const_cast<WorkerPrivate
*>(wp
);
743 bool IsFrozen() const;
745 bool IsFrozenForWorkerThread() const;
747 bool IsParentWindowPaused() const {
748 AssertIsOnParentThread();
749 return mParentWindowPaused
;
752 // When we debug a worker, we want to disconnect the window and the worker
753 // communication. This happens calling this method.
754 // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
755 void ParentWindowPaused();
757 void ParentWindowResumed();
759 const nsString
& ScriptURL() const { return mScriptURL
; }
761 const nsString
& WorkerName() const { return mWorkerName
; }
762 RequestCredentials
WorkerCredentials() const { return mCredentialsMode
; }
763 enum WorkerType
WorkerType() const { return mWorkerType
; }
765 WorkerKind
Kind() const { return mWorkerKind
; }
767 bool IsDedicatedWorker() const { return mWorkerKind
== WorkerKindDedicated
; }
769 bool IsSharedWorker() const { return mWorkerKind
== WorkerKindShared
; }
771 bool IsServiceWorker() const { return mWorkerKind
== WorkerKindService
; }
773 nsContentPolicyType
ContentPolicyType() const {
774 return ContentPolicyType(mWorkerKind
);
777 static nsContentPolicyType
ContentPolicyType(WorkerKind aWorkerKind
) {
778 switch (aWorkerKind
) {
779 case WorkerKindDedicated
:
780 return nsIContentPolicy::TYPE_INTERNAL_WORKER
;
781 case WorkerKindShared
:
782 return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
;
783 case WorkerKindService
:
784 return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER
;
786 MOZ_ASSERT_UNREACHABLE("Invalid worker type");
787 return nsIContentPolicy::TYPE_INVALID
;
791 nsIScriptContext
* GetScriptContext() const {
792 AssertIsOnMainThread();
793 return mLoadInfo
.mScriptContext
;
796 const nsCString
& Domain() const { return mLoadInfo
.mDomain
; }
798 bool IsFromWindow() const { return mLoadInfo
.mFromWindow
; }
800 nsLoadFlags
GetLoadFlags() const { return mLoadInfo
.mLoadFlags
; }
802 uint64_t WindowID() const { return mLoadInfo
.mWindowID
; }
804 uint64_t AssociatedBrowsingContextID() const {
805 return mLoadInfo
.mAssociatedBrowsingContextID
;
808 uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); }
810 const nsCString
& ServiceWorkerScope() const {
811 return GetServiceWorkerDescriptor().Scope();
814 // This value should never change after the script load completes. Before
815 // then, it may only be called on the main thread.
816 nsIURI
* GetBaseURI() const { return mLoadInfo
.mBaseURI
; }
818 void SetBaseURI(nsIURI
* aBaseURI
);
820 nsIURI
* GetResolvedScriptURI() const { return mLoadInfo
.mResolvedScriptURI
; }
822 const nsString
& ServiceWorkerCacheName() const {
823 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
824 AssertIsOnMainThread();
825 return mLoadInfo
.mServiceWorkerCacheName
;
828 const ServiceWorkerDescriptor
& GetServiceWorkerDescriptor() const {
829 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
830 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
831 return mLoadInfo
.mServiceWorkerDescriptor
.ref();
834 const ServiceWorkerRegistrationDescriptor
&
835 GetServiceWorkerRegistrationDescriptor() const {
836 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
837 MOZ_DIAGNOSTIC_ASSERT(
838 mLoadInfo
.mServiceWorkerRegistrationDescriptor
.isSome());
839 return mLoadInfo
.mServiceWorkerRegistrationDescriptor
.ref();
842 const ClientInfo
& GetSourceInfo() const {
843 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
844 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mSourceInfo
.isSome());
845 return mLoadInfo
.mSourceInfo
.ref();
848 void UpdateServiceWorkerState(ServiceWorkerState aState
) {
849 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
850 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
851 return mLoadInfo
.mServiceWorkerDescriptor
.ref().SetState(aState
);
854 void UpdateIsOnContentBlockingAllowList(bool aOnContentBlockingAllowList
);
856 const Maybe
<ServiceWorkerDescriptor
>& GetParentController() const {
857 return mLoadInfo
.mParentController
;
860 const ChannelInfo
& GetChannelInfo() const { return mLoadInfo
.mChannelInfo
; }
862 void SetChannelInfo(const ChannelInfo
& aChannelInfo
) {
863 AssertIsOnMainThread();
864 MOZ_ASSERT(!mLoadInfo
.mChannelInfo
.IsInitialized());
865 MOZ_ASSERT(aChannelInfo
.IsInitialized());
866 mLoadInfo
.mChannelInfo
= aChannelInfo
;
869 void InitChannelInfo(nsIChannel
* aChannel
) {
870 mLoadInfo
.mChannelInfo
.InitFromChannel(aChannel
);
873 void InitChannelInfo(const ChannelInfo
& aChannelInfo
) {
874 mLoadInfo
.mChannelInfo
= aChannelInfo
;
877 nsIPrincipal
* GetPrincipal() const { return mLoadInfo
.mPrincipal
; }
879 nsIPrincipal
* GetLoadingPrincipal() const {
880 return mLoadInfo
.mLoadingPrincipal
;
883 nsIPrincipal
* GetPartitionedPrincipal() const {
884 return mLoadInfo
.mPartitionedPrincipal
;
887 nsIPrincipal
* GetEffectiveStoragePrincipal() const;
889 nsILoadGroup
* GetLoadGroup() const {
890 AssertIsOnMainThread();
891 return mLoadInfo
.mLoadGroup
;
894 bool UsesSystemPrincipal() const {
895 return GetPrincipal()->IsSystemPrincipal();
897 bool UsesAddonOrExpandedAddonPrincipal() const {
898 return GetPrincipal()->GetIsAddonOrExpandedAddonPrincipal();
901 const mozilla::ipc::PrincipalInfo
& GetPrincipalInfo() const {
902 return *mLoadInfo
.mPrincipalInfo
;
905 const mozilla::ipc::PrincipalInfo
& GetPartitionedPrincipalInfo() const {
906 return *mLoadInfo
.mPartitionedPrincipalInfo
;
909 const mozilla::ipc::PrincipalInfo
& GetEffectiveStoragePrincipalInfo() const;
911 already_AddRefed
<nsIChannel
> ForgetWorkerChannel() {
912 AssertIsOnMainThread();
913 return mLoadInfo
.mChannel
.forget();
916 nsPIDOMWindowInner
* GetWindow() const {
917 AssertIsOnMainThread();
918 return mLoadInfo
.mWindow
;
921 nsPIDOMWindowInner
* GetAncestorWindow() const;
923 void EvictFromBFCache();
925 nsIContentSecurityPolicy
* GetCsp() const {
926 AssertIsOnMainThread();
927 return mLoadInfo
.mCSP
;
930 void SetCsp(nsIContentSecurityPolicy
* aCSP
);
932 nsresult
SetCSPFromHeaderValues(const nsACString
& aCSPHeaderValue
,
933 const nsACString
& aCSPReportOnlyHeaderValue
);
935 void StoreCSPOnClient();
937 const mozilla::ipc::CSPInfo
& GetCSPInfo() const {
938 return *mLoadInfo
.mCSPInfo
;
941 void UpdateReferrerInfoFromHeader(
942 const nsACString
& aReferrerPolicyHeaderValue
);
944 nsIReferrerInfo
* GetReferrerInfo() const { return mLoadInfo
.mReferrerInfo
; }
946 ReferrerPolicy
GetReferrerPolicy() const {
947 return mLoadInfo
.mReferrerInfo
->ReferrerPolicy();
950 void SetReferrerInfo(nsIReferrerInfo
* aReferrerInfo
) {
951 mLoadInfo
.mReferrerInfo
= aReferrerInfo
;
954 bool IsEvalAllowed() const { return mLoadInfo
.mEvalAllowed
; }
956 void SetEvalAllowed(bool aAllowed
) { mLoadInfo
.mEvalAllowed
= aAllowed
; }
958 bool GetReportEvalCSPViolations() const {
959 return mLoadInfo
.mReportEvalCSPViolations
;
962 void SetReportEvalCSPViolations(bool aReport
) {
963 mLoadInfo
.mReportEvalCSPViolations
= aReport
;
966 bool IsWasmEvalAllowed() const { return mLoadInfo
.mWasmEvalAllowed
; }
968 void SetWasmEvalAllowed(bool aAllowed
) {
969 mLoadInfo
.mWasmEvalAllowed
= aAllowed
;
972 bool GetReportWasmEvalCSPViolations() const {
973 return mLoadInfo
.mReportWasmEvalCSPViolations
;
976 void SetReportWasmEvalCSPViolations(bool aReport
) {
977 mLoadInfo
.mReportWasmEvalCSPViolations
= aReport
;
980 bool XHRParamsAllowed() const { return mLoadInfo
.mXHRParamsAllowed
; }
982 void SetXHRParamsAllowed(bool aAllowed
) {
983 mLoadInfo
.mXHRParamsAllowed
= aAllowed
;
986 mozilla::StorageAccess
StorageAccess() const {
987 AssertIsOnWorkerThread();
988 if (mLoadInfo
.mUsingStorageAccess
) {
989 return mozilla::StorageAccess::eAllow
;
992 return mLoadInfo
.mStorageAccess
;
995 bool UseRegularPrincipal() const {
996 AssertIsOnWorkerThread();
997 return mLoadInfo
.mUseRegularPrincipal
;
1000 bool UsingStorageAccess() const {
1001 AssertIsOnWorkerThread();
1002 return mLoadInfo
.mUsingStorageAccess
;
1005 nsICookieJarSettings
* CookieJarSettings() const {
1007 MOZ_ASSERT(mLoadInfo
.mCookieJarSettings
);
1008 return mLoadInfo
.mCookieJarSettings
;
1011 const net::CookieJarSettingsArgs
& CookieJarSettingsArgs() const {
1012 MOZ_ASSERT(mLoadInfo
.mCookieJarSettings
);
1013 return mLoadInfo
.mCookieJarSettingsArgs
;
1016 const OriginAttributes
& GetOriginAttributes() const {
1017 return mLoadInfo
.mOriginAttributes
;
1020 // Determine if the SW testing per-window flag is set by devtools
1021 bool ServiceWorkersTestingInWindow() const {
1022 return mLoadInfo
.mServiceWorkersTestingInWindow
;
1025 // Determine if the worker was created under a third-party context.
1026 bool IsThirdPartyContext() const { return mLoadInfo
.mIsThirdPartyContext
; }
1028 bool IsWatchedByDevTools() const { return mLoadInfo
.mWatchedByDevTools
; }
1030 bool ShouldResistFingerprinting(RFPTarget aTarget
) const;
1032 const Maybe
<RFPTargetSet
>& GetOverriddenFingerprintingSettings() const {
1033 return mLoadInfo
.mOverriddenFingerprintingSettings
;
1036 bool IsOn3PCBExceptionList() const {
1037 return mLoadInfo
.mIsOn3PCBExceptionList
;
1040 RemoteWorkerChild
* GetRemoteWorkerController();
1042 void SetRemoteWorkerController(RemoteWorkerChild
* aController
);
1044 RefPtr
<GenericPromise
> SetServiceWorkerSkipWaitingFlag();
1046 // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
1047 // as these are only used for globals going in and out of the bfcache.
1048 bool Freeze(const nsPIDOMWindowInner
* aWindow
);
1050 bool Thaw(const nsPIDOMWindowInner
* aWindow
);
1052 void PropagateStorageAccessPermissionGranted();
1054 void NotifyStorageKeyUsed();
1056 void EnableDebugger();
1058 void DisableDebugger();
1060 already_AddRefed
<WorkerRunnable
> MaybeWrapAsWorkerRunnable(
1061 already_AddRefed
<nsIRunnable
> aRunnable
);
1063 bool ProxyReleaseMainThreadObjects();
1065 void SetLowMemoryState(bool aState
);
1067 void GarbageCollect(bool aShrinking
);
1069 void CycleCollect();
1071 nsresult
SetPrincipalsAndCSPOnMainThread(nsIPrincipal
* aPrincipal
,
1072 nsIPrincipal
* aPartitionedPrincipal
,
1073 nsILoadGroup
* aLoadGroup
,
1074 nsIContentSecurityPolicy
* aCsp
);
1076 nsresult
SetPrincipalsAndCSPFromChannel(nsIChannel
* aChannel
);
1078 bool FinalChannelPrincipalIsValid(nsIChannel
* aChannel
);
1080 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1081 bool PrincipalURIMatchesScriptURL();
1084 void UpdateOverridenLoadGroup(nsILoadGroup
* aBaseLoadGroup
);
1086 void WorkerScriptLoaded();
1088 Document
* GetDocument() const;
1090 void MemoryPressure();
1092 void UpdateContextOptions(const JS::ContextOptions
& aContextOptions
);
1094 void UpdateLanguages(const nsTArray
<nsString
>& aLanguages
);
1096 void UpdateJSWorkerMemoryParameter(JSGCParamKey key
, Maybe
<uint32_t> value
);
1099 void UpdateGCZeal(uint8_t aGCZeal
, uint32_t aFrequency
);
1102 void OfflineStatusChangeEvent(bool aIsOffline
);
1104 nsresult
Dispatch(already_AddRefed
<WorkerRunnable
> aRunnable
,
1105 nsIEventTarget
* aSyncLoopTarget
= nullptr);
1107 nsresult
DispatchControlRunnable(
1108 already_AddRefed
<WorkerRunnable
> aWorkerRunnable
);
1110 nsresult
DispatchDebuggerRunnable(
1111 already_AddRefed
<WorkerRunnable
> aDebuggerRunnable
);
1113 nsresult
DispatchToParent(already_AddRefed
<WorkerRunnable
> aRunnable
);
1115 bool IsOnParentThread() const;
1116 void DebuggerInterruptRequest();
1119 void AssertIsOnParentThread() const;
1121 void AssertInnerWindowIsCorrect() const;
1123 void AssertIsOnParentThread() const {}
1125 void AssertInnerWindowIsCorrect() const {}
1128 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1129 bool PrincipalIsValid() const;
1132 void StartCancelingTimer();
1134 const nsAString
& Id();
1136 const nsID
& AgentClusterId() const { return mAgentClusterId
; }
1138 bool IsSharedMemoryAllowed() const;
1140 // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated
1141 bool CrossOriginIsolated() const;
1143 void SetUseCounter(UseCounterWorker aUseCounter
) {
1144 MOZ_ASSERT(!mReportedUseCounters
);
1145 MOZ_ASSERT(aUseCounter
> UseCounterWorker::Unknown
);
1146 AssertIsOnWorkerThread();
1147 mUseCounters
[static_cast<size_t>(aUseCounter
)] = true;
1153 * If browser.tabs.remote.useCrossOriginEmbedderPolicy=false, these methods
1154 * will, depending on the return type, return a value that will avoid
1155 * assertion failures or a value that won't block loads.
1157 nsILoadInfo::CrossOriginEmbedderPolicy
GetEmbedderPolicy() const;
1159 // Fails if a policy has already been set or if `aPolicy` violates the owner's
1160 // policy, if an owner exists.
1161 mozilla::Result
<Ok
, nsresult
> SetEmbedderPolicy(
1162 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy
);
1164 // `aRequest` is the request loading the worker and must be QI-able to
1165 // `nsIChannel*`. It's used to verify that the worker can indeed inherit its
1166 // owner's COEP (when an owner exists).
1168 // TODO: remove `aRequest`; currently, it's required because instances may not
1169 // always know its final, resolved script URL or have access internally to
1171 void InheritOwnerEmbedderPolicyOrNull(nsIRequest
* aRequest
);
1173 // Requires a policy to already have been set.
1174 bool MatchEmbedderPolicy(
1175 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy
) const;
1177 nsILoadInfo::CrossOriginEmbedderPolicy
GetOwnerEmbedderPolicy() const;
1179 void SetCCCollectedAnything(bool collectedAnything
);
1180 bool isLastCCCollectedAnything();
1182 uint32_t GetCurrentTimerNestingLevel() const;
1184 void IncreaseTopLevelWorkerFinishedRunnableCount() {
1185 ++mTopLevelWorkerFinishedRunnableCount
;
1187 void DecreaseTopLevelWorkerFinishedRunnableCount() {
1188 --mTopLevelWorkerFinishedRunnableCount
;
1190 void IncreaseWorkerFinishedRunnableCount() { ++mWorkerFinishedRunnableCount
; }
1191 void DecreaseWorkerFinishedRunnableCount() { --mWorkerFinishedRunnableCount
; }
1193 void RunShutdownTasks();
1195 bool CancelBeforeWorkerScopeConstructed() const {
1196 auto data
= mWorkerThreadAccessible
.Access();
1197 return data
->mCancelBeforeWorkerScopeConstructed
;
1200 enum class CCFlag
: uint8_t {
1201 EligibleForWorkerRef
,
1202 IneligibleForWorkerRef
,
1203 EligibleForChildWorker
,
1204 IneligibleForChildWorker
,
1206 IneligibleForTimeout
,
1207 CheckBackgroundActors
,
1210 // When create/release a StrongWorkerRef, child worker, and timeout, this
1211 // method is used to setup if mParentEventTargetRef can get into
1212 // cycle-collection.
1213 // When this method is called, it will also checks if any background actor
1214 // should block the mParentEventTargetRef cycle-collection when there is no
1215 // StrongWorkerRef/ChildWorker/Timeout.
1216 // Worker thread only.
1217 void UpdateCCFlag(const CCFlag
);
1219 // This is used in WorkerPrivate::Traverse() to checking if
1220 // mParentEventTargetRef should get into cycle-collection.
1221 // Parent thread only method.
1222 bool IsEligibleForCC();
1224 // A method which adjusts the count of background actors which should not
1225 // block WorkerPrivate::mParentEventTargetRef cycle-collection.
1226 // Worker thread only.
1227 void AdjustNonblockingCCBackgroundActorCount(int32_t aCount
);
1229 RefPtr
<WorkerParentRef
> GetWorkerParentRef() const;
1231 bool MayContinueRunning() {
1232 AssertIsOnWorkerThread();
1234 WorkerStatus status
;
1236 MutexAutoLock
lock(mMutex
);
1240 if (status
< Canceling
) {
1249 WorkerPrivate
* aParent
, const nsAString
& aScriptURL
, bool aIsChromeWorker
,
1250 WorkerKind aWorkerKind
, RequestCredentials aRequestCredentials
,
1251 enum WorkerType aWorkerType
, const nsAString
& aWorkerName
,
1252 const nsACString
& aServiceWorkerScope
, WorkerLoadInfo
& aLoadInfo
,
1253 nsString
&& aId
, const nsID
& aAgentClusterId
,
1254 const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy
,
1255 CancellationCallback
&& aCancellationCallback
,
1256 TerminationCallback
&& aTerminationCallback
,
1257 mozilla::ipc::Endpoint
<PRemoteWorkerNonLifeCycleOpControllerChild
>&&
1262 struct AgentClusterIdAndCoop
{
1264 nsILoadInfo::CrossOriginOpenerPolicy mCoop
;
1267 static AgentClusterIdAndCoop
ComputeAgentClusterIdAndCoop(
1268 WorkerPrivate
* aParent
, WorkerKind aWorkerKind
, WorkerLoadInfo
* aLoadInfo
,
1269 bool aIsChromeWorker
);
1271 void CancelAllTimeouts();
1273 enum class ProcessAllControlRunnablesResult
{
1274 // We did not process anything.
1276 // We did process something, states may have changed, but we can keep
1277 // executing script.
1279 // We did process something, and should not continue executing script.
1283 ProcessAllControlRunnablesResult
ProcessAllControlRunnables() {
1284 MutexAutoLock
lock(mMutex
);
1285 return ProcessAllControlRunnablesLocked();
1288 ProcessAllControlRunnablesResult
ProcessAllControlRunnablesLocked()
1289 MOZ_REQUIRES(mMutex
);
1291 void EnableMemoryReporter();
1293 void DisableMemoryReporter();
1295 void WaitForWorkerEvents() MOZ_REQUIRES(mMutex
);
1297 // If the worker shutdown status is equal or greater then aFailStatus, this
1298 // operation will fail and nullptr will be returned. See WorkerStatus.h for
1299 // more information about the correct value to use.
1300 already_AddRefed
<nsISerialEventTarget
> CreateNewSyncLoop(
1301 WorkerStatus aFailStatus
);
1303 nsresult
RunCurrentSyncLoop();
1305 nsresult
DestroySyncLoop(uint32_t aLoopIndex
);
1307 void InitializeGCTimers();
1309 enum GCTimerMode
{ PeriodicTimer
= 0, IdleTimer
, NoTimer
};
1311 void SetGCTimerMode(GCTimerMode aMode
);
1314 void CancelGCTimers() { SetGCTimerMode(NoTimer
); }
1317 void ShutdownGCTimers();
1319 friend class WorkerRef
;
1321 bool AddWorkerRef(WorkerRef
* aWorkerRefer
, WorkerStatus aFailStatus
);
1323 void RemoveWorkerRef(WorkerRef
* aWorkerRef
);
1325 void NotifyWorkerRefs(WorkerStatus aStatus
);
1327 bool HasActiveWorkerRefs() {
1328 auto data
= mWorkerThreadAccessible
.Access();
1329 return !(data
->mChildWorkers
.IsEmpty() && data
->mTimeouts
.IsEmpty() &&
1330 data
->mWorkerRefs
.IsEmpty());
1333 friend class WorkerEventTarget
;
1335 nsresult
RegisterShutdownTask(nsITargetShutdownTask
* aTask
);
1337 nsresult
UnregisterShutdownTask(nsITargetShutdownTask
* aTask
);
1339 // Internal logic to dispatch a runnable. This is separate from Dispatch()
1340 // to allow runnables to be atomically dispatched in bulk.
1341 nsresult
DispatchLockHeld(already_AddRefed
<WorkerRunnable
> aRunnable
,
1342 nsIEventTarget
* aSyncLoopTarget
,
1343 const MutexAutoLock
& aProofOfLock
)
1344 MOZ_REQUIRES(mMutex
);
1346 // This method dispatches a simple runnable that starts the shutdown procedure
1347 // after a self.close(). This method is called after a ClearMainEventQueue()
1348 // to be sure that the canceling runnable is the only one in the queue. We
1349 // need this async operation to be sure that all the current JS code is
1351 void DispatchCancelingRunnable();
1353 bool GetUseCounter(UseCounterWorker aUseCounter
) {
1354 MOZ_ASSERT(aUseCounter
> UseCounterWorker::Unknown
);
1355 AssertIsOnWorkerThread();
1356 return mUseCounters
[static_cast<size_t>(aUseCounter
)];
1359 void ReportUseCounters();
1361 UniquePtr
<ClientSource
> CreateClientSource();
1363 // This method is called when corresponding script loader processes the COEP
1364 // header for the worker.
1365 // This method should be called only once in the main thread.
1366 // After this method is called the COEP value owner(window/parent worker) is
1367 // cached in mOwnerEmbedderPolicy such that it can be accessed in other
1368 // threads, i.e. WorkerThread.
1369 void EnsureOwnerEmbedderPolicy();
1372 friend class EventTarget
;
1373 friend class AutoSyncLoopHolder
;
1377 class MemoryReporter
;
1378 friend class MemoryReporter
;
1380 friend class mozilla::dom::WorkerThread
;
1383 mozilla::CondVar mCondVar
MOZ_GUARDED_BY(mMutex
);
1385 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1386 // our static assert
1387 MOZ_NON_OWNING_REF WorkerPrivate
* const mParent
;
1389 const nsString mScriptURL
;
1391 // This is the worker name for shared workers and dedicated workers.
1392 const nsString mWorkerName
;
1393 const RequestCredentials mCredentialsMode
;
1394 enum WorkerType mWorkerType
;
1396 const WorkerKind mWorkerKind
;
1398 // The worker is owned by its thread, which is represented here. This is set
1399 // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
1400 // traversed by the cycle collector if no other things preventing shutdown.
1402 // There are 4 ways a worker can be terminated:
1403 // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
1404 // traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed
1405 // Worker webidl object. Doing this, CC will be able to detect a cycle and
1406 // Unlink is called. In Unlink, Worker calls Cancel().
1407 // 2. Worker::Cancel() is called - the shutdown procedure starts immediately.
1408 // 3. WorkerScope::Close() is called - Similar to point 2.
1409 // 4. xpcom-shutdown notification - We call Kill().
1410 RefPtr
<Worker
> mParentEventTargetRef
;
1411 RefPtr
<WorkerPrivate
> mSelfRef
;
1413 CancellationCallback mCancellationCallback
;
1415 // The termination callback is passed into the constructor on the parent
1416 // thread and invoked by `ClearSelfAndParentEventTargetRef` just before it
1417 // drops its self-ref.
1418 TerminationCallback mTerminationCallback
;
1420 // The lifetime of these objects within LoadInfo is managed explicitly;
1421 // they do not need to be cycle collected.
1422 WorkerLoadInfo mLoadInfo
;
1423 LocationInfo mLocationInfo
;
1425 // Protected by mMutex.
1426 workerinternals::JSSettings mJSSettings
MOZ_GUARDED_BY(mMutex
);
1428 WorkerDebugger
* mDebugger
;
1430 workerinternals::Queue
<WorkerRunnable
*, 4> mControlQueue
;
1431 workerinternals::Queue
<WorkerRunnable
*, 4> mDebuggerQueue
1432 MOZ_GUARDED_BY(mMutex
);
1434 // Touched on multiple threads, protected with mMutex. Only modified on the
1436 JSContext
* mJSContext
MOZ_GUARDED_BY(mMutex
);
1437 // mThread is only modified on the Worker thread, before calling DoRunLoop
1438 RefPtr
<WorkerThread
> mThread
MOZ_GUARDED_BY(mMutex
);
1439 // mPRThread is only modified on another thread in ScheduleWorker(), and is
1440 // constant for the duration of DoRunLoop. Static mutex analysis doesn't help
1442 PRThread
* mPRThread
;
1444 // Accessed from main thread
1445 RefPtr
<ThrottledEventQueue
> mMainThreadEventTargetForMessaging
;
1446 RefPtr
<ThrottledEventQueue
> mMainThreadEventTarget
;
1448 // Accessed from worker thread and destructing thread
1449 RefPtr
<WorkerEventTarget
> mWorkerControlEventTarget
;
1450 RefPtr
<WorkerEventTarget
> mWorkerHybridEventTarget
;
1452 // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread.
1453 // See WorkerDebuggeeRunnable for details.
1454 RefPtr
<ThrottledEventQueue
> mMainThreadDebuggeeEventTarget
;
1456 struct SyncLoopInfo
{
1457 explicit SyncLoopInfo(EventTarget
* aEventTarget
);
1459 RefPtr
<EventTarget
> mEventTarget
;
1467 // This is only modified on the worker thread, but in DEBUG builds
1468 // AssertValidSyncLoop function iterates it on other threads. Therefore
1469 // modifications are done with mMutex held *only* in DEBUG builds.
1470 nsTArray
<UniquePtr
<SyncLoopInfo
>> mSyncLoopStack
;
1472 nsCOMPtr
<nsITimer
> mCancelingTimer
;
1474 // fired on the main thread if the worker script fails to load
1475 nsCOMPtr
<nsIRunnable
> mLoadFailedRunnable
;
1477 RefPtr
<PerformanceStorage
> mPerformanceStorage
;
1479 RefPtr
<WorkerCSPEventListener
> mCSPEventListener
;
1481 // Protected by mMutex.
1482 nsTArray
<RefPtr
<WorkerThreadRunnable
>> mPreStartRunnables
1483 MOZ_GUARDED_BY(mMutex
);
1485 // Only touched on the parent thread. Used for both SharedWorker and
1486 // ServiceWorker RemoteWorkers.
1487 RefPtr
<RemoteWorkerChild
> mRemoteWorkerController
;
1489 // Only touched on the worker thread. Used for both SharedWorker and
1490 // ServiceWorker RemoteWorkers.
1491 RefPtr
<RemoteWorkerNonLifeCycleOpControllerChild
>
1492 mRemoteWorkerNonLifeCycleOpController
;
1494 mozilla::ipc::Endpoint
<PRemoteWorkerNonLifeCycleOpControllerChild
> mChildEp
;
1496 JS::UniqueChars mDefaultLocale
; // nulled during worker JSContext init
1497 TimeStamp mKillTime
;
1498 WorkerStatus mParentStatus
MOZ_GUARDED_BY(mMutex
);
1499 WorkerStatus mStatus
MOZ_GUARDED_BY(mMutex
);
1501 TimeStamp mCreationTimeStamp
;
1502 DOMHighResTimeStamp mCreationTimeHighRes
;
1504 // Flags for use counters used directly by this worker.
1505 static_assert(sizeof(UseCounterWorker
) <= sizeof(size_t),
1506 "UseCounterWorker is too big");
1507 static_assert(UseCounterWorker::Count
>= static_cast<UseCounterWorker
>(0),
1508 "Should be non-negative value and safe to cast to unsigned");
1509 std::bitset
<static_cast<size_t>(UseCounterWorker::Count
)> mUseCounters
;
1510 bool mReportedUseCounters
;
1512 // This is created while creating the WorkerPrivate, so it's safe to be
1513 // touched on any thread.
1514 const nsID mAgentClusterId
;
1516 // Things touched on worker thread only.
1517 struct WorkerThreadAccessible
{
1518 explicit WorkerThreadAccessible(WorkerPrivate
* aParent
);
1520 RefPtr
<WorkerGlobalScope
> mScope
;
1521 RefPtr
<WorkerDebuggerGlobalScope
> mDebuggerScope
;
1522 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1523 // our static assert
1524 nsTArray
<WorkerPrivate
*> mChildWorkers
;
1525 nsTObserverArray
<WorkerRef
*> mWorkerRefs
;
1526 nsTArray
<UniquePtr
<TimeoutInfo
>> mTimeouts
;
1528 nsCOMPtr
<nsITimer
> mTimer
;
1529 nsCOMPtr
<nsITimerCallback
> mTimerRunnable
;
1531 nsCOMPtr
<nsITimer
> mPeriodicGCTimer
;
1532 nsCOMPtr
<nsITimer
> mIdleGCTimer
;
1534 RefPtr
<MemoryReporter
> mMemoryReporter
;
1536 // While running a nested event loop, whether a sync loop or a debugger
1537 // event loop we want to keep track of which global is running it, if any,
1538 // so runnables that run off that event loop can get at that information. In
1539 // practice this only matters for various worker debugger runnables running
1540 // against sandboxes, because all other runnables know which globals they
1541 // belong to already. We could also address this by threading the relevant
1542 // global through the chains of runnables involved, but we'd need to thread
1543 // it through some runnables that run on the main thread, and that would
1544 // require some care to make sure things get released on the correct thread,
1545 // which we'd rather avoid. This member is only accessed on the worker
1547 nsCOMPtr
<nsIGlobalObject
> mCurrentEventLoopGlobal
;
1549 // Timer that triggers an interrupt on expiration of the current time slice
1550 nsCOMPtr
<nsITimer
> mTSTimer
;
1552 // Execution manager used to regulate execution for this worker.
1553 RefPtr
<JSExecutionManager
> mExecutionManager
;
1555 // Used to relinguish clearance for CTypes Callbacks.
1556 nsTArray
<AutoYieldJSThreadExecution
> mYieldJSThreadExecution
;
1558 uint32_t mNumWorkerRefsPreventingShutdownStart
;
1559 uint32_t mDebuggerEventLoopLevel
;
1561 // This is the count of background actors that binding with IPCWorkerRefs.
1562 // This count would be used in WorkerPrivate::UpdateCCFlag for checking if
1563 // CC should be blocked by background actors.
1564 uint32_t mNonblockingCCBackgroundActorCount
;
1566 uint32_t mErrorHandlerRecursionCount
;
1567 int32_t mNextTimeoutId
;
1569 // Tracks the current setTimeout/setInterval nesting level.
1570 // When there isn't a TimeoutHandler on the stack, this will be 0.
1571 // Whenever setTimeout/setInterval are called, a new TimeoutInfo will be
1572 // created with a nesting level one more than the current nesting level,
1573 // saturating at the kClampTimeoutNestingLevel.
1575 // When RunExpiredTimeouts is run, it sets this value to the
1576 // TimeoutInfo::mNestingLevel for the duration of
1577 // the WorkerScriptTimeoutHandler::Call which will explicitly trigger a
1578 // microtask checkpoint so that any immediately-resolved promises will
1579 // still see the nesting level.
1580 uint32_t mCurrentTimerNestingLevel
;
1584 // This flag is set by the debugger interrupt control runnable to indicate
1585 // that we want to process debugger runnables as part of control runnable
1586 // processing, which is something we don't normally want to do. The flag is
1587 // cleared after processing the debugger runnables.
1588 bool mDebuggerInterruptRequested
;
1591 bool mRunningExpiredTimeouts
;
1592 bool mPeriodicGCTimerRunning
;
1593 bool mIdleGCTimerRunning
;
1595 bool mJSThreadExecutionGranted
;
1596 bool mCCCollectedAnything
;
1597 FlippedOnce
<false> mDeletionScheduled
;
1598 FlippedOnce
<false> mCancelBeforeWorkerScopeConstructed
;
1599 FlippedOnce
<false> mPerformedShutdownAfterLastContentTaskExecuted
;
1600 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1601 bool mIsPotentiallyLastGCCCRunning
= false;
1604 ThreadBound
<WorkerThreadAccessible
> mWorkerThreadAccessible
;
1606 class MOZ_RAII AutoPushEventLoopGlobal
{
1608 AutoPushEventLoopGlobal(WorkerPrivate
* aWorkerPrivate
, JSContext
* aCx
);
1609 ~AutoPushEventLoopGlobal();
1612 nsCOMPtr
<nsIGlobalObject
> mOldEventLoopGlobal
;
1615 // This is used to checking if we are on the right stack while push the
1616 // mOldEventLoopGlobal back.
1617 nsCOMPtr
<nsIGlobalObject
> mNewEventLoopGlobal
;
1620 friend class AutoPushEventLoopGlobal
;
1622 uint32_t mPostSyncLoopOperations
;
1624 // List of operations to do at the end of the last sync event loop.
1626 eDispatchCancelingRunnable
= 0x02,
1629 bool mParentWindowPaused
;
1631 bool mWorkerScriptExecutedSuccessfully
;
1632 bool mFetchHandlerWasAdded
;
1633 bool mMainThreadObjectsForgotten
;
1634 bool mIsChromeWorker
;
1637 // In order to ensure that the debugger can interrupt a busy worker,
1638 // including when atomics are used, we reuse the worker's existing
1639 // JS Interrupt facility used by control runnables.
1640 // Rather that triggering an interrupt immediately when a debugger runnable
1641 // is dispatched, we instead start a timer that will fire if we haven't
1642 // already processed the runnable, targeting the timer's callback at the
1643 // control event target. This allows existing runnables that were going to
1644 // finish in a timely fashion to finish.
1645 nsCOMPtr
<nsITimer
> mDebuggerInterruptTimer
MOZ_GUARDED_BY(mMutex
);
1647 // mIsSecureContext is set once in our constructor; after that it can be read
1648 // from various threads.
1650 // It's a bit unfortunate that we have to have an out-of-band boolean for
1651 // this, but we need access to this state from the parent thread, and we can't
1652 // use our global object's secure state there.
1653 const bool mIsSecureContext
;
1655 bool mDebuggerRegistered
MOZ_GUARDED_BY(mMutex
);
1656 mozilla::Atomic
<bool> mIsInBackground
;
1658 // During registration, this worker may be marked as not being ready to
1659 // execute debuggee runnables or content.
1661 // Protected by mMutex.
1662 bool mDebuggerReady
;
1663 nsTArray
<RefPtr
<WorkerRunnable
>> mDelayedDebuggeeRunnables
;
1665 // Whether this worker should have access to the WebExtension API bindings
1666 // (currently only the Extension Background ServiceWorker declared in the
1667 // extension manifest is allowed to access any WebExtension API bindings).
1668 // This default to false, and it is eventually set to true by
1669 // RemoteWorkerChild::ExecWorkerOnMainThread if the needed conditions
1671 bool mExtensionAPIAllowed
;
1673 // mIsInAutomation is true when we're running in test automation.
1674 // We expose some extra testing functions in that case.
1675 bool mIsInAutomation
;
1679 // This is used to check if it's allowed to share the memory across the agent
1681 const nsILoadInfo::CrossOriginOpenerPolicy mAgentClusterOpenerPolicy
;
1683 // Member variable of this class rather than the worker global scope because
1684 // it's received on the main thread, but the global scope is thread-bound
1685 // to the worker thread, so storing the value in the global scope would
1686 // involve sacrificing the thread-bound-ness or using a WorkerRunnable, and
1687 // there isn't a strong reason to store it on the global scope other than
1688 // better consistency with the COEP spec.
1689 Maybe
<nsILoadInfo::CrossOriginEmbedderPolicy
> mEmbedderPolicy
;
1690 Maybe
<nsILoadInfo::CrossOriginEmbedderPolicy
> mOwnerEmbedderPolicy
;
1692 /* Privileged add-on flag extracted from the AddonPolicy on the nsIPrincipal
1693 * on the main thread when constructing a top-level worker. The flag is
1694 * propagated to nested workers. The flag is only allowed to take effect in
1695 * extension processes and is forbidden in content scripts in content
1696 * processes. The flag may be read on either the parent/owner thread as well
1697 * as on the worker thread itself. When bug 1443925 is fixed allowing
1698 * nsIPrincipal to be used OMT, it may be possible to remove this flag. */
1699 bool mIsPrivilegedAddonGlobal
;
1701 Atomic
<uint32_t> mTopLevelWorkerFinishedRunnableCount
;
1702 Atomic
<uint32_t> mWorkerFinishedRunnableCount
;
1704 nsTArray
<nsCOMPtr
<nsITargetShutdownTask
>> mShutdownTasks
1705 MOZ_GUARDED_BY(mMutex
);
1706 bool mShutdownTasksRun
MOZ_GUARDED_BY(mMutex
) = false;
1708 bool mCCFlagSaysEligible
MOZ_GUARDED_BY(mMutex
){true};
1710 // The flag indicates if the worke is idle for events in the main event loop.
1711 bool mWorkerLoopIsIdle
MOZ_GUARDED_BY(mMutex
){false};
1713 // This flag is used to ensure we only call NotifyStorageKeyUsed once per
1715 bool hasNotifiedStorageKeyUsed
{false};
1717 RefPtr
<WorkerParentRef
> mParentRef
;
1720 class AutoSyncLoopHolder
{
1721 RefPtr
<StrongWorkerRef
> mWorkerRef
;
1722 nsCOMPtr
<nsISerialEventTarget
> mTarget
;
1726 // See CreateNewSyncLoop() for more information about the correct value to use
1728 AutoSyncLoopHolder(WorkerPrivate
* aWorkerPrivate
, WorkerStatus aFailStatus
,
1729 const char* const aName
= "AutoSyncLoopHolder");
1731 ~AutoSyncLoopHolder();
1735 nsISerialEventTarget
* GetSerialEventTarget() const;
1739 * WorkerParentRef is a RefPtr<WorkerPrivate> wrapper for cross-thread access.
1740 * WorkerPrivate needs to be accessed in multiple threads; for example,
1741 * in WorkerParentThreadRunnable, the associated WorkerPrivate must be accessed
1742 * in the worker thread when creating/dispatching and in the parent thread when
1743 * executing. Unfortunately, RefPtr can not be used on this WorkerPrivate since
1744 * it is not a thread-safe ref-counted object.
1746 * Instead of using a raw pointer and a complicated mechanism to ensure the
1747 * WorkerPrivate's accessibility. WorkerParentRef is used to resolve the
1748 * problem. WorkerParentRef has a RefPtr<WorkerPrivate> mWorkerPrivate
1749 * initialized on the parent thread when WorkerPrivate::Constructor().
1750 * WorkerParentRef is a thread-safe ref-counted object that can be copied at
1751 * any thread by WorkerPrivate::GetWorkerParentRef() and propagated to other
1752 * threads. In the target thread, call WorkerParentRef::Private() to get the
1753 * reference for WorkerPrivate or get a nullptr if the Worker has shut down.
1755 * Since currently usage cases, WorkerParentRef::Private() will assert to be on
1756 * the parent thread.
1758 class WorkerParentRef final
{
1760 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerParentRef
);
1762 explicit WorkerParentRef(RefPtr
<WorkerPrivate
>& aWorkerPrivate
);
1764 const RefPtr
<WorkerPrivate
>& Private() const;
1766 void DropWorkerPrivate();
1771 RefPtr
<WorkerPrivate
> mWorkerPrivate
;
1775 } // namespace mozilla
1777 #endif /* mozilla_dom_workers_workerprivate_h__ */