2 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #ifndef mozilla_dom_workers_workerprivate_h__
9 #define mozilla_dom_workers_workerprivate_h__
11 #include "mozilla/dom/WorkerCommon.h"
12 #include "mozilla/dom/WorkerStatus.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/CondVar.h"
15 #include "mozilla/DOMEventTargetHelper.h"
16 #include "mozilla/MozPromise.h"
17 #include "mozilla/RelativeTimeline.h"
18 #include "mozilla/StorageAccess.h"
19 #include "mozilla/ThreadSafeWeakPtr.h"
20 #include "mozilla/UseCounter.h"
21 #include "nsContentUtils.h"
22 #include "nsIContentSecurityPolicy.h"
23 #include "nsIEventTarget.h"
24 #include "nsTObserverArray.h"
26 #include "js/ContextOptions.h"
27 #include "mozilla/dom/RemoteWorkerChild.h"
28 #include "mozilla/dom/Worker.h"
29 #include "mozilla/dom/WorkerLoadInfo.h"
30 #include "mozilla/dom/workerinternals/JSSettings.h"
31 #include "mozilla/dom/workerinternals/Queue.h"
32 #include "mozilla/PerformanceCounter.h"
33 #include "mozilla/ThreadBound.h"
35 class nsIThreadInternal
;
38 class ThrottledEventQueue
;
41 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
42 // to be updated too. And histograms enum for worker use counters uses the same
43 // order of worker type. Please also update dom/base/usecounters.py.
44 enum WorkerType
{ WorkerTypeDedicated
, WorkerTypeShared
, WorkerTypeService
};
50 class UniqueMessagePortId
;
51 class PerformanceStorage
;
53 class WorkerControlRunnable
;
54 class WorkerCSPEventListener
;
56 class WorkerDebuggerGlobalScope
;
57 class WorkerErrorReport
;
58 class WorkerEventTarget
;
59 class WorkerGlobalScope
;
62 class WorkerDebuggeeRunnable
;
65 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
66 // object. It exists to avoid changing a lot of code to use Mutex* instead of
69 typedef mozilla::Mutex Mutex
;
71 class RefCountedMutex final
: public Mutex
{
73 explicit RefCountedMutex(const char* aName
) : Mutex(aName
) {}
75 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex
)
81 RefPtr
<RefCountedMutex
> mMutex
;
84 explicit SharedMutex(const char* aName
)
85 : mMutex(new RefCountedMutex(aName
)) {}
87 SharedMutex(SharedMutex
& aOther
) : mMutex(aOther
.mMutex
) {}
89 operator Mutex
&() { return *mMutex
; }
91 operator const Mutex
&() const { return *mMutex
; }
93 void AssertCurrentThreadOwns() const { mMutex
->AssertCurrentThreadOwns(); }
96 nsString
ComputeWorkerPrivateId();
98 class WorkerPrivate
: public RelativeTimeline
{
100 struct LocationInfo
{
112 NS_INLINE_DECL_REFCOUNTING(WorkerPrivate
)
114 static already_AddRefed
<WorkerPrivate
> Constructor(
115 JSContext
* aCx
, const nsAString
& aScriptURL
, bool aIsChromeWorker
,
116 WorkerType aWorkerType
, const nsAString
& aWorkerName
,
117 const nsACString
& aServiceWorkerScope
, WorkerLoadInfo
* aLoadInfo
,
118 ErrorResult
& aRv
, nsString aId
= EmptyString());
120 enum LoadGroupBehavior
{ InheritLoadGroup
, OverrideLoadGroup
};
122 static nsresult
GetLoadInfo(JSContext
* aCx
, nsPIDOMWindowInner
* aWindow
,
123 WorkerPrivate
* aParent
,
124 const nsAString
& aScriptURL
, bool aIsChromeWorker
,
125 LoadGroupBehavior aLoadGroupBehavior
,
126 WorkerType aWorkerType
,
127 WorkerLoadInfo
* aLoadInfo
);
129 void Traverse(nsCycleCollectionTraversalCallback
& aCb
);
131 void ClearSelfAndParentEventTargetRef() {
132 AssertIsOnParentThread();
133 MOZ_ASSERT(mSelfRef
);
134 mParentEventTargetRef
= nullptr;
138 // May be called on any thread...
141 // Called on the parent thread.
142 bool Notify(WorkerStatus aStatus
);
144 bool Cancel() { return Notify(Canceling
); }
148 // The passed principal must be the Worker principal in case of a
149 // ServiceWorker and the loading principal for any other type.
150 static void OverrideLoadInfoLoadGroup(WorkerLoadInfo
& aLoadInfo
,
151 nsIPrincipal
* aPrincipal
);
153 bool IsDebuggerRegistered() {
154 AssertIsOnMainThread();
156 // No need to lock here since this is only ever modified by the same thread.
157 return mDebuggerRegistered
;
160 void SetIsDebuggerRegistered(bool aDebuggerRegistered
) {
161 AssertIsOnMainThread();
163 MutexAutoLock
lock(mMutex
);
165 MOZ_ASSERT(mDebuggerRegistered
!= aDebuggerRegistered
);
166 mDebuggerRegistered
= aDebuggerRegistered
;
171 void WaitForIsDebuggerRegistered(bool aDebuggerRegistered
) {
172 AssertIsOnParentThread();
174 MOZ_ASSERT(!NS_IsMainThread());
176 MutexAutoLock
lock(mMutex
);
178 while (mDebuggerRegistered
!= aDebuggerRegistered
) {
183 nsresult
SetIsDebuggerReady(bool aReady
);
185 WorkerDebugger
* Debugger() const {
186 AssertIsOnMainThread();
188 MOZ_ASSERT(mDebugger
);
192 void SetDebugger(WorkerDebugger
* aDebugger
) {
193 AssertIsOnMainThread();
195 MOZ_ASSERT(mDebugger
!= aDebugger
);
196 mDebugger
= aDebugger
;
199 JS::UniqueChars
AdoptDefaultLocale() {
200 MOZ_ASSERT(mDefaultLocale
,
201 "the default locale must have been successfully set for anyone "
202 "to be trying to adopt it");
203 return std::move(mDefaultLocale
);
207 void DoRunLoop(JSContext
* aCx
);
209 bool InterruptCallback(JSContext
* aCx
);
211 bool IsOnCurrentThread();
213 void CloseInternal();
215 bool FreezeInternal();
219 void PropagateFirstPartyStorageAccessGrantedInternal();
221 void TraverseTimeouts(nsCycleCollectionTraversalCallback
& aCallback
);
223 void UnlinkTimeouts();
225 bool ModifyBusyCountFromWorker(bool aIncrease
);
227 bool AddChildWorker(WorkerPrivate
* aChildWorker
);
229 void RemoveChildWorker(WorkerPrivate
* aChildWorker
);
231 void PostMessageToParent(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
232 const Sequence
<JSObject
*>& aTransferable
,
235 void PostMessageToParentMessagePort(JSContext
* aCx
,
236 JS::Handle
<JS::Value
> aMessage
,
237 const Sequence
<JSObject
*>& aTransferable
,
240 MOZ_CAN_RUN_SCRIPT
void EnterDebuggerEventLoop();
242 void LeaveDebuggerEventLoop();
244 void PostMessageToDebugger(const nsAString
& aMessage
);
246 void SetDebuggerImmediate(Function
& aHandler
, ErrorResult
& aRv
);
248 void ReportErrorToDebugger(const nsAString
& aFilename
, uint32_t aLineno
,
249 const nsAString
& aMessage
);
251 bool NotifyInternal(WorkerStatus aStatus
);
253 void ReportError(JSContext
* aCx
, JS::ConstUTF8CharsZ aToStringResult
,
254 JSErrorReport
* aReport
);
256 static void ReportErrorToConsole(const char* aMessage
);
258 static void ReportErrorToConsole(const char* aMessage
,
259 const nsTArray
<nsString
>& aParams
);
261 int32_t SetTimeout(JSContext
* aCx
, TimeoutHandler
* aHandler
, int32_t aTimeout
,
262 bool aIsInterval
, ErrorResult
& aRv
);
264 void ClearTimeout(int32_t aId
);
266 MOZ_CAN_RUN_SCRIPT
bool RunExpiredTimeouts(JSContext
* aCx
);
268 bool RescheduleTimeoutTimer(JSContext
* aCx
);
270 void UpdateContextOptionsInternal(JSContext
* aCx
,
271 const JS::ContextOptions
& aContextOptions
);
273 void UpdateLanguagesInternal(const nsTArray
<nsString
>& aLanguages
);
275 void UpdateJSWorkerMemoryParameterInternal(JSContext
* aCx
, JSGCParamKey key
,
278 enum WorkerRanOrNot
{ WorkerNeverRan
= 0, WorkerRan
};
280 void ScheduleDeletion(WorkerRanOrNot aRanOrNot
);
282 bool CollectRuntimeStats(JS::RuntimeStats
* aRtStats
, bool aAnonymize
);
285 void UpdateGCZealInternal(JSContext
* aCx
, uint8_t aGCZeal
,
286 uint32_t aFrequency
);
289 void SetLowMemoryStateInternal(JSContext
* aCx
, bool aState
);
291 void GarbageCollectInternal(JSContext
* aCx
, bool aShrinking
,
292 bool aCollectChildren
);
294 void CycleCollectInternal(bool aCollectChildren
);
296 void OfflineStatusChangeEventInternal(bool aIsOffline
);
298 void MemoryPressureInternal();
300 void SetFetchHandlerWasAdded() {
301 MOZ_ASSERT(IsServiceWorker());
302 AssertIsOnWorkerThread();
303 mFetchHandlerWasAdded
= true;
306 bool FetchHandlerWasAdded() const {
307 MOZ_ASSERT(IsServiceWorker());
308 AssertIsOnWorkerThread();
309 return mFetchHandlerWasAdded
;
312 JSContext
* GetJSContext() const {
313 AssertIsOnWorkerThread();
317 WorkerGlobalScope
* GlobalScope() const {
318 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
322 WorkerDebuggerGlobalScope
* DebuggerGlobalScope() const {
323 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
324 return data
->mDebuggerScope
;
327 // Get the global associated with the current nested event loop. Will return
328 // null if we're not in a nested event loop or that nested event loop does not
329 // have an associated global.
330 nsIGlobalObject
* GetCurrentEventLoopGlobal() const {
331 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
332 return data
->mCurrentEventLoopGlobal
;
335 nsICSPEventListener
* CSPEventListener() const;
337 void SetThread(WorkerThread
* aThread
);
339 void SetWorkerPrivateInWorkerThread(WorkerThread
* aThread
);
341 void ResetWorkerPrivateInWorkerThread();
343 bool IsOnWorkerThread() const;
345 void AssertIsOnWorkerThread() const
354 void BeginCTypesCall();
357 void EndCTypesCall();
359 void BeginCTypesCallback() {
360 // If a callback is beginning then we need to do the exact same thing as
361 // when a ctypes call ends.
365 void EndCTypesCallback() {
366 // If a callback is ending then we need to do the exact same thing as
367 // when a ctypes call begins.
371 bool ConnectMessagePort(JSContext
* aCx
, UniqueMessagePortId
& aIdentifier
);
373 WorkerGlobalScope
* GetOrCreateGlobalScope(JSContext
* aCx
);
375 WorkerDebuggerGlobalScope
* CreateDebuggerGlobalScope(JSContext
* aCx
);
377 bool RegisterBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
379 bool RegisterDebuggerBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
381 bool OnLine() const {
382 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
383 return data
->mOnLine
;
386 void StopSyncLoop(nsIEventTarget
* aSyncLoopTarget
, bool aResult
);
388 bool AllPendingRunnablesShouldBeCanceled() const {
389 return mCancelAllPendingRunnables
;
392 void ClearMainEventQueue(WorkerRanOrNot aRanOrNot
);
394 void ClearDebuggerEventQueue();
396 void OnProcessNextEvent();
398 void AfterProcessNextEvent();
400 void AssertValidSyncLoop(nsIEventTarget
* aSyncLoopTarget
)
408 void SetWorkerScriptExecutedSuccessfully() {
409 AssertIsOnWorkerThread();
410 // Should only be called once!
411 MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully
);
412 mWorkerScriptExecutedSuccessfully
= true;
415 // Only valid after CompileScriptRunnable has finished running!
416 bool WorkerScriptExecutedSuccessfully() const {
417 AssertIsOnWorkerThread();
418 return mWorkerScriptExecutedSuccessfully
;
421 // Get the event target to use when dispatching to the main thread
422 // from this Worker thread. This may be the main thread itself or
423 // a ThrottledEventQueue to the main thread.
424 nsIEventTarget
* MainThreadEventTargetForMessaging();
426 nsresult
DispatchToMainThreadForMessaging(
427 nsIRunnable
* aRunnable
, uint32_t aFlags
= NS_DISPATCH_NORMAL
);
429 nsresult
DispatchToMainThreadForMessaging(
430 already_AddRefed
<nsIRunnable
> aRunnable
,
431 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
433 nsIEventTarget
* MainThreadEventTarget();
435 nsresult
DispatchToMainThread(nsIRunnable
* aRunnable
,
436 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
438 nsresult
DispatchToMainThread(already_AddRefed
<nsIRunnable
> aRunnable
,
439 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
441 nsresult
DispatchDebuggeeToMainThread(
442 already_AddRefed
<WorkerDebuggeeRunnable
> aRunnable
,
443 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
445 // Get an event target that will dispatch runnables as control runnables on
446 // the worker thread. Implement nsICancelableRunnable if you wish to take
447 // action on cancelation.
448 nsISerialEventTarget
* ControlEventTarget();
450 // Get an event target that will attempt to dispatch a normal WorkerRunnable,
451 // but if that fails will then fall back to a control runnable.
452 nsISerialEventTarget
* HybridEventTarget();
454 void DumpCrashInformation(nsACString
& aString
);
456 bool EnsureClientSource();
458 bool EnsureCSPEventListener();
460 void EnsurePerformanceStorage();
462 void EnsurePerformanceCounter();
464 Maybe
<ClientInfo
> GetClientInfo() const;
466 const ClientState
GetClientState() const;
468 const Maybe
<ServiceWorkerDescriptor
> GetController();
470 void Control(const ServiceWorkerDescriptor
& aServiceWorker
);
472 void ExecutionReady();
474 PerformanceStorage
* GetPerformanceStorage();
476 PerformanceCounter
* GetPerformanceCounter();
478 bool IsAcceptingEvents() {
479 AssertIsOnParentThread();
481 MutexAutoLock
lock(mMutex
);
482 return mParentStatus
< Canceling
;
485 WorkerStatus
ParentStatusProtected() {
486 AssertIsOnParentThread();
487 MutexAutoLock
lock(mMutex
);
488 return mParentStatus
;
491 WorkerStatus
ParentStatus() const {
492 mMutex
.AssertCurrentThreadOwns();
493 return mParentStatus
;
496 Worker
* ParentEventTargetRef() const {
497 MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef
);
498 return mParentEventTargetRef
;
501 void SetParentEventTargetRef(Worker
* aParentEventTargetRef
) {
502 MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef
);
503 MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef
);
504 mParentEventTargetRef
= aParentEventTargetRef
;
507 bool ModifyBusyCount(bool aIncrease
);
509 // This method is used by RuntimeService to know what is going wrong the
511 uint32_t BusyCount() { return mBusyCount
; }
513 // Check whether this worker is a secure context. For use from the parent
514 // thread only; the canonical "is secure context" boolean is stored on the
515 // compartment of the worker global. The only reason we don't
516 // AssertIsOnParentThread() here is so we can assert that this value matches
517 // the one on the compartment, which has to be done from the worker thread.
518 bool IsSecureContext() const { return mIsSecureContext
; }
520 // Check whether we're running in automation.
521 bool IsInAutomation() const { return mIsInAutomation
; }
523 TimeStamp
CreationTimeStamp() const { return mCreationTimeStamp
; }
525 DOMHighResTimeStamp
CreationTime() const { return mCreationTimeHighRes
; }
527 DOMHighResTimeStamp
TimeStampToDOMHighRes(const TimeStamp
& aTimeStamp
) const {
528 MOZ_ASSERT(!aTimeStamp
.IsNull());
529 TimeDuration duration
= aTimeStamp
- mCreationTimeStamp
;
530 return duration
.ToMilliseconds();
533 LocationInfo
& GetLocationInfo() { return mLocationInfo
; }
535 void CopyJSSettings(workerinternals::JSSettings
& aSettings
) {
536 mozilla::MutexAutoLock
lock(mMutex
);
537 aSettings
= mJSSettings
;
540 void CopyJSRealmOptions(JS::RealmOptions
& aOptions
) {
541 mozilla::MutexAutoLock
lock(mMutex
);
542 aOptions
= IsChromeWorker() ? mJSSettings
.chrome
.realmOptions
543 : mJSSettings
.content
.realmOptions
;
546 // The ability to be a chrome worker is orthogonal to the type of
547 // worker [Dedicated|Shared|Service].
548 bool IsChromeWorker() const { return mIsChromeWorker
; }
550 WorkerPrivate
* GetParent() const { return mParent
; }
552 bool IsFrozen() const {
553 AssertIsOnParentThread();
554 return mParentFrozen
;
557 bool IsParentWindowPaused() const {
558 AssertIsOnParentThread();
559 return mParentWindowPaused
;
562 // When we debug a worker, we want to disconnect the window and the worker
563 // communication. This happens calling this method.
564 // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
565 void ParentWindowPaused();
567 void ParentWindowResumed();
569 const nsString
& ScriptURL() const { return mScriptURL
; }
571 const nsString
& WorkerName() const { return mWorkerName
; }
573 WorkerType
Type() const { return mWorkerType
; }
575 bool IsDedicatedWorker() const { return mWorkerType
== WorkerTypeDedicated
; }
577 bool IsSharedWorker() const { return mWorkerType
== WorkerTypeShared
; }
579 bool IsServiceWorker() const { return mWorkerType
== WorkerTypeService
; }
581 nsContentPolicyType
ContentPolicyType() const {
582 return ContentPolicyType(mWorkerType
);
585 static nsContentPolicyType
ContentPolicyType(WorkerType aWorkerType
) {
586 switch (aWorkerType
) {
587 case WorkerTypeDedicated
:
588 return nsIContentPolicy::TYPE_INTERNAL_WORKER
;
589 case WorkerTypeShared
:
590 return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
;
591 case WorkerTypeService
:
592 return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER
;
594 MOZ_ASSERT_UNREACHABLE("Invalid worker type");
595 return nsIContentPolicy::TYPE_INVALID
;
599 nsIScriptContext
* GetScriptContext() const {
600 AssertIsOnMainThread();
601 return mLoadInfo
.mScriptContext
;
604 const nsCString
& Domain() const { return mLoadInfo
.mDomain
; }
606 bool IsFromWindow() const { return mLoadInfo
.mFromWindow
; }
608 nsLoadFlags
GetLoadFlags() const { return mLoadInfo
.mLoadFlags
; }
610 uint64_t WindowID() const { return mLoadInfo
.mWindowID
; }
612 uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); }
614 const nsCString
& ServiceWorkerScope() const {
615 return GetServiceWorkerDescriptor().Scope();
618 nsIURI
* GetBaseURI() const {
619 AssertIsOnMainThread();
620 return mLoadInfo
.mBaseURI
;
623 void SetBaseURI(nsIURI
* aBaseURI
);
625 nsIURI
* GetResolvedScriptURI() const {
626 AssertIsOnMainThread();
627 return mLoadInfo
.mResolvedScriptURI
;
630 const nsString
& ServiceWorkerCacheName() const {
631 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
632 AssertIsOnMainThread();
633 return mLoadInfo
.mServiceWorkerCacheName
;
636 const ServiceWorkerDescriptor
& GetServiceWorkerDescriptor() const {
637 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
638 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
639 return mLoadInfo
.mServiceWorkerDescriptor
.ref();
642 const ServiceWorkerRegistrationDescriptor
&
643 GetServiceWorkerRegistrationDescriptor() const {
644 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
645 MOZ_DIAGNOSTIC_ASSERT(
646 mLoadInfo
.mServiceWorkerRegistrationDescriptor
.isSome());
647 return mLoadInfo
.mServiceWorkerRegistrationDescriptor
.ref();
650 void UpdateServiceWorkerState(ServiceWorkerState aState
) {
651 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
652 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
653 return mLoadInfo
.mServiceWorkerDescriptor
.ref().SetState(aState
);
656 const Maybe
<ServiceWorkerDescriptor
>& GetParentController() const {
657 return mLoadInfo
.mParentController
;
660 const ChannelInfo
& GetChannelInfo() const { return mLoadInfo
.mChannelInfo
; }
662 void SetChannelInfo(const ChannelInfo
& aChannelInfo
) {
663 AssertIsOnMainThread();
664 MOZ_ASSERT(!mLoadInfo
.mChannelInfo
.IsInitialized());
665 MOZ_ASSERT(aChannelInfo
.IsInitialized());
666 mLoadInfo
.mChannelInfo
= aChannelInfo
;
669 void InitChannelInfo(nsIChannel
* aChannel
) {
670 mLoadInfo
.mChannelInfo
.InitFromChannel(aChannel
);
673 void InitChannelInfo(const ChannelInfo
& aChannelInfo
) {
674 mLoadInfo
.mChannelInfo
= aChannelInfo
;
677 nsIPrincipal
* GetPrincipal() const {
678 AssertIsOnMainThread();
679 return mLoadInfo
.mPrincipal
;
682 nsIPrincipal
* GetEffectiveStoragePrincipal() const {
683 AssertIsOnMainThread();
684 return mLoadInfo
.mStoragePrincipal
;
687 nsIPrincipal
* GetLoadingPrincipal() const {
688 AssertIsOnMainThread();
689 return mLoadInfo
.mLoadingPrincipal
;
692 const nsAString
& Origin() const { return mLoadInfo
.mOrigin
; }
694 nsILoadGroup
* GetLoadGroup() const {
695 AssertIsOnMainThread();
696 return mLoadInfo
.mLoadGroup
;
699 bool UsesSystemPrincipal() const { return mLoadInfo
.mPrincipalIsSystem
; }
700 bool UsesAddonOrExpandedAddonPrincipal() const {
701 return mLoadInfo
.mPrincipalIsAddonOrExpandedAddon
;
704 const mozilla::ipc::PrincipalInfo
& GetPrincipalInfo() const {
705 return *mLoadInfo
.mPrincipalInfo
;
708 const mozilla::ipc::PrincipalInfo
& GetEffectiveStoragePrincipalInfo() const {
709 return *mLoadInfo
.mStoragePrincipalInfo
;
712 already_AddRefed
<nsIChannel
> ForgetWorkerChannel() {
713 AssertIsOnMainThread();
714 return mLoadInfo
.mChannel
.forget();
717 nsPIDOMWindowInner
* GetWindow() {
718 AssertIsOnMainThread();
719 return mLoadInfo
.mWindow
;
722 nsIContentSecurityPolicy
* GetCSP() const {
723 AssertIsOnMainThread();
724 return mLoadInfo
.mCSP
;
727 void SetCSP(nsIContentSecurityPolicy
* aCSP
);
729 nsresult
SetCSPFromHeaderValues(const nsACString
& aCSPHeaderValue
,
730 const nsACString
& aCSPReportOnlyHeaderValue
);
732 void StoreCSPOnClient();
734 const mozilla::ipc::CSPInfo
& GetCSPInfo() const {
735 return *mLoadInfo
.mCSPInfo
;
738 void UpdateReferrerInfoFromHeader(
739 const nsACString
& aReferrerPolicyHeaderValue
);
741 nsIReferrerInfo
* GetReferrerInfo() const { return mLoadInfo
.mReferrerInfo
; }
743 ReferrerPolicy
GetReferrerPolicy() const {
744 return mLoadInfo
.mReferrerInfo
->ReferrerPolicy();
747 void SetReferrerInfo(nsIReferrerInfo
* aReferrerInfo
) {
748 mLoadInfo
.mReferrerInfo
= aReferrerInfo
;
751 bool IsEvalAllowed() const { return mLoadInfo
.mEvalAllowed
; }
753 void SetEvalAllowed(bool aEvalAllowed
) {
754 mLoadInfo
.mEvalAllowed
= aEvalAllowed
;
757 bool GetReportCSPViolations() const { return mLoadInfo
.mReportCSPViolations
; }
759 void SetReportCSPViolations(bool aReport
) {
760 mLoadInfo
.mReportCSPViolations
= aReport
;
763 bool XHRParamsAllowed() const { return mLoadInfo
.mXHRParamsAllowed
; }
765 void SetXHRParamsAllowed(bool aAllowed
) {
766 mLoadInfo
.mXHRParamsAllowed
= aAllowed
;
769 mozilla::StorageAccess
StorageAccess() const {
770 AssertIsOnWorkerThread();
771 if (mLoadInfo
.mFirstPartyStorageAccessGranted
) {
772 return mozilla::StorageAccess::eAllow
;
775 return mLoadInfo
.mStorageAccess
;
778 nsICookieSettings
* CookieSettings() const {
780 MOZ_ASSERT(mLoadInfo
.mCookieSettings
);
781 return mLoadInfo
.mCookieSettings
;
784 const OriginAttributes
& GetOriginAttributes() const {
785 return mLoadInfo
.mOriginAttributes
;
788 // Determine if the SW testing per-window flag is set by devtools
789 bool ServiceWorkersTestingInWindow() const {
790 return mLoadInfo
.mServiceWorkersTestingInWindow
;
793 bool IsWatchedByDevtools() const { return mLoadInfo
.mWatchedByDevtools
; }
795 // Determine if the worker is currently loading its top level script.
796 bool IsLoadingWorkerScript() const { return mLoadingWorkerScript
; }
798 // Called by ScriptLoader to track when this worker is loading its
800 void SetLoadingWorkerScript(bool aLoadingWorkerScript
) {
802 mLoadingWorkerScript
= aLoadingWorkerScript
;
805 RemoteWorkerChild
* GetRemoteWorkerController();
807 void SetRemoteWorkerController(RemoteWorkerChild
* aController
);
809 void SetRemoteWorkerControllerWeakRef(
810 ThreadSafeWeakPtr
<RemoteWorkerChild
> aWeakRef
);
812 ThreadSafeWeakPtr
<RemoteWorkerChild
> GetRemoteWorkerControllerWeakRef();
814 RefPtr
<GenericPromise
> SetServiceWorkerSkipWaitingFlag();
816 // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
817 // as these are only used for globals going in and out of the bfcache.
818 bool Freeze(nsPIDOMWindowInner
* aWindow
);
820 bool Thaw(nsPIDOMWindowInner
* aWindow
);
822 void PropagateFirstPartyStorageAccessGranted();
824 void EnableDebugger();
826 void DisableDebugger();
828 already_AddRefed
<WorkerRunnable
> MaybeWrapAsWorkerRunnable(
829 already_AddRefed
<nsIRunnable
> aRunnable
);
831 bool ProxyReleaseMainThreadObjects();
833 void SetLowMemoryState(bool aState
);
835 void GarbageCollect(bool aShrinking
);
837 void CycleCollect(bool aDummy
);
839 nsresult
SetPrincipalsAndCSPOnMainThread(nsIPrincipal
* aPrincipal
,
840 nsIPrincipal
* aStoragePrincipal
,
841 nsILoadGroup
* aLoadGroup
,
842 nsIContentSecurityPolicy
* aCsp
);
844 nsresult
SetPrincipalsAndCSPFromChannel(nsIChannel
* aChannel
);
846 bool FinalChannelPrincipalIsValid(nsIChannel
* aChannel
);
848 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
849 bool PrincipalURIMatchesScriptURL();
852 void UpdateOverridenLoadGroup(nsILoadGroup
* aBaseLoadGroup
);
854 void WorkerScriptLoaded();
856 Document
* GetDocument() const;
858 void MemoryPressure(bool aDummy
);
860 void UpdateContextOptions(const JS::ContextOptions
& aContextOptions
);
862 void UpdateLanguages(const nsTArray
<nsString
>& aLanguages
);
864 void UpdateJSWorkerMemoryParameter(JSGCParamKey key
, uint32_t value
);
867 void UpdateGCZeal(uint8_t aGCZeal
, uint32_t aFrequency
);
870 void OfflineStatusChangeEvent(bool aIsOffline
);
872 nsresult
Dispatch(already_AddRefed
<WorkerRunnable
> aRunnable
,
873 nsIEventTarget
* aSyncLoopTarget
= nullptr);
875 nsresult
DispatchControlRunnable(
876 already_AddRefed
<WorkerControlRunnable
> aWorkerControlRunnable
);
878 nsresult
DispatchDebuggerRunnable(
879 already_AddRefed
<WorkerRunnable
> aDebuggerRunnable
);
882 void AssertIsOnParentThread() const;
884 void AssertInnerWindowIsCorrect() const;
886 void AssertIsOnParentThread() const {}
888 void AssertInnerWindowIsCorrect() const {}
891 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
892 bool PrincipalIsValid() const;
895 void StartCancelingTimer();
897 const nsAString
& Id();
899 const nsID
& AgentClusterId() const { return mAgentClusterId
; }
901 bool IsSharedMemoryAllowed() const;
903 // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated
904 bool CrossOriginIsolated() const;
906 void SetUseCounter(UseCounterWorker aUseCounter
) {
907 MOZ_ASSERT(!mReportedUseCounters
);
908 MOZ_ASSERT(aUseCounter
> UseCounterWorker::Unknown
);
909 AssertIsOnWorkerThread();
910 mUseCounters
[static_cast<size_t>(aUseCounter
)] = true;
915 WorkerPrivate
* aParent
, const nsAString
& aScriptURL
, bool aIsChromeWorker
,
916 WorkerType aWorkerType
, const nsAString
& aWorkerName
,
917 const nsACString
& aServiceWorkerScope
, WorkerLoadInfo
& aLoadInfo
,
918 nsString
&& aId
, const nsID
& aAgentClusterId
,
919 const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy
);
923 bool MayContinueRunning() {
924 AssertIsOnWorkerThread();
928 MutexAutoLock
lock(mMutex
);
932 if (status
< Canceling
) {
939 void CancelAllTimeouts();
941 enum class ProcessAllControlRunnablesResult
{
942 // We did not process anything.
944 // We did process something, states may have changed, but we can keep
947 // We did process something, and should not continue executing script.
951 ProcessAllControlRunnablesResult
ProcessAllControlRunnables() {
952 MutexAutoLock
lock(mMutex
);
953 return ProcessAllControlRunnablesLocked();
956 ProcessAllControlRunnablesResult
ProcessAllControlRunnablesLocked();
958 void EnableMemoryReporter();
960 void DisableMemoryReporter();
962 void WaitForWorkerEvents();
964 // If the worker shutdown status is equal or greater then aFailStatus, this
965 // operation will fail and nullptr will be returned. See WorkerStatus.h for
966 // more information about the correct value to use.
967 already_AddRefed
<nsIEventTarget
> CreateNewSyncLoop(WorkerStatus aFailStatus
);
969 bool RunCurrentSyncLoop();
971 bool DestroySyncLoop(uint32_t aLoopIndex
);
973 void InitializeGCTimers();
975 enum GCTimerMode
{ PeriodicTimer
= 0, IdleTimer
, NoTimer
};
977 void SetGCTimerMode(GCTimerMode aMode
);
979 void ShutdownGCTimers();
981 friend class WorkerRef
;
983 bool AddWorkerRef(WorkerRef
* aWorkerRefer
, WorkerStatus aFailStatus
);
985 void RemoveWorkerRef(WorkerRef
* aWorkerRef
);
987 void NotifyWorkerRefs(WorkerStatus aStatus
);
989 bool HasActiveWorkerRefs() {
990 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
991 return !(data
->mChildWorkers
.IsEmpty() && data
->mTimeouts
.IsEmpty() &&
992 data
->mWorkerRefs
.IsEmpty());
995 // Internal logic to dispatch a runnable. This is separate from Dispatch()
996 // to allow runnables to be atomically dispatched in bulk.
997 nsresult
DispatchLockHeld(already_AddRefed
<WorkerRunnable
> aRunnable
,
998 nsIEventTarget
* aSyncLoopTarget
,
999 const MutexAutoLock
& aProofOfLock
);
1001 // This method dispatches a simple runnable that starts the shutdown procedure
1002 // after a self.close(). This method is called after a ClearMainEventQueue()
1003 // to be sure that the canceling runnable is the only one in the queue. We
1004 // need this async operation to be sure that all the current JS code is
1006 void DispatchCancelingRunnable();
1008 bool GetUseCounter(UseCounterWorker aUseCounter
) {
1009 MOZ_ASSERT(aUseCounter
> UseCounterWorker::Unknown
);
1010 AssertIsOnWorkerThread();
1011 return mUseCounters
[static_cast<size_t>(aUseCounter
)];
1014 void ReportUseCounters();
1017 friend class EventTarget
;
1018 friend class AutoSyncLoopHolder
;
1022 class MemoryReporter
;
1023 friend class MemoryReporter
;
1025 friend class mozilla::dom::WorkerThread
;
1028 mozilla::CondVar mCondVar
;
1030 WorkerPrivate
* mParent
;
1032 nsString mScriptURL
;
1034 // This is the worker name for shared workers and dedicated workers.
1035 nsString mWorkerName
;
1037 WorkerType mWorkerType
;
1039 // The worker is owned by its thread, which is represented here. This is set
1040 // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
1041 // traversed by the cycle collector if the busy count is zero.
1043 // There are 4 ways a worker can be terminated:
1044 // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
1045 // traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed
1046 // Worker webidl object. Doing this, CC will be able to detect a cycle and
1047 // Unlink is called. In Unlink, Worker calls Cancel().
1048 // 2. Worker::Cancel() is called - the shutdown procedure starts immediately.
1049 // 3. WorkerScope::Close() is called - Similar to point 2.
1050 // 4. xpcom-shutdown notification - We call Kill().
1051 RefPtr
<Worker
> mParentEventTargetRef
;
1052 RefPtr
<WorkerPrivate
> mSelfRef
;
1054 // The lifetime of these objects within LoadInfo is managed explicitly;
1055 // they do not need to be cycle collected.
1056 WorkerLoadInfo mLoadInfo
;
1057 LocationInfo mLocationInfo
;
1059 // Protected by mMutex.
1060 workerinternals::JSSettings mJSSettings
;
1062 WorkerDebugger
* mDebugger
;
1064 workerinternals::Queue
<WorkerControlRunnable
*, 4> mControlQueue
;
1065 workerinternals::Queue
<WorkerRunnable
*, 4> mDebuggerQueue
;
1067 // Touched on multiple threads, protected with mMutex.
1068 JSContext
* mJSContext
;
1069 RefPtr
<WorkerThread
> mThread
;
1070 PRThread
* mPRThread
;
1072 // Accessed from main thread
1073 RefPtr
<ThrottledEventQueue
> mMainThreadEventTargetForMessaging
;
1074 RefPtr
<ThrottledEventQueue
> mMainThreadEventTarget
;
1076 // Accessed from worker thread and destructing thread
1077 RefPtr
<WorkerEventTarget
> mWorkerControlEventTarget
;
1078 RefPtr
<WorkerEventTarget
> mWorkerHybridEventTarget
;
1080 // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread.
1081 // See WorkerDebuggeeRunnable for details.
1082 RefPtr
<ThrottledEventQueue
> mMainThreadDebuggeeEventTarget
;
1084 struct SyncLoopInfo
{
1085 explicit SyncLoopInfo(EventTarget
* aEventTarget
);
1087 RefPtr
<EventTarget
> mEventTarget
;
1095 // This is only modified on the worker thread, but in DEBUG builds
1096 // AssertValidSyncLoop function iterates it on other threads. Therefore
1097 // modifications are done with mMutex held *only* in DEBUG builds.
1098 nsTArray
<nsAutoPtr
<SyncLoopInfo
>> mSyncLoopStack
;
1100 nsCOMPtr
<nsITimer
> mCancelingTimer
;
1102 // fired on the main thread if the worker script fails to load
1103 nsCOMPtr
<nsIRunnable
> mLoadFailedRunnable
;
1105 RefPtr
<PerformanceStorage
> mPerformanceStorage
;
1107 RefPtr
<WorkerCSPEventListener
> mCSPEventListener
;
1109 // Protected by mMutex.
1110 nsTArray
<RefPtr
<WorkerRunnable
>> mPreStartRunnables
;
1112 // Only touched on the parent thread. This is set only if IsSharedWorker().
1113 RefPtr
<RemoteWorkerChild
> mRemoteWorkerController
;
1115 // This is set only if IsServiceWorker().
1116 ThreadSafeWeakPtr
<RemoteWorkerChild
> mRemoteWorkerControllerWeakRef
;
1118 JS::UniqueChars mDefaultLocale
; // nulled during worker JSContext init
1119 TimeStamp mKillTime
;
1120 WorkerStatus mParentStatus
;
1121 WorkerStatus mStatus
;
1123 // This is touched on parent thread only, but it can be read on a different
1124 // thread before crashing because hanging.
1125 Atomic
<uint64_t> mBusyCount
;
1127 Atomic
<bool> mLoadingWorkerScript
;
1129 TimeStamp mCreationTimeStamp
;
1130 DOMHighResTimeStamp mCreationTimeHighRes
;
1132 // Flags for use counters used directly by this worker.
1133 static_assert(sizeof(UseCounterWorker
) <= sizeof(size_t),
1134 "UseCounterWorker is too big");
1135 static_assert(UseCounterWorker::Count
>= static_cast<UseCounterWorker
>(0),
1136 "Should be non-negative value and safe to cast to unsigned");
1137 std::bitset
<static_cast<size_t>(UseCounterWorker::Count
)> mUseCounters
;
1138 bool mReportedUseCounters
;
1140 // This is created while creating the WorkerPrivate, so it's safe to be
1141 // touched on any thread.
1142 const nsID mAgentClusterId
;
1144 // Things touched on worker thread only.
1145 struct WorkerThreadAccessible
{
1146 explicit WorkerThreadAccessible(WorkerPrivate
* aParent
);
1148 RefPtr
<WorkerGlobalScope
> mScope
;
1149 RefPtr
<WorkerDebuggerGlobalScope
> mDebuggerScope
;
1150 nsTArray
<WorkerPrivate
*> mChildWorkers
;
1151 nsTObserverArray
<WorkerRef
*> mWorkerRefs
;
1152 nsTArray
<nsAutoPtr
<TimeoutInfo
>> mTimeouts
;
1154 nsCOMPtr
<nsITimer
> mTimer
;
1155 nsCOMPtr
<nsITimerCallback
> mTimerRunnable
;
1157 nsCOMPtr
<nsITimer
> mGCTimer
;
1159 RefPtr
<MemoryReporter
> mMemoryReporter
;
1161 UniquePtr
<ClientSource
> mClientSource
;
1163 // While running a nested event loop, whether a sync loop or a debugger
1164 // event loop we want to keep track of which global is running it, if any,
1165 // so runnables that run off that event loop can get at that information. In
1166 // practice this only matters for various worker debugger runnables running
1167 // against sandboxes, because all other runnables know which globals they
1168 // belong to already. We could also address this by threading the relevant
1169 // global through the chains of runnables involved, but we'd need to thread
1170 // it through some runnables that run on the main thread, and that would
1171 // require some care to make sure things get released on the correct thread,
1172 // which we'd rather avoid. This member is only accessed on the worker
1174 nsCOMPtr
<nsIGlobalObject
> mCurrentEventLoopGlobal
;
1176 uint32_t mNumWorkerRefsPreventingShutdownStart
;
1177 uint32_t mDebuggerEventLoopLevel
;
1179 uint32_t mErrorHandlerRecursionCount
;
1180 uint32_t mNextTimeoutId
;
1184 bool mRunningExpiredTimeouts
;
1185 bool mPeriodicGCTimerRunning
;
1186 bool mIdleGCTimerRunning
;
1189 ThreadBound
<WorkerThreadAccessible
> mWorkerThreadAccessible
;
1191 class MOZ_RAII AutoPushEventLoopGlobal
{
1193 AutoPushEventLoopGlobal(WorkerPrivate
* aWorkerPrivate
, JSContext
* aCx
);
1194 ~AutoPushEventLoopGlobal();
1197 WorkerPrivate
* mWorkerPrivate
;
1198 nsCOMPtr
<nsIGlobalObject
> mOldEventLoopGlobal
;
1200 friend class AutoPushEventLoopGlobal
;
1202 uint32_t mPostSyncLoopOperations
;
1204 // List of operations to do at the end of the last sync event loop.
1206 ePendingEventQueueClearing
= 0x01,
1207 eDispatchCancelingRunnable
= 0x02,
1210 bool mParentWindowPaused
;
1212 bool mCancelAllPendingRunnables
;
1213 bool mWorkerScriptExecutedSuccessfully
;
1214 bool mFetchHandlerWasAdded
;
1215 bool mMainThreadObjectsForgotten
;
1216 bool mIsChromeWorker
;
1219 // mIsSecureContext is set once in our constructor; after that it can be read
1220 // from various threads.
1222 // It's a bit unfortunate that we have to have an out-of-band boolean for
1223 // this, but we need access to this state from the parent thread, and we can't
1224 // use our global object's secure state there.
1225 const bool mIsSecureContext
;
1227 bool mDebuggerRegistered
;
1229 // During registration, this worker may be marked as not being ready to
1230 // execute debuggee runnables or content.
1232 // Protected by mMutex.
1233 bool mDebuggerReady
;
1234 nsTArray
<RefPtr
<WorkerRunnable
>> mDelayedDebuggeeRunnables
;
1236 // mIsInAutomation is true when we're running in test automation.
1237 // We expose some extra testing functions in that case.
1238 bool mIsInAutomation
;
1240 RefPtr
<mozilla::PerformanceCounter
> mPerformanceCounter
;
1244 // This is used to check if it's allowed to share the memory across the agent
1246 const nsILoadInfo::CrossOriginOpenerPolicy mAgentClusterOpenerPolicy
;
1249 class AutoSyncLoopHolder
{
1250 WorkerPrivate
* mWorkerPrivate
;
1251 nsCOMPtr
<nsIEventTarget
> mTarget
;
1255 // See CreateNewSyncLoop() for more information about the correct value to use
1257 AutoSyncLoopHolder(WorkerPrivate
* aWorkerPrivate
, WorkerStatus aFailStatus
)
1258 : mWorkerPrivate(aWorkerPrivate
),
1259 mTarget(aWorkerPrivate
->CreateNewSyncLoop(aFailStatus
)),
1260 mIndex(aWorkerPrivate
->mSyncLoopStack
.Length() - 1) {
1261 aWorkerPrivate
->AssertIsOnWorkerThread();
1264 ~AutoSyncLoopHolder() {
1265 if (mWorkerPrivate
&& mTarget
) {
1266 mWorkerPrivate
->AssertIsOnWorkerThread();
1267 mWorkerPrivate
->StopSyncLoop(mTarget
, false);
1268 mWorkerPrivate
->DestroySyncLoop(mIndex
);
1273 WorkerPrivate
* workerPrivate
= mWorkerPrivate
;
1274 mWorkerPrivate
= nullptr;
1276 workerPrivate
->AssertIsOnWorkerThread();
1278 return workerPrivate
->RunCurrentSyncLoop();
1281 nsIEventTarget
* GetEventTarget() const {
1282 // This can be null if CreateNewSyncLoop() fails.
1288 } // namespace mozilla
1290 #endif /* mozilla_dom_workers_workerprivate_h__ */