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/Attributes.h"
15 #include "mozilla/AutoRestore.h"
16 #include "mozilla/BasePrincipal.h"
17 #include "mozilla/CondVar.h"
18 #include "mozilla/DOMEventTargetHelper.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/MozPromise.h"
21 #include "mozilla/OriginTrials.h"
22 #include "mozilla/RelativeTimeline.h"
23 #include "mozilla/Result.h"
24 #include "mozilla/StorageAccess.h"
25 #include "mozilla/ThreadBound.h"
26 #include "mozilla/ThreadSafeWeakPtr.h"
27 #include "mozilla/UniquePtr.h"
28 #include "mozilla/UseCounter.h"
29 #include "mozilla/dom/ClientSource.h"
30 #include "mozilla/dom/FlippedOnce.h"
31 #include "mozilla/dom/Timeout.h"
32 #include "mozilla/dom/quota/CheckedUnsafePtr.h"
33 #include "mozilla/dom/Worker.h"
34 #include "mozilla/dom/WorkerBinding.h"
35 #include "mozilla/dom/WorkerCommon.h"
36 #include "mozilla/dom/WorkerLoadInfo.h"
37 #include "mozilla/dom/WorkerStatus.h"
38 #include "mozilla/dom/workerinternals/JSSettings.h"
39 #include "mozilla/dom/workerinternals/Queue.h"
40 #include "mozilla/dom/JSExecutionManager.h"
41 #include "mozilla/net/NeckoChannelParams.h"
42 #include "mozilla/StaticPrefs_extensions.h"
43 #include "nsContentUtils.h"
44 #include "nsIChannel.h"
45 #include "nsIContentSecurityPolicy.h"
46 #include "nsIEventTarget.h"
47 #include "nsILoadInfo.h"
48 #include "nsTObserverArray.h"
50 class nsIThreadInternal
;
57 class ThrottledEventQueue
;
60 class RemoteWorkerChild
;
62 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
63 // to be updated too. And histograms enum for worker use counters uses the same
64 // order of worker kind. Please also update dom/base/usecounters.py.
65 enum WorkerKind
{ WorkerKindDedicated
, WorkerKindShared
, WorkerKindService
};
70 class JSExecutionManager
;
72 class UniqueMessagePortId
;
73 class PerformanceStorage
;
75 class WorkerControlRunnable
;
76 class WorkerCSPEventListener
;
78 class WorkerDebuggerGlobalScope
;
79 class WorkerErrorReport
;
80 class WorkerEventTarget
;
81 class WorkerGlobalScope
;
84 class WorkerDebuggeeRunnable
;
87 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
88 // object. It exists to avoid changing a lot of code to use Mutex* instead of
90 class MOZ_CAPABILITY("mutex") SharedMutex
{
91 using Mutex
= mozilla::Mutex
;
93 class MOZ_CAPABILITY("mutex") RefCountedMutex final
: public Mutex
{
95 explicit RefCountedMutex(const char* aName
) : Mutex(aName
) {}
97 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex
)
100 ~RefCountedMutex() = default;
103 const RefPtr
<RefCountedMutex
> mMutex
;
106 explicit SharedMutex(const char* aName
)
107 : mMutex(new RefCountedMutex(aName
)) {}
109 SharedMutex(const SharedMutex
& aOther
) = default;
111 operator Mutex
&() MOZ_RETURN_CAPABILITY(this) { return *mMutex
; }
113 operator const Mutex
&() const MOZ_RETURN_CAPABILITY(this) { return *mMutex
; }
115 // We need these to make thread-safety analysis work
116 void Lock() MOZ_CAPABILITY_ACQUIRE() { mMutex
->Lock(); }
117 void Unlock() MOZ_CAPABILITY_RELEASE() { mMutex
->Unlock(); }
119 // We can assert we own 'this', but we can't assert we hold mMutex
120 void AssertCurrentThreadOwns() const
121 MOZ_ASSERT_CAPABILITY(this) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
122 mMutex
->AssertCurrentThreadOwns();
126 nsString
ComputeWorkerPrivateId();
128 class WorkerPrivate final
129 : public RelativeTimeline
,
130 public SupportsCheckedUnsafePtr
<CheckIf
<DiagnosticAssertEnabled
>> {
132 // Callback invoked on the parent thread when the worker's cancellation is
133 // about to be requested. This covers both calls to
134 // WorkerPrivate::Cancel() by the owner as well as self-initiated cancellation
135 // due to top-level script evaluation failing or close() being invoked on the
136 // global scope for Dedicated and Shared workers, but not Service Workers as
137 // they do not expose a close() method.
139 // ### Parent-Initiated Cancellation
141 // When WorkerPrivate::Cancel is invoked on the parent thread (by the binding
142 // exposed Worker::Terminate), this callback is invoked synchronously inside
145 // ### Worker Self-Cancellation
147 // When a worker initiates self-cancellation, the worker's notification to the
148 // parent thread is a non-blocking, async mechanism triggered by
149 // `WorkerPrivate::DispatchCancelingRunnable`.
151 // Self-cancellation races a normally scheduled runnable against a timer that
152 // is scheduled against the parent. The 2 paths initiated by
153 // DispatchCancelingRunnable are:
155 // 1. A CancelingRunnable is dispatched at the worker's normal event target to
156 // wait for the event loop to be clear of runnables. When the
157 // CancelingRunnable runs it will dispatch a CancelingOnParentRunnable to
158 // its parent which is a normal, non-control WorkerDebuggeeRunnable to
159 // ensure that any postMessages to the parent or similar events get a
160 // chance to be processed prior to cancellation. The timer scheduled in
161 // the next bullet will not be canceled unless
163 // 2. A CancelingWithTimeoutOnParentRunnable control runnable is dispatched
164 // to the parent to schedule a timer which will (also) fire on the parent
165 // thread. This handles the case where the worker does not yield
166 // control-flow, and so the normal runnable scheduled above does not get to
167 // run in a timely fashion. Because this is a control runnable, if the
168 // parent is a worker then the runnable will be processed with urgency.
169 // However, if the worker is top-level, then the control-like throttled
170 // WorkerPrivate::mMainThreadEventTarget will end up getting used which is
171 // nsIRunnablePriority::PRIORITY_MEDIUMHIGH and distinct from the
172 // mMainThreadDebuggeeEventTarget which most runnables (like postMessage)
175 // The timer will explicitly use the control event target if the parent is
176 // a worker and the implicit event target (via `NS_NewTimer()`) otherwise.
177 // The callback is CancelingTimerCallback which just calls
178 // WorkerPrivate::Cancel.
179 using CancellationCallback
= std::function
<void(bool aEverRan
)>;
181 // Callback invoked on the parent just prior to dropping the worker thread's
182 // strong reference that keeps the WorkerPrivate alive while the worker thread
183 // is running. This does not provide a guarantee that the underlying thread
184 // has fully shutdown, just that the worker logic has fully shutdown.
188 // The last thing the worker thread's WorkerThreadPrimaryRunnable does before
189 // initiating the shutdown of the underlying thread is call ScheduleDeletion.
190 // ScheduleDeletion dispatches a runnable to the parent to notify it that the
191 // worker has completed its work and will never touch the WorkerPrivate again
192 // and that the strong self-reference can be dropped.
194 // For parents that are themselves workers, this will be done by
195 // WorkerFinishedRunnable which is a WorkerControlRunnable, ensuring that this
196 // is processed in a timely fashion. For main-thread parents,
197 // TopLevelWorkerFinishedRunnable will be used and sent via
198 // mMainThreadEventTargetForMessaging which is a weird ThrottledEventQueue
199 // which does not provide any ordering guarantees relative to
200 // mMainThreadDebuggeeEventTarget, so if you want those, you need to enhance
202 using TerminationCallback
= std::function
<void(void)>;
204 struct LocationInfo
{
216 NS_INLINE_DECL_REFCOUNTING(WorkerPrivate
)
218 static already_AddRefed
<WorkerPrivate
> Constructor(
219 JSContext
* aCx
, const nsAString
& aScriptURL
, bool aIsChromeWorker
,
220 WorkerKind aWorkerKind
, RequestCredentials aRequestCredentials
,
221 const WorkerType aWorkerType
, const nsAString
& aWorkerName
,
222 const nsACString
& aServiceWorkerScope
, WorkerLoadInfo
* aLoadInfo
,
223 ErrorResult
& aRv
, nsString aId
= u
""_ns
,
224 CancellationCallback
&& aCancellationCallback
= {},
225 TerminationCallback
&& aTerminationCallback
= {});
227 enum LoadGroupBehavior
{ InheritLoadGroup
, OverrideLoadGroup
};
229 static nsresult
GetLoadInfo(
230 JSContext
* aCx
, nsPIDOMWindowInner
* aWindow
, WorkerPrivate
* aParent
,
231 const nsAString
& aScriptURL
, const enum WorkerType
& aWorkerType
,
232 const RequestCredentials
& aCredentials
, bool aIsChromeWorker
,
233 LoadGroupBehavior aLoadGroupBehavior
, WorkerKind aWorkerKind
,
234 WorkerLoadInfo
* aLoadInfo
);
236 void Traverse(nsCycleCollectionTraversalCallback
& aCb
);
238 void ClearSelfAndParentEventTargetRef() {
239 AssertIsOnParentThread();
240 MOZ_ASSERT(mSelfRef
);
242 if (mTerminationCallback
) {
243 mTerminationCallback();
244 mTerminationCallback
= nullptr;
247 mParentEventTargetRef
= nullptr;
251 // May be called on any thread...
254 // Called on the parent thread.
255 bool Notify(WorkerStatus aStatus
);
257 bool Cancel() { return Notify(Canceling
); }
259 bool Close() MOZ_REQUIRES(mMutex
);
261 // The passed principal must be the Worker principal in case of a
262 // ServiceWorker and the loading principal for any other type.
263 static void OverrideLoadInfoLoadGroup(WorkerLoadInfo
& aLoadInfo
,
264 nsIPrincipal
* aPrincipal
);
266 bool IsDebuggerRegistered() MOZ_NO_THREAD_SAFETY_ANALYSIS
{
267 AssertIsOnMainThread();
269 // No need to lock here since this is only ever modified by the same thread.
270 return mDebuggerRegistered
; // would give a thread-safety warning
273 bool ExtensionAPIAllowed() {
275 StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup() &&
276 mExtensionAPIAllowed
);
279 void SetIsDebuggerRegistered(bool aDebuggerRegistered
) {
280 AssertIsOnMainThread();
282 MutexAutoLock
lock(mMutex
);
284 MOZ_ASSERT(mDebuggerRegistered
!= aDebuggerRegistered
);
285 mDebuggerRegistered
= aDebuggerRegistered
;
290 void WaitForIsDebuggerRegistered(bool aDebuggerRegistered
) {
291 AssertIsOnParentThread();
293 // Yield so that the main thread won't be blocked.
294 AutoYieldJSThreadExecution yield
;
296 MOZ_ASSERT(!NS_IsMainThread());
298 MutexAutoLock
lock(mMutex
);
300 while (mDebuggerRegistered
!= aDebuggerRegistered
) {
305 nsresult
SetIsDebuggerReady(bool aReady
);
307 WorkerDebugger
* Debugger() const {
308 AssertIsOnMainThread();
310 MOZ_ASSERT(mDebugger
);
314 const OriginTrials
& Trials() const { return mLoadInfo
.mTrials
; }
316 void SetDebugger(WorkerDebugger
* aDebugger
) {
317 AssertIsOnMainThread();
319 MOZ_ASSERT(mDebugger
!= aDebugger
);
320 mDebugger
= aDebugger
;
323 JS::UniqueChars
AdoptDefaultLocale() {
324 MOZ_ASSERT(mDefaultLocale
,
325 "the default locale must have been successfully set for anyone "
326 "to be trying to adopt it");
327 return std::move(mDefaultLocale
);
331 * Invoked by WorkerThreadPrimaryRunnable::Run if it already called
332 * SetWorkerPrivateInWorkerThread but has to bail out on initialization before
333 * calling DoRunLoop because PBackground failed to initialize or something
334 * like that. Note that there's currently no point earlier than this that
335 * failure can be reported.
337 * When this happens, the worker will need to be deleted, plus the call to
338 * SetWorkerPrivateInWorkerThread will have scheduled all the
339 * mPreStartRunnables which need to be cleaned up after, as well as any
340 * scheduled control runnables. We're somewhat punting on debugger runnables
341 * for now, which may leak, but the intent is to moot this whole scenario via
342 * shutdown blockers, so we don't want the extra complexity right now.
344 void RunLoopNeverRan();
347 void DoRunLoop(JSContext
* aCx
);
349 void UnrootGlobalScopes();
351 bool InterruptCallback(JSContext
* aCx
);
353 bool IsOnCurrentThread();
355 void CloseInternal();
357 bool FreezeInternal();
361 void PropagateStorageAccessPermissionGrantedInternal();
363 void TraverseTimeouts(nsCycleCollectionTraversalCallback
& aCallback
);
365 void UnlinkTimeouts();
367 bool ModifyBusyCountFromWorker(bool aIncrease
);
369 bool AddChildWorker(WorkerPrivate
& aChildWorker
);
371 void RemoveChildWorker(WorkerPrivate
& aChildWorker
);
373 void PostMessageToParent(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
374 const Sequence
<JSObject
*>& aTransferable
,
377 void PostMessageToParentMessagePort(JSContext
* aCx
,
378 JS::Handle
<JS::Value
> aMessage
,
379 const Sequence
<JSObject
*>& aTransferable
,
382 MOZ_CAN_RUN_SCRIPT
void EnterDebuggerEventLoop();
384 void LeaveDebuggerEventLoop();
386 void PostMessageToDebugger(const nsAString
& aMessage
);
388 void SetDebuggerImmediate(Function
& aHandler
, ErrorResult
& aRv
);
390 void ReportErrorToDebugger(const nsAString
& aFilename
, uint32_t aLineno
,
391 const nsAString
& aMessage
);
393 bool NotifyInternal(WorkerStatus aStatus
);
395 void ReportError(JSContext
* aCx
, JS::ConstUTF8CharsZ aToStringResult
,
396 JSErrorReport
* aReport
);
398 static void ReportErrorToConsole(const char* aMessage
);
400 static void ReportErrorToConsole(const char* aMessage
,
401 const nsTArray
<nsString
>& aParams
);
403 int32_t SetTimeout(JSContext
* aCx
, TimeoutHandler
* aHandler
, int32_t aTimeout
,
404 bool aIsInterval
, Timeout::Reason aReason
,
407 void ClearTimeout(int32_t aId
, Timeout::Reason aReason
);
409 MOZ_CAN_RUN_SCRIPT
bool RunExpiredTimeouts(JSContext
* aCx
);
411 bool RescheduleTimeoutTimer(JSContext
* aCx
);
413 void UpdateContextOptionsInternal(JSContext
* aCx
,
414 const JS::ContextOptions
& aContextOptions
);
416 void UpdateLanguagesInternal(const nsTArray
<nsString
>& aLanguages
);
418 void UpdateJSWorkerMemoryParameterInternal(JSContext
* aCx
, JSGCParamKey key
,
419 Maybe
<uint32_t> aValue
);
421 enum WorkerRanOrNot
{ WorkerNeverRan
= 0, WorkerRan
};
423 void ScheduleDeletion(WorkerRanOrNot aRanOrNot
);
425 bool CollectRuntimeStats(JS::RuntimeStats
* aRtStats
, bool aAnonymize
);
428 void UpdateGCZealInternal(JSContext
* aCx
, uint8_t aGCZeal
,
429 uint32_t aFrequency
);
432 void SetLowMemoryStateInternal(JSContext
* aCx
, bool aState
);
434 void GarbageCollectInternal(JSContext
* aCx
, bool aShrinking
,
435 bool aCollectChildren
);
437 void CycleCollectInternal(bool aCollectChildren
);
439 void OfflineStatusChangeEventInternal(bool aIsOffline
);
441 void MemoryPressureInternal();
443 typedef MozPromise
<uint64_t, nsresult
, true> JSMemoryUsagePromise
;
444 RefPtr
<JSMemoryUsagePromise
> GetJSMemoryUsage();
446 void SetFetchHandlerWasAdded() {
447 MOZ_ASSERT(IsServiceWorker());
448 AssertIsOnWorkerThread();
449 mFetchHandlerWasAdded
= true;
452 bool FetchHandlerWasAdded() const {
453 MOZ_ASSERT(IsServiceWorker());
454 AssertIsOnWorkerThread();
455 return mFetchHandlerWasAdded
;
458 JSContext
* GetJSContext() const MOZ_NO_THREAD_SAFETY_ANALYSIS
{
459 // mJSContext is only modified on the worker thread, so workerthread code
460 // can safely read it without a lock
461 AssertIsOnWorkerThread();
465 WorkerGlobalScope
* GlobalScope() const {
466 auto data
= mWorkerThreadAccessible
.Access();
470 WorkerDebuggerGlobalScope
* DebuggerGlobalScope() const {
471 auto data
= mWorkerThreadAccessible
.Access();
472 return data
->mDebuggerScope
;
475 // Get the global associated with the current nested event loop. Will return
476 // null if we're not in a nested event loop or that nested event loop does not
477 // have an associated global.
478 nsIGlobalObject
* GetCurrentEventLoopGlobal() const {
479 auto data
= mWorkerThreadAccessible
.Access();
480 return data
->mCurrentEventLoopGlobal
;
483 nsICSPEventListener
* CSPEventListener() const;
485 void SetThread(WorkerThread
* aThread
);
487 void SetWorkerPrivateInWorkerThread(WorkerThread
* aThread
);
489 void ResetWorkerPrivateInWorkerThread();
491 bool IsOnWorkerThread() const;
493 void AssertIsOnWorkerThread() const
502 void BeginCTypesCall();
505 void EndCTypesCall();
507 void BeginCTypesCallback();
509 void EndCTypesCallback();
511 bool ConnectMessagePort(JSContext
* aCx
, UniqueMessagePortId
& aIdentifier
);
513 WorkerGlobalScope
* GetOrCreateGlobalScope(JSContext
* aCx
);
515 WorkerDebuggerGlobalScope
* CreateDebuggerGlobalScope(JSContext
* aCx
);
517 bool RegisterBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
519 bool RegisterDebuggerBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
521 bool OnLine() const {
522 auto data
= mWorkerThreadAccessible
.Access();
523 return data
->mOnLine
;
526 void StopSyncLoop(nsIEventTarget
* aSyncLoopTarget
, nsresult aResult
);
528 void ShutdownModuleLoader();
530 void ClearPreStartRunnables();
532 void ClearDebuggerEventQueue();
534 void OnProcessNextEvent();
536 void AfterProcessNextEvent();
538 void AssertValidSyncLoop(nsIEventTarget
* aSyncLoopTarget
)
546 void AssertIsNotPotentiallyLastGCCCRunning() {
547 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
548 auto data
= mWorkerThreadAccessible
.Access();
549 MOZ_DIAGNOSTIC_ASSERT(!data
->mIsPotentiallyLastGCCCRunning
);
553 void SetWorkerScriptExecutedSuccessfully() {
554 AssertIsOnWorkerThread();
555 // Should only be called once!
556 MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully
);
557 mWorkerScriptExecutedSuccessfully
= true;
560 // Only valid after CompileScriptRunnable has finished running!
561 bool WorkerScriptExecutedSuccessfully() const {
562 AssertIsOnWorkerThread();
563 return mWorkerScriptExecutedSuccessfully
;
566 // Get the event target to use when dispatching to the main thread
567 // from this Worker thread. This may be the main thread itself or
568 // a ThrottledEventQueue to the main thread.
569 nsISerialEventTarget
* MainThreadEventTargetForMessaging();
571 nsresult
DispatchToMainThreadForMessaging(
572 nsIRunnable
* aRunnable
, uint32_t aFlags
= NS_DISPATCH_NORMAL
);
574 nsresult
DispatchToMainThreadForMessaging(
575 already_AddRefed
<nsIRunnable
> aRunnable
,
576 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
578 nsISerialEventTarget
* MainThreadEventTarget();
580 nsresult
DispatchToMainThread(nsIRunnable
* aRunnable
,
581 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
583 nsresult
DispatchToMainThread(already_AddRefed
<nsIRunnable
> aRunnable
,
584 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
586 nsresult
DispatchDebuggeeToMainThread(
587 already_AddRefed
<WorkerDebuggeeRunnable
> aRunnable
,
588 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
590 // Get an event target that will dispatch runnables as control runnables on
591 // the worker thread. Implement nsICancelableRunnable if you wish to take
592 // action on cancelation.
593 nsISerialEventTarget
* ControlEventTarget();
595 // Get an event target that will attempt to dispatch a normal WorkerRunnable,
596 // but if that fails will then fall back to a control runnable.
597 nsISerialEventTarget
* HybridEventTarget();
599 void DumpCrashInformation(nsACString
& aString
);
601 ClientType
GetClientType() const;
603 bool EnsureCSPEventListener();
605 void EnsurePerformanceStorage();
607 bool GetExecutionGranted() const;
608 void SetExecutionGranted(bool aGranted
);
610 void ScheduleTimeSliceExpiration(uint32_t aDelay
);
611 void CancelTimeSliceExpiration();
613 JSExecutionManager
* GetExecutionManager() const;
614 void SetExecutionManager(JSExecutionManager
* aManager
);
616 void ExecutionReady();
618 PerformanceStorage
* GetPerformanceStorage();
620 bool IsAcceptingEvents() {
621 AssertIsOnParentThread();
623 MutexAutoLock
lock(mMutex
);
624 return mParentStatus
< Canceling
;
627 WorkerStatus
ParentStatusProtected() {
628 AssertIsOnParentThread();
629 MutexAutoLock
lock(mMutex
);
630 return mParentStatus
;
633 WorkerStatus
ParentStatus() const MOZ_REQUIRES(mMutex
) {
634 mMutex
.AssertCurrentThreadOwns();
635 return mParentStatus
;
638 Worker
* ParentEventTargetRef() const {
639 MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef
);
640 return mParentEventTargetRef
;
643 void SetParentEventTargetRef(Worker
* aParentEventTargetRef
) {
644 MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef
);
645 MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef
);
646 mParentEventTargetRef
= aParentEventTargetRef
;
649 bool ModifyBusyCount(bool aIncrease
);
651 // This method is used by RuntimeService to know what is going wrong the
653 uint32_t BusyCount() { return mBusyCount
; }
655 // Check whether this worker is a secure context. For use from the parent
656 // thread only; the canonical "is secure context" boolean is stored on the
657 // compartment of the worker global. The only reason we don't
658 // AssertIsOnParentThread() here is so we can assert that this value matches
659 // the one on the compartment, which has to be done from the worker thread.
660 bool IsSecureContext() const { return mIsSecureContext
; }
662 // Check whether we're running in automation.
663 bool IsInAutomation() const { return mIsInAutomation
; }
665 bool IsPrivilegedAddonGlobal() const { return mIsPrivilegedAddonGlobal
; }
667 TimeStamp
CreationTimeStamp() const { return mCreationTimeStamp
; }
669 DOMHighResTimeStamp
CreationTime() const { return mCreationTimeHighRes
; }
671 DOMHighResTimeStamp
TimeStampToDOMHighRes(const TimeStamp
& aTimeStamp
) const {
672 MOZ_ASSERT(!aTimeStamp
.IsNull());
673 TimeDuration duration
= aTimeStamp
- mCreationTimeStamp
;
674 return duration
.ToMilliseconds();
677 LocationInfo
& GetLocationInfo() { return mLocationInfo
; }
679 void CopyJSSettings(workerinternals::JSSettings
& aSettings
) {
680 mozilla::MutexAutoLock
lock(mMutex
);
681 aSettings
= mJSSettings
;
684 void CopyJSRealmOptions(JS::RealmOptions
& aOptions
) {
685 mozilla::MutexAutoLock
lock(mMutex
);
686 aOptions
= IsChromeWorker() ? mJSSettings
.chromeRealmOptions
687 : mJSSettings
.contentRealmOptions
;
690 // The ability to be a chrome worker is orthogonal to the type of
691 // worker [Dedicated|Shared|Service].
692 bool IsChromeWorker() const { return mIsChromeWorker
; }
694 // TODO: Invariants require that the parent worker out-live any child
695 // worker, so WorkerPrivate* should be safe in the moment of calling.
696 // We would like to have stronger type-system annotated/enforced handling.
697 WorkerPrivate
* GetParent() const { return mParent
; }
699 bool IsFrozen() const {
700 AssertIsOnParentThread();
701 return mParentFrozen
;
704 bool IsParentWindowPaused() const {
705 AssertIsOnParentThread();
706 return mParentWindowPaused
;
709 // When we debug a worker, we want to disconnect the window and the worker
710 // communication. This happens calling this method.
711 // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
712 void ParentWindowPaused();
714 void ParentWindowResumed();
716 const nsString
& ScriptURL() const { return mScriptURL
; }
718 const nsString
& WorkerName() const { return mWorkerName
; }
719 RequestCredentials
WorkerCredentials() const { return mCredentialsMode
; }
720 enum WorkerType
WorkerType() const { return mWorkerType
; }
722 WorkerKind
Kind() const { return mWorkerKind
; }
724 bool IsDedicatedWorker() const { return mWorkerKind
== WorkerKindDedicated
; }
726 bool IsSharedWorker() const { return mWorkerKind
== WorkerKindShared
; }
728 bool IsServiceWorker() const { return mWorkerKind
== WorkerKindService
; }
730 nsContentPolicyType
ContentPolicyType() const {
731 return ContentPolicyType(mWorkerKind
);
734 static nsContentPolicyType
ContentPolicyType(WorkerKind aWorkerKind
) {
735 switch (aWorkerKind
) {
736 case WorkerKindDedicated
:
737 return nsIContentPolicy::TYPE_INTERNAL_WORKER
;
738 case WorkerKindShared
:
739 return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
;
740 case WorkerKindService
:
741 return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER
;
743 MOZ_ASSERT_UNREACHABLE("Invalid worker type");
744 return nsIContentPolicy::TYPE_INVALID
;
748 nsIScriptContext
* GetScriptContext() const {
749 AssertIsOnMainThread();
750 return mLoadInfo
.mScriptContext
;
753 const nsCString
& Domain() const { return mLoadInfo
.mDomain
; }
755 bool IsFromWindow() const { return mLoadInfo
.mFromWindow
; }
757 nsLoadFlags
GetLoadFlags() const { return mLoadInfo
.mLoadFlags
; }
759 uint64_t WindowID() const { return mLoadInfo
.mWindowID
; }
761 uint64_t AssociatedBrowsingContextID() const {
762 return mLoadInfo
.mAssociatedBrowsingContextID
;
765 uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); }
767 const nsCString
& ServiceWorkerScope() const {
768 return GetServiceWorkerDescriptor().Scope();
771 // This value should never change after the script load completes. Before
772 // then, it may only be called on the main thread.
773 nsIURI
* GetBaseURI() const { return mLoadInfo
.mBaseURI
; }
775 void SetBaseURI(nsIURI
* aBaseURI
);
777 nsIURI
* GetResolvedScriptURI() const { return mLoadInfo
.mResolvedScriptURI
; }
779 const nsString
& ServiceWorkerCacheName() const {
780 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
781 AssertIsOnMainThread();
782 return mLoadInfo
.mServiceWorkerCacheName
;
785 const ServiceWorkerDescriptor
& GetServiceWorkerDescriptor() const {
786 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
787 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
788 return mLoadInfo
.mServiceWorkerDescriptor
.ref();
791 const ServiceWorkerRegistrationDescriptor
&
792 GetServiceWorkerRegistrationDescriptor() const {
793 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
794 MOZ_DIAGNOSTIC_ASSERT(
795 mLoadInfo
.mServiceWorkerRegistrationDescriptor
.isSome());
796 return mLoadInfo
.mServiceWorkerRegistrationDescriptor
.ref();
799 void UpdateServiceWorkerState(ServiceWorkerState aState
) {
800 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
801 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
802 return mLoadInfo
.mServiceWorkerDescriptor
.ref().SetState(aState
);
805 const Maybe
<ServiceWorkerDescriptor
>& GetParentController() const {
806 return mLoadInfo
.mParentController
;
809 const ChannelInfo
& GetChannelInfo() const { return mLoadInfo
.mChannelInfo
; }
811 void SetChannelInfo(const ChannelInfo
& aChannelInfo
) {
812 AssertIsOnMainThread();
813 MOZ_ASSERT(!mLoadInfo
.mChannelInfo
.IsInitialized());
814 MOZ_ASSERT(aChannelInfo
.IsInitialized());
815 mLoadInfo
.mChannelInfo
= aChannelInfo
;
818 void InitChannelInfo(nsIChannel
* aChannel
) {
819 mLoadInfo
.mChannelInfo
.InitFromChannel(aChannel
);
822 void InitChannelInfo(const ChannelInfo
& aChannelInfo
) {
823 mLoadInfo
.mChannelInfo
= aChannelInfo
;
826 nsIPrincipal
* GetPrincipal() const { return mLoadInfo
.mPrincipal
; }
828 nsIPrincipal
* GetLoadingPrincipal() const {
829 return mLoadInfo
.mLoadingPrincipal
;
832 nsIPrincipal
* GetPartitionedPrincipal() const {
833 return mLoadInfo
.mPartitionedPrincipal
;
836 nsIPrincipal
* GetEffectiveStoragePrincipal() const;
838 nsILoadGroup
* GetLoadGroup() const {
839 AssertIsOnMainThread();
840 return mLoadInfo
.mLoadGroup
;
843 bool UsesSystemPrincipal() const {
844 return GetPrincipal()->IsSystemPrincipal();
846 bool UsesAddonOrExpandedAddonPrincipal() const {
847 return GetPrincipal()->GetIsAddonOrExpandedAddonPrincipal();
850 const mozilla::ipc::PrincipalInfo
& GetPrincipalInfo() const {
851 return *mLoadInfo
.mPrincipalInfo
;
854 const mozilla::ipc::PrincipalInfo
& GetPartitionedPrincipalInfo() const {
855 return *mLoadInfo
.mPartitionedPrincipalInfo
;
858 const mozilla::ipc::PrincipalInfo
& GetEffectiveStoragePrincipalInfo() const;
860 already_AddRefed
<nsIChannel
> ForgetWorkerChannel() {
861 AssertIsOnMainThread();
862 return mLoadInfo
.mChannel
.forget();
865 nsPIDOMWindowInner
* GetWindow() const {
866 AssertIsOnMainThread();
867 return mLoadInfo
.mWindow
;
870 nsPIDOMWindowInner
* GetAncestorWindow() const;
872 void EvictFromBFCache();
874 nsIContentSecurityPolicy
* GetCsp() const {
875 AssertIsOnMainThread();
876 return mLoadInfo
.mCSP
;
879 void SetCsp(nsIContentSecurityPolicy
* aCSP
);
881 nsresult
SetCSPFromHeaderValues(const nsACString
& aCSPHeaderValue
,
882 const nsACString
& aCSPReportOnlyHeaderValue
);
884 void StoreCSPOnClient();
886 const mozilla::ipc::CSPInfo
& GetCSPInfo() const {
887 return *mLoadInfo
.mCSPInfo
;
890 void UpdateReferrerInfoFromHeader(
891 const nsACString
& aReferrerPolicyHeaderValue
);
893 nsIReferrerInfo
* GetReferrerInfo() const { return mLoadInfo
.mReferrerInfo
; }
895 ReferrerPolicy
GetReferrerPolicy() const {
896 return mLoadInfo
.mReferrerInfo
->ReferrerPolicy();
899 void SetReferrerInfo(nsIReferrerInfo
* aReferrerInfo
) {
900 mLoadInfo
.mReferrerInfo
= aReferrerInfo
;
903 bool IsEvalAllowed() const { return mLoadInfo
.mEvalAllowed
; }
905 void SetEvalAllowed(bool aAllowed
) { mLoadInfo
.mEvalAllowed
= aAllowed
; }
907 bool GetReportEvalCSPViolations() const {
908 return mLoadInfo
.mReportEvalCSPViolations
;
911 void SetReportEvalCSPViolations(bool aReport
) {
912 mLoadInfo
.mReportEvalCSPViolations
= aReport
;
915 bool IsWasmEvalAllowed() const { return mLoadInfo
.mWasmEvalAllowed
; }
917 void SetWasmEvalAllowed(bool aAllowed
) {
918 mLoadInfo
.mWasmEvalAllowed
= aAllowed
;
921 bool GetReportWasmEvalCSPViolations() const {
922 return mLoadInfo
.mReportWasmEvalCSPViolations
;
925 void SetReportWasmEvalCSPViolations(bool aReport
) {
926 mLoadInfo
.mReportWasmEvalCSPViolations
= aReport
;
929 bool XHRParamsAllowed() const { return mLoadInfo
.mXHRParamsAllowed
; }
931 void SetXHRParamsAllowed(bool aAllowed
) {
932 mLoadInfo
.mXHRParamsAllowed
= aAllowed
;
935 mozilla::StorageAccess
StorageAccess() const {
936 AssertIsOnWorkerThread();
937 if (mLoadInfo
.mHasStorageAccessPermissionGranted
) {
938 return mozilla::StorageAccess::eAllow
;
941 return mLoadInfo
.mStorageAccess
;
944 bool UseRegularPrincipal() const {
945 AssertIsOnWorkerThread();
946 return mLoadInfo
.mUseRegularPrincipal
;
949 bool HasStorageAccessPermissionGranted() const {
950 AssertIsOnWorkerThread();
951 return mLoadInfo
.mHasStorageAccessPermissionGranted
;
954 nsICookieJarSettings
* CookieJarSettings() const {
956 MOZ_ASSERT(mLoadInfo
.mCookieJarSettings
);
957 return mLoadInfo
.mCookieJarSettings
;
960 const net::CookieJarSettingsArgs
& CookieJarSettingsArgs() const {
961 MOZ_ASSERT(mLoadInfo
.mCookieJarSettings
);
962 return mLoadInfo
.mCookieJarSettingsArgs
;
965 const OriginAttributes
& GetOriginAttributes() const {
966 return mLoadInfo
.mOriginAttributes
;
969 // Determine if the SW testing per-window flag is set by devtools
970 bool ServiceWorkersTestingInWindow() const {
971 return mLoadInfo
.mServiceWorkersTestingInWindow
;
974 // Determine if the worker was created under a third-party context.
975 bool IsThirdPartyContextToTopWindow() const {
976 return mLoadInfo
.mIsThirdPartyContextToTopWindow
;
979 bool IsWatchedByDevTools() const { return mLoadInfo
.mWatchedByDevTools
; }
981 bool ShouldResistFingerprinting(RFPTarget aTarget
) const;
983 RemoteWorkerChild
* GetRemoteWorkerController();
985 void SetRemoteWorkerController(RemoteWorkerChild
* aController
);
987 RefPtr
<GenericPromise
> SetServiceWorkerSkipWaitingFlag();
989 // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
990 // as these are only used for globals going in and out of the bfcache.
991 bool Freeze(const nsPIDOMWindowInner
* aWindow
);
993 bool Thaw(const nsPIDOMWindowInner
* aWindow
);
995 void PropagateStorageAccessPermissionGranted();
997 void EnableDebugger();
999 void DisableDebugger();
1001 already_AddRefed
<WorkerRunnable
> MaybeWrapAsWorkerRunnable(
1002 already_AddRefed
<nsIRunnable
> aRunnable
);
1004 bool ProxyReleaseMainThreadObjects();
1006 void SetLowMemoryState(bool aState
);
1008 void GarbageCollect(bool aShrinking
);
1010 void CycleCollect();
1012 nsresult
SetPrincipalsAndCSPOnMainThread(nsIPrincipal
* aPrincipal
,
1013 nsIPrincipal
* aPartitionedPrincipal
,
1014 nsILoadGroup
* aLoadGroup
,
1015 nsIContentSecurityPolicy
* aCsp
);
1017 nsresult
SetPrincipalsAndCSPFromChannel(nsIChannel
* aChannel
);
1019 bool FinalChannelPrincipalIsValid(nsIChannel
* aChannel
);
1021 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1022 bool PrincipalURIMatchesScriptURL();
1025 void UpdateOverridenLoadGroup(nsILoadGroup
* aBaseLoadGroup
);
1027 void WorkerScriptLoaded();
1029 Document
* GetDocument() const;
1031 void MemoryPressure();
1033 void UpdateContextOptions(const JS::ContextOptions
& aContextOptions
);
1035 void UpdateLanguages(const nsTArray
<nsString
>& aLanguages
);
1037 void UpdateJSWorkerMemoryParameter(JSGCParamKey key
, Maybe
<uint32_t> value
);
1040 void UpdateGCZeal(uint8_t aGCZeal
, uint32_t aFrequency
);
1043 void OfflineStatusChangeEvent(bool aIsOffline
);
1045 nsresult
Dispatch(already_AddRefed
<WorkerRunnable
> aRunnable
,
1046 nsIEventTarget
* aSyncLoopTarget
= nullptr);
1048 nsresult
DispatchControlRunnable(
1049 already_AddRefed
<WorkerControlRunnable
> aWorkerControlRunnable
);
1051 nsresult
DispatchDebuggerRunnable(
1052 already_AddRefed
<WorkerRunnable
> aDebuggerRunnable
);
1055 void AssertIsOnParentThread() const;
1057 void AssertInnerWindowIsCorrect() const;
1059 void AssertIsOnParentThread() const {}
1061 void AssertInnerWindowIsCorrect() const {}
1064 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1065 bool PrincipalIsValid() const;
1068 void StartCancelingTimer();
1070 const nsAString
& Id();
1072 const nsID
& AgentClusterId() const { return mAgentClusterId
; }
1074 bool IsSharedMemoryAllowed() const;
1076 // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated
1077 bool CrossOriginIsolated() const;
1079 void SetUseCounter(UseCounterWorker aUseCounter
) {
1080 MOZ_ASSERT(!mReportedUseCounters
);
1081 MOZ_ASSERT(aUseCounter
> UseCounterWorker::Unknown
);
1082 AssertIsOnWorkerThread();
1083 mUseCounters
[static_cast<size_t>(aUseCounter
)] = true;
1089 * If browser.tabs.remote.useCrossOriginEmbedderPolicy=false, these methods
1090 * will, depending on the return type, return a value that will avoid
1091 * assertion failures or a value that won't block loads.
1093 nsILoadInfo::CrossOriginEmbedderPolicy
GetEmbedderPolicy() const;
1095 // Fails if a policy has already been set or if `aPolicy` violates the owner's
1096 // policy, if an owner exists.
1097 mozilla::Result
<Ok
, nsresult
> SetEmbedderPolicy(
1098 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy
);
1100 // `aRequest` is the request loading the worker and must be QI-able to
1101 // `nsIChannel*`. It's used to verify that the worker can indeed inherit its
1102 // owner's COEP (when an owner exists).
1104 // TODO: remove `aRequest`; currently, it's required because instances may not
1105 // always know its final, resolved script URL or have access internally to
1107 void InheritOwnerEmbedderPolicyOrNull(nsIRequest
* aRequest
);
1109 // Requires a policy to already have been set.
1110 bool MatchEmbedderPolicy(
1111 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy
) const;
1113 nsILoadInfo::CrossOriginEmbedderPolicy
GetOwnerEmbedderPolicy() const;
1115 void SetCCCollectedAnything(bool collectedAnything
);
1116 bool isLastCCCollectedAnything();
1118 uint32_t GetCurrentTimerNestingLevel() const {
1119 auto data
= mWorkerThreadAccessible
.Access();
1120 return data
->mCurrentTimerNestingLevel
;
1123 void IncreaseTopLevelWorkerFinishedRunnableCount() {
1124 ++mTopLevelWorkerFinishedRunnableCount
;
1126 void DecreaseTopLevelWorkerFinishedRunnableCount() {
1127 --mTopLevelWorkerFinishedRunnableCount
;
1129 void IncreaseWorkerFinishedRunnableCount() { ++mWorkerFinishedRunnableCount
; }
1130 void DecreaseWorkerFinishedRunnableCount() { --mWorkerFinishedRunnableCount
; }
1132 void RunShutdownTasks();
1134 bool CancelBeforeWorkerScopeConstructed() const {
1135 auto data
= mWorkerThreadAccessible
.Access();
1136 return data
->mCancelBeforeWorkerScopeConstructed
;
1141 WorkerPrivate
* aParent
, const nsAString
& aScriptURL
, bool aIsChromeWorker
,
1142 WorkerKind aWorkerKind
, RequestCredentials aRequestCredentials
,
1143 enum WorkerType aWorkerType
, const nsAString
& aWorkerName
,
1144 const nsACString
& aServiceWorkerScope
, WorkerLoadInfo
& aLoadInfo
,
1145 nsString
&& aId
, const nsID
& aAgentClusterId
,
1146 const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy
,
1147 CancellationCallback
&& aCancellationCallback
,
1148 TerminationCallback
&& aTerminationCallback
);
1152 struct AgentClusterIdAndCoop
{
1154 nsILoadInfo::CrossOriginOpenerPolicy mCoop
;
1157 static AgentClusterIdAndCoop
ComputeAgentClusterIdAndCoop(
1158 WorkerPrivate
* aParent
, WorkerKind aWorkerKind
,
1159 WorkerLoadInfo
* aLoadInfo
);
1161 bool MayContinueRunning() {
1162 AssertIsOnWorkerThread();
1164 WorkerStatus status
;
1166 MutexAutoLock
lock(mMutex
);
1170 if (status
< Canceling
) {
1177 void CancelAllTimeouts();
1179 enum class ProcessAllControlRunnablesResult
{
1180 // We did not process anything.
1182 // We did process something, states may have changed, but we can keep
1183 // executing script.
1185 // We did process something, and should not continue executing script.
1189 ProcessAllControlRunnablesResult
ProcessAllControlRunnables() {
1190 MutexAutoLock
lock(mMutex
);
1191 return ProcessAllControlRunnablesLocked();
1194 ProcessAllControlRunnablesResult
ProcessAllControlRunnablesLocked()
1195 MOZ_REQUIRES(mMutex
);
1197 void EnableMemoryReporter();
1199 void DisableMemoryReporter();
1201 void WaitForWorkerEvents() MOZ_REQUIRES(mMutex
);
1203 // If the worker shutdown status is equal or greater then aFailStatus, this
1204 // operation will fail and nullptr will be returned. See WorkerStatus.h for
1205 // more information about the correct value to use.
1206 already_AddRefed
<nsISerialEventTarget
> CreateNewSyncLoop(
1207 WorkerStatus aFailStatus
);
1209 nsresult
RunCurrentSyncLoop();
1211 nsresult
DestroySyncLoop(uint32_t aLoopIndex
);
1213 void InitializeGCTimers();
1215 enum GCTimerMode
{ PeriodicTimer
= 0, IdleTimer
, NoTimer
};
1217 void SetGCTimerMode(GCTimerMode aMode
);
1220 void CancelGCTimers() { SetGCTimerMode(NoTimer
); }
1223 void ShutdownGCTimers();
1225 friend class WorkerRef
;
1227 bool AddWorkerRef(WorkerRef
* aWorkerRefer
, WorkerStatus aFailStatus
);
1229 void RemoveWorkerRef(WorkerRef
* aWorkerRef
);
1231 void NotifyWorkerRefs(WorkerStatus aStatus
);
1233 bool HasActiveWorkerRefs() {
1234 auto data
= mWorkerThreadAccessible
.Access();
1235 return !(data
->mChildWorkers
.IsEmpty() && data
->mTimeouts
.IsEmpty() &&
1236 data
->mWorkerRefs
.IsEmpty());
1239 friend class WorkerEventTarget
;
1241 nsresult
RegisterShutdownTask(nsITargetShutdownTask
* aTask
);
1243 nsresult
UnregisterShutdownTask(nsITargetShutdownTask
* aTask
);
1245 // Internal logic to dispatch a runnable. This is separate from Dispatch()
1246 // to allow runnables to be atomically dispatched in bulk.
1247 nsresult
DispatchLockHeld(already_AddRefed
<WorkerRunnable
> aRunnable
,
1248 nsIEventTarget
* aSyncLoopTarget
,
1249 const MutexAutoLock
& aProofOfLock
)
1250 MOZ_REQUIRES(mMutex
);
1252 // This method dispatches a simple runnable that starts the shutdown procedure
1253 // after a self.close(). This method is called after a ClearMainEventQueue()
1254 // to be sure that the canceling runnable is the only one in the queue. We
1255 // need this async operation to be sure that all the current JS code is
1257 void DispatchCancelingRunnable();
1259 bool GetUseCounter(UseCounterWorker aUseCounter
) {
1260 MOZ_ASSERT(aUseCounter
> UseCounterWorker::Unknown
);
1261 AssertIsOnWorkerThread();
1262 return mUseCounters
[static_cast<size_t>(aUseCounter
)];
1265 void ReportUseCounters();
1267 UniquePtr
<ClientSource
> CreateClientSource();
1269 // This method is called when corresponding script loader processes the COEP
1270 // header for the worker.
1271 // This method should be called only once in the main thread.
1272 // After this method is called the COEP value owner(window/parent worker) is
1273 // cached in mOwnerEmbedderPolicy such that it can be accessed in other
1274 // threads, i.e. WorkerThread.
1275 void EnsureOwnerEmbedderPolicy();
1278 friend class EventTarget
;
1279 friend class AutoSyncLoopHolder
;
1283 class MemoryReporter
;
1284 friend class MemoryReporter
;
1286 friend class mozilla::dom::WorkerThread
;
1289 mozilla::CondVar mCondVar
MOZ_GUARDED_BY(mMutex
);
1291 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1292 // our static assert
1293 MOZ_NON_OWNING_REF WorkerPrivate
* const mParent
;
1295 const nsString mScriptURL
;
1297 // This is the worker name for shared workers and dedicated workers.
1298 const nsString mWorkerName
;
1299 const RequestCredentials mCredentialsMode
;
1300 enum WorkerType mWorkerType
;
1302 const WorkerKind mWorkerKind
;
1304 // The worker is owned by its thread, which is represented here. This is set
1305 // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
1306 // traversed by the cycle collector if the busy count is zero.
1308 // There are 4 ways a worker can be terminated:
1309 // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
1310 // traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed
1311 // Worker webidl object. Doing this, CC will be able to detect a cycle and
1312 // Unlink is called. In Unlink, Worker calls Cancel().
1313 // 2. Worker::Cancel() is called - the shutdown procedure starts immediately.
1314 // 3. WorkerScope::Close() is called - Similar to point 2.
1315 // 4. xpcom-shutdown notification - We call Kill().
1316 RefPtr
<Worker
> mParentEventTargetRef
;
1317 RefPtr
<WorkerPrivate
> mSelfRef
;
1319 CancellationCallback mCancellationCallback
;
1321 // The termination callback is passed into the constructor on the parent
1322 // thread and invoked by `ClearSelfAndParentEventTargetRef` just before it
1323 // drops its self-ref.
1324 TerminationCallback mTerminationCallback
;
1326 // The lifetime of these objects within LoadInfo is managed explicitly;
1327 // they do not need to be cycle collected.
1328 WorkerLoadInfo mLoadInfo
;
1329 LocationInfo mLocationInfo
;
1331 // Protected by mMutex.
1332 workerinternals::JSSettings mJSSettings
MOZ_GUARDED_BY(mMutex
);
1334 WorkerDebugger
* mDebugger
;
1336 workerinternals::Queue
<WorkerControlRunnable
*, 4> mControlQueue
;
1337 workerinternals::Queue
<WorkerRunnable
*, 4> mDebuggerQueue
;
1339 // Touched on multiple threads, protected with mMutex. Only modified on the
1341 JSContext
* mJSContext
MOZ_GUARDED_BY(mMutex
);
1342 // mThread is only modified on the Worker thread, before calling DoRunLoop
1343 RefPtr
<WorkerThread
> mThread
MOZ_GUARDED_BY(mMutex
);
1344 // mPRThread is only modified on another thread in ScheduleWorker(), and is
1345 // constant for the duration of DoRunLoop. Static mutex analysis doesn't help
1347 PRThread
* mPRThread
;
1349 // Accessed from main thread
1350 RefPtr
<ThrottledEventQueue
> mMainThreadEventTargetForMessaging
;
1351 RefPtr
<ThrottledEventQueue
> mMainThreadEventTarget
;
1353 // Accessed from worker thread and destructing thread
1354 RefPtr
<WorkerEventTarget
> mWorkerControlEventTarget
;
1355 RefPtr
<WorkerEventTarget
> mWorkerHybridEventTarget
;
1357 // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread.
1358 // See WorkerDebuggeeRunnable for details.
1359 RefPtr
<ThrottledEventQueue
> mMainThreadDebuggeeEventTarget
;
1361 struct SyncLoopInfo
{
1362 explicit SyncLoopInfo(EventTarget
* aEventTarget
);
1364 RefPtr
<EventTarget
> mEventTarget
;
1372 // This is only modified on the worker thread, but in DEBUG builds
1373 // AssertValidSyncLoop function iterates it on other threads. Therefore
1374 // modifications are done with mMutex held *only* in DEBUG builds.
1375 nsTArray
<UniquePtr
<SyncLoopInfo
>> mSyncLoopStack
;
1377 nsCOMPtr
<nsITimer
> mCancelingTimer
;
1379 // fired on the main thread if the worker script fails to load
1380 nsCOMPtr
<nsIRunnable
> mLoadFailedRunnable
;
1382 RefPtr
<PerformanceStorage
> mPerformanceStorage
;
1384 RefPtr
<WorkerCSPEventListener
> mCSPEventListener
;
1386 // Protected by mMutex.
1387 nsTArray
<RefPtr
<WorkerRunnable
>> mPreStartRunnables
MOZ_GUARDED_BY(mMutex
);
1389 // Only touched on the parent thread. Used for both SharedWorker and
1390 // ServiceWorker RemoteWorkers.
1391 RefPtr
<RemoteWorkerChild
> mRemoteWorkerController
;
1393 JS::UniqueChars mDefaultLocale
; // nulled during worker JSContext init
1394 TimeStamp mKillTime
;
1395 WorkerStatus mParentStatus
MOZ_GUARDED_BY(mMutex
);
1396 WorkerStatus mStatus
MOZ_GUARDED_BY(mMutex
);
1398 // This is touched on parent thread only, but it can be read on a different
1399 // thread before crashing because hanging.
1400 Atomic
<uint64_t> mBusyCount
;
1402 TimeStamp mCreationTimeStamp
;
1403 DOMHighResTimeStamp mCreationTimeHighRes
;
1405 // Flags for use counters used directly by this worker.
1406 static_assert(sizeof(UseCounterWorker
) <= sizeof(size_t),
1407 "UseCounterWorker is too big");
1408 static_assert(UseCounterWorker::Count
>= static_cast<UseCounterWorker
>(0),
1409 "Should be non-negative value and safe to cast to unsigned");
1410 std::bitset
<static_cast<size_t>(UseCounterWorker::Count
)> mUseCounters
;
1411 bool mReportedUseCounters
;
1413 // This is created while creating the WorkerPrivate, so it's safe to be
1414 // touched on any thread.
1415 const nsID mAgentClusterId
;
1417 // Things touched on worker thread only.
1418 struct WorkerThreadAccessible
{
1419 explicit WorkerThreadAccessible(WorkerPrivate
* aParent
);
1421 RefPtr
<WorkerGlobalScope
> mScope
;
1422 RefPtr
<WorkerDebuggerGlobalScope
> mDebuggerScope
;
1423 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1424 // our static assert
1425 nsTArray
<WorkerPrivate
*> mChildWorkers
;
1426 nsTObserverArray
<WorkerRef
*> mWorkerRefs
;
1427 nsTArray
<UniquePtr
<TimeoutInfo
>> mTimeouts
;
1429 nsCOMPtr
<nsITimer
> mTimer
;
1430 nsCOMPtr
<nsITimerCallback
> mTimerRunnable
;
1432 nsCOMPtr
<nsITimer
> mPeriodicGCTimer
;
1433 nsCOMPtr
<nsITimer
> mIdleGCTimer
;
1435 RefPtr
<MemoryReporter
> mMemoryReporter
;
1437 // While running a nested event loop, whether a sync loop or a debugger
1438 // event loop we want to keep track of which global is running it, if any,
1439 // so runnables that run off that event loop can get at that information. In
1440 // practice this only matters for various worker debugger runnables running
1441 // against sandboxes, because all other runnables know which globals they
1442 // belong to already. We could also address this by threading the relevant
1443 // global through the chains of runnables involved, but we'd need to thread
1444 // it through some runnables that run on the main thread, and that would
1445 // require some care to make sure things get released on the correct thread,
1446 // which we'd rather avoid. This member is only accessed on the worker
1448 nsCOMPtr
<nsIGlobalObject
> mCurrentEventLoopGlobal
;
1450 // Timer that triggers an interrupt on expiration of the current time slice
1451 nsCOMPtr
<nsITimer
> mTSTimer
;
1453 // Execution manager used to regulate execution for this worker.
1454 RefPtr
<JSExecutionManager
> mExecutionManager
;
1456 // Used to relinguish clearance for CTypes Callbacks.
1457 nsTArray
<AutoYieldJSThreadExecution
> mYieldJSThreadExecution
;
1459 uint32_t mNumWorkerRefsPreventingShutdownStart
;
1460 uint32_t mDebuggerEventLoopLevel
;
1462 uint32_t mErrorHandlerRecursionCount
;
1463 int32_t mNextTimeoutId
;
1465 // Tracks the current setTimeout/setInterval nesting level.
1466 // When there isn't a TimeoutHandler on the stack, this will be 0.
1467 // Whenever setTimeout/setInterval are called, a new TimeoutInfo will be
1468 // created with a nesting level one more than the current nesting level,
1469 // saturating at the kClampTimeoutNestingLevel.
1471 // When RunExpiredTimeouts is run, it sets this value to the
1472 // TimeoutInfo::mNestingLevel for the duration of
1473 // the WorkerScriptTimeoutHandler::Call which will explicitly trigger a
1474 // microtask checkpoint so that any immediately-resolved promises will
1475 // still see the nesting level.
1476 uint32_t mCurrentTimerNestingLevel
;
1480 bool mRunningExpiredTimeouts
;
1481 bool mPeriodicGCTimerRunning
;
1482 bool mIdleGCTimerRunning
;
1484 bool mJSThreadExecutionGranted
;
1485 bool mCCCollectedAnything
;
1486 FlippedOnce
<false> mDeletionScheduled
;
1487 FlippedOnce
<false> mCancelBeforeWorkerScopeConstructed
;
1488 FlippedOnce
<false> mPerformedShutdownAfterLastContentTaskExecuted
;
1489 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1490 bool mIsPotentiallyLastGCCCRunning
= false;
1493 ThreadBound
<WorkerThreadAccessible
> mWorkerThreadAccessible
;
1495 class MOZ_RAII AutoPushEventLoopGlobal
{
1497 AutoPushEventLoopGlobal(WorkerPrivate
* aWorkerPrivate
, JSContext
* aCx
);
1498 ~AutoPushEventLoopGlobal();
1501 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate
1502 // our static assert
1503 MOZ_NON_OWNING_REF WorkerPrivate
* mWorkerPrivate
;
1504 nsCOMPtr
<nsIGlobalObject
> mOldEventLoopGlobal
;
1506 friend class AutoPushEventLoopGlobal
;
1508 uint32_t mPostSyncLoopOperations
;
1510 // List of operations to do at the end of the last sync event loop.
1512 eDispatchCancelingRunnable
= 0x02,
1515 bool mParentWindowPaused
;
1517 bool mWorkerScriptExecutedSuccessfully
;
1518 bool mFetchHandlerWasAdded
;
1519 bool mMainThreadObjectsForgotten
;
1520 bool mIsChromeWorker
;
1523 // mIsSecureContext is set once in our constructor; after that it can be read
1524 // from various threads.
1526 // It's a bit unfortunate that we have to have an out-of-band boolean for
1527 // this, but we need access to this state from the parent thread, and we can't
1528 // use our global object's secure state there.
1529 const bool mIsSecureContext
;
1531 bool mDebuggerRegistered
MOZ_GUARDED_BY(mMutex
);
1533 // During registration, this worker may be marked as not being ready to
1534 // execute debuggee runnables or content.
1536 // Protected by mMutex.
1537 bool mDebuggerReady
;
1538 nsTArray
<RefPtr
<WorkerRunnable
>> mDelayedDebuggeeRunnables
;
1540 // Whether this worker should have access to the WebExtension API bindings
1541 // (currently only the Extension Background ServiceWorker declared in the
1542 // extension manifest is allowed to access any WebExtension API bindings).
1543 // This default to false, and it is eventually set to true by
1544 // RemoteWorkerChild::ExecWorkerOnMainThread if the needed conditions
1546 bool mExtensionAPIAllowed
;
1548 // mIsInAutomation is true when we're running in test automation.
1549 // We expose some extra testing functions in that case.
1550 bool mIsInAutomation
;
1554 // This is used to check if it's allowed to share the memory across the agent
1556 const nsILoadInfo::CrossOriginOpenerPolicy mAgentClusterOpenerPolicy
;
1558 // Member variable of this class rather than the worker global scope because
1559 // it's received on the main thread, but the global scope is thread-bound
1560 // to the worker thread, so storing the value in the global scope would
1561 // involve sacrificing the thread-bound-ness or using a WorkerRunnable, and
1562 // there isn't a strong reason to store it on the global scope other than
1563 // better consistency with the COEP spec.
1564 Maybe
<nsILoadInfo::CrossOriginEmbedderPolicy
> mEmbedderPolicy
;
1565 Maybe
<nsILoadInfo::CrossOriginEmbedderPolicy
> mOwnerEmbedderPolicy
;
1567 /* Privileged add-on flag extracted from the AddonPolicy on the nsIPrincipal
1568 * on the main thread when constructing a top-level worker. The flag is
1569 * propagated to nested workers. The flag is only allowed to take effect in
1570 * extension processes and is forbidden in content scripts in content
1571 * processes. The flag may be read on either the parent/owner thread as well
1572 * as on the worker thread itself. When bug 1443925 is fixed allowing
1573 * nsIPrincipal to be used OMT, it may be possible to remove this flag. */
1574 bool mIsPrivilegedAddonGlobal
;
1576 Atomic
<uint32_t> mTopLevelWorkerFinishedRunnableCount
;
1577 Atomic
<uint32_t> mWorkerFinishedRunnableCount
;
1579 nsTArray
<nsCOMPtr
<nsITargetShutdownTask
>> mShutdownTasks
1580 MOZ_GUARDED_BY(mMutex
);
1581 bool mShutdownTasksRun
MOZ_GUARDED_BY(mMutex
) = false;
1584 class AutoSyncLoopHolder
{
1585 CheckedUnsafePtr
<WorkerPrivate
> mWorkerPrivate
;
1586 nsCOMPtr
<nsISerialEventTarget
> mTarget
;
1590 // See CreateNewSyncLoop() for more information about the correct value to use
1592 AutoSyncLoopHolder(WorkerPrivate
* aWorkerPrivate
, WorkerStatus aFailStatus
)
1593 : mWorkerPrivate(aWorkerPrivate
),
1594 mTarget(aWorkerPrivate
->CreateNewSyncLoop(aFailStatus
)),
1595 mIndex(aWorkerPrivate
->mSyncLoopStack
.Length() - 1) {
1596 aWorkerPrivate
->AssertIsOnWorkerThread();
1599 ~AutoSyncLoopHolder() {
1600 if (mWorkerPrivate
&& mTarget
) {
1601 mWorkerPrivate
->AssertIsOnWorkerThread();
1602 mWorkerPrivate
->StopSyncLoop(mTarget
, NS_ERROR_FAILURE
);
1603 mWorkerPrivate
->DestroySyncLoop(mIndex
);
1608 CheckedUnsafePtr
<WorkerPrivate
> workerPrivate
= mWorkerPrivate
;
1609 mWorkerPrivate
= nullptr;
1611 workerPrivate
->AssertIsOnWorkerThread();
1613 return workerPrivate
->RunCurrentSyncLoop();
1616 nsISerialEventTarget
* GetSerialEventTarget() const {
1617 // This can be null if CreateNewSyncLoop() fails.
1623 } // namespace mozilla
1625 #endif /* mozilla_dom_workers_workerprivate_h__ */