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__
10 #include "mozilla/dom/WorkerCommon.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/CondVar.h"
13 #include "mozilla/DOMEventTargetHelper.h"
14 #include "mozilla/RelativeTimeline.h"
15 #include "mozilla/StorageAccess.h"
16 #include "nsContentUtils.h"
17 #include "nsIContentSecurityPolicy.h"
18 #include "nsIEventTarget.h"
19 #include "nsTObserverArray.h"
21 #include "js/ContextOptions.h"
22 #include "mozilla/dom/Worker.h"
23 #include "mozilla/dom/WorkerHolder.h"
24 #include "mozilla/dom/WorkerLoadInfo.h"
25 #include "mozilla/dom/workerinternals/JSSettings.h"
26 #include "mozilla/dom/workerinternals/Queue.h"
27 #include "mozilla/PerformanceCounter.h"
28 #include "mozilla/ThreadBound.h"
30 class nsIThreadInternal
;
33 class ThrottledEventQueue
;
36 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs
38 enum WorkerType
{ WorkerTypeDedicated
, WorkerTypeShared
, WorkerTypeService
};
44 class MessagePortIdentifier
;
45 class PerformanceStorage
;
46 class RemoteWorkerChild
;
47 class WorkerControlRunnable
;
48 class WorkerCSPEventListener
;
50 class WorkerDebuggerGlobalScope
;
51 class WorkerErrorReport
;
52 class WorkerEventTarget
;
53 class WorkerGlobalScope
;
55 class WorkerDebuggeeRunnable
;
58 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex
59 // object. It exists to avoid changing a lot of code to use Mutex* instead of
62 typedef mozilla::Mutex Mutex
;
64 class RefCountedMutex final
: public Mutex
{
66 explicit RefCountedMutex(const char* aName
) : Mutex(aName
) {}
68 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex
)
74 RefPtr
<RefCountedMutex
> mMutex
;
77 explicit SharedMutex(const char* aName
)
78 : mMutex(new RefCountedMutex(aName
)) {}
80 SharedMutex(SharedMutex
& aOther
) : mMutex(aOther
.mMutex
) {}
82 operator Mutex
&() { return *mMutex
; }
84 operator const Mutex
&() const { return *mMutex
; }
86 void AssertCurrentThreadOwns() const { mMutex
->AssertCurrentThreadOwns(); }
89 class WorkerPrivate
: public RelativeTimeline
{
103 NS_INLINE_DECL_REFCOUNTING(WorkerPrivate
)
105 static already_AddRefed
<WorkerPrivate
> Constructor(
106 JSContext
* aCx
, const nsAString
& aScriptURL
, bool aIsChromeWorker
,
107 WorkerType aWorkerType
, const nsAString
& aWorkerName
,
108 const nsACString
& aServiceWorkerScope
, WorkerLoadInfo
* aLoadInfo
,
111 enum LoadGroupBehavior
{ InheritLoadGroup
, OverrideLoadGroup
};
113 static nsresult
GetLoadInfo(JSContext
* aCx
, nsPIDOMWindowInner
* aWindow
,
114 WorkerPrivate
* aParent
,
115 const nsAString
& aScriptURL
, bool aIsChromeWorker
,
116 LoadGroupBehavior aLoadGroupBehavior
,
117 WorkerType aWorkerType
,
118 WorkerLoadInfo
* aLoadInfo
);
120 void Traverse(nsCycleCollectionTraversalCallback
& aCb
);
122 void ClearSelfAndParentEventTargetRef() {
123 AssertIsOnParentThread();
124 MOZ_ASSERT(mSelfRef
);
125 mParentEventTargetRef
= nullptr;
129 // May be called on any thread...
132 // Called on the parent thread.
133 bool Notify(WorkerStatus aStatus
);
135 bool Cancel() { return Notify(Canceling
); }
139 // The passed principal must be the Worker principal in case of a
140 // ServiceWorker and the loading principal for any other type.
141 static void OverrideLoadInfoLoadGroup(WorkerLoadInfo
& aLoadInfo
,
142 nsIPrincipal
* aPrincipal
);
144 bool IsDebuggerRegistered() {
145 AssertIsOnMainThread();
147 // No need to lock here since this is only ever modified by the same thread.
148 return mDebuggerRegistered
;
151 void SetIsDebuggerRegistered(bool aDebuggerRegistered
) {
152 AssertIsOnMainThread();
154 MutexAutoLock
lock(mMutex
);
156 MOZ_ASSERT(mDebuggerRegistered
!= aDebuggerRegistered
);
157 mDebuggerRegistered
= aDebuggerRegistered
;
162 void WaitForIsDebuggerRegistered(bool aDebuggerRegistered
) {
163 AssertIsOnParentThread();
165 MOZ_ASSERT(!NS_IsMainThread());
167 MutexAutoLock
lock(mMutex
);
169 while (mDebuggerRegistered
!= aDebuggerRegistered
) {
174 nsresult
SetIsDebuggerReady(bool aReady
);
176 WorkerDebugger
* Debugger() const {
177 AssertIsOnMainThread();
179 MOZ_ASSERT(mDebugger
);
183 void SetDebugger(WorkerDebugger
* aDebugger
) {
184 AssertIsOnMainThread();
186 MOZ_ASSERT(mDebugger
!= aDebugger
);
187 mDebugger
= aDebugger
;
190 JS::UniqueChars
AdoptDefaultLocale() {
191 MOZ_ASSERT(mDefaultLocale
,
192 "the default locale must have been successfully set for anyone "
193 "to be trying to adopt it");
194 return std::move(mDefaultLocale
);
198 void DoRunLoop(JSContext
* aCx
);
200 bool InterruptCallback(JSContext
* aCx
);
202 bool IsOnCurrentThread();
204 void CloseInternal();
206 bool FreezeInternal();
210 void PropagateFirstPartyStorageAccessGrantedInternal();
212 void TraverseTimeouts(nsCycleCollectionTraversalCallback
& aCallback
);
214 void UnlinkTimeouts();
216 bool ModifyBusyCountFromWorker(bool aIncrease
);
218 bool AddChildWorker(WorkerPrivate
* aChildWorker
);
220 void RemoveChildWorker(WorkerPrivate
* aChildWorker
);
222 void PostMessageToParent(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
223 const Sequence
<JSObject
*>& aTransferable
,
226 void PostMessageToParentMessagePort(JSContext
* aCx
,
227 JS::Handle
<JS::Value
> aMessage
,
228 const Sequence
<JSObject
*>& aTransferable
,
231 MOZ_CAN_RUN_SCRIPT
void EnterDebuggerEventLoop();
233 void LeaveDebuggerEventLoop();
235 void PostMessageToDebugger(const nsAString
& aMessage
);
237 void SetDebuggerImmediate(Function
& aHandler
, ErrorResult
& aRv
);
239 void ReportErrorToDebugger(const nsAString
& aFilename
, uint32_t aLineno
,
240 const nsAString
& aMessage
);
242 bool NotifyInternal(WorkerStatus aStatus
);
244 void ReportError(JSContext
* aCx
, JS::ConstUTF8CharsZ aToStringResult
,
245 JSErrorReport
* aReport
);
247 static void ReportErrorToConsole(const char* aMessage
);
249 static void ReportErrorToConsole(const char* aMessage
,
250 const nsTArray
<nsString
>& aParams
);
252 int32_t SetTimeout(JSContext
* aCx
, nsIScriptTimeoutHandler
* aHandler
,
253 int32_t aTimeout
, bool aIsInterval
, ErrorResult
& aRv
);
255 void ClearTimeout(int32_t aId
);
257 MOZ_CAN_RUN_SCRIPT
bool RunExpiredTimeouts(JSContext
* aCx
);
259 bool RescheduleTimeoutTimer(JSContext
* aCx
);
261 void UpdateContextOptionsInternal(JSContext
* aCx
,
262 const JS::ContextOptions
& aContextOptions
);
264 void UpdateLanguagesInternal(const nsTArray
<nsString
>& aLanguages
);
266 void UpdateJSWorkerMemoryParameterInternal(JSContext
* aCx
, JSGCParamKey key
,
269 enum WorkerRanOrNot
{ WorkerNeverRan
= 0, WorkerRan
};
271 void ScheduleDeletion(WorkerRanOrNot aRanOrNot
);
273 bool CollectRuntimeStats(JS::RuntimeStats
* aRtStats
, bool aAnonymize
);
276 void UpdateGCZealInternal(JSContext
* aCx
, uint8_t aGCZeal
,
277 uint32_t aFrequency
);
280 void GarbageCollectInternal(JSContext
* aCx
, bool aShrinking
,
281 bool aCollectChildren
);
283 void CycleCollectInternal(bool aCollectChildren
);
285 void OfflineStatusChangeEventInternal(bool aIsOffline
);
287 void MemoryPressureInternal();
289 void SetFetchHandlerWasAdded() {
290 MOZ_ASSERT(IsServiceWorker());
291 AssertIsOnWorkerThread();
292 mFetchHandlerWasAdded
= true;
295 bool FetchHandlerWasAdded() const {
296 MOZ_ASSERT(IsServiceWorker());
297 AssertIsOnWorkerThread();
298 return mFetchHandlerWasAdded
;
301 JSContext
* GetJSContext() const {
302 AssertIsOnWorkerThread();
306 WorkerGlobalScope
* GlobalScope() const {
307 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
311 WorkerDebuggerGlobalScope
* DebuggerGlobalScope() const {
312 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
313 return data
->mDebuggerScope
;
316 nsICSPEventListener
* CSPEventListener() const;
318 void SetThread(WorkerThread
* aThread
);
320 void SetWorkerPrivateInWorkerThread(WorkerThread
* aThread
);
322 void ResetWorkerPrivateInWorkerThread();
324 bool IsOnWorkerThread() const;
326 void AssertIsOnWorkerThread() const
335 void BeginCTypesCall();
338 void EndCTypesCall();
340 void BeginCTypesCallback() {
341 // If a callback is beginning then we need to do the exact same thing as
342 // when a ctypes call ends.
346 void EndCTypesCallback() {
347 // If a callback is ending then we need to do the exact same thing as
348 // when a ctypes call begins.
352 bool ConnectMessagePort(JSContext
* aCx
,
353 const MessagePortIdentifier
& aIdentifier
);
355 WorkerGlobalScope
* GetOrCreateGlobalScope(JSContext
* aCx
);
357 WorkerDebuggerGlobalScope
* CreateDebuggerGlobalScope(JSContext
* aCx
);
359 bool RegisterBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
361 bool RegisterDebuggerBindings(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
363 bool OnLine() const {
364 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
365 return data
->mOnLine
;
368 void StopSyncLoop(nsIEventTarget
* aSyncLoopTarget
, bool aResult
);
370 bool AllPendingRunnablesShouldBeCanceled() const {
371 return mCancelAllPendingRunnables
;
374 void ClearMainEventQueue(WorkerRanOrNot aRanOrNot
);
376 void ClearDebuggerEventQueue();
378 void OnProcessNextEvent();
380 void AfterProcessNextEvent();
382 void AssertValidSyncLoop(nsIEventTarget
* aSyncLoopTarget
)
390 void SetWorkerScriptExecutedSuccessfully() {
391 AssertIsOnWorkerThread();
392 // Should only be called once!
393 MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully
);
394 mWorkerScriptExecutedSuccessfully
= true;
397 // Only valid after CompileScriptRunnable has finished running!
398 bool WorkerScriptExecutedSuccessfully() const {
399 AssertIsOnWorkerThread();
400 return mWorkerScriptExecutedSuccessfully
;
403 // Get the event target to use when dispatching to the main thread
404 // from this Worker thread. This may be the main thread itself or
405 // a ThrottledEventQueue to the main thread.
406 nsIEventTarget
* MainThreadEventTargetForMessaging();
408 nsresult
DispatchToMainThreadForMessaging(
409 nsIRunnable
* aRunnable
, uint32_t aFlags
= NS_DISPATCH_NORMAL
);
411 nsresult
DispatchToMainThreadForMessaging(
412 already_AddRefed
<nsIRunnable
> aRunnable
,
413 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
415 nsIEventTarget
* MainThreadEventTarget();
417 nsresult
DispatchToMainThread(nsIRunnable
* aRunnable
,
418 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
420 nsresult
DispatchToMainThread(already_AddRefed
<nsIRunnable
> aRunnable
,
421 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
423 nsresult
DispatchDebuggeeToMainThread(
424 already_AddRefed
<WorkerDebuggeeRunnable
> aRunnable
,
425 uint32_t aFlags
= NS_DISPATCH_NORMAL
);
427 // Get an event target that will dispatch runnables as control runnables on
428 // the worker thread. Implement nsICancelableRunnable if you wish to take
429 // action on cancelation.
430 nsISerialEventTarget
* ControlEventTarget();
432 // Get an event target that will attempt to dispatch a normal WorkerRunnable,
433 // but if that fails will then fall back to a control runnable.
434 nsISerialEventTarget
* HybridEventTarget();
436 void DumpCrashInformation(nsACString
& aString
);
438 bool EnsureClientSource();
440 bool EnsureCSPEventListener();
442 void EnsurePerformanceStorage();
444 void EnsurePerformanceCounter();
446 Maybe
<ClientInfo
> GetClientInfo() const;
448 const ClientState
GetClientState() const;
450 const Maybe
<ServiceWorkerDescriptor
> GetController();
452 void Control(const ServiceWorkerDescriptor
& aServiceWorker
);
454 void ExecutionReady();
456 PerformanceStorage
* GetPerformanceStorage();
458 PerformanceCounter
* GetPerformanceCounter();
460 bool IsAcceptingEvents() {
461 AssertIsOnParentThread();
463 MutexAutoLock
lock(mMutex
);
464 return mParentStatus
< Canceling
;
467 WorkerStatus
ParentStatusProtected() {
468 AssertIsOnParentThread();
469 MutexAutoLock
lock(mMutex
);
470 return mParentStatus
;
473 WorkerStatus
ParentStatus() const {
474 mMutex
.AssertCurrentThreadOwns();
475 return mParentStatus
;
478 Worker
* ParentEventTargetRef() const {
479 MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef
);
480 return mParentEventTargetRef
;
483 void SetParentEventTargetRef(Worker
* aParentEventTargetRef
) {
484 MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef
);
485 MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef
);
486 mParentEventTargetRef
= aParentEventTargetRef
;
489 bool ModifyBusyCount(bool aIncrease
);
491 // This method is used by RuntimeService to know what is going wrong the
493 uint32_t BusyCount() { return mBusyCount
; }
495 // Check whether this worker is a secure context. For use from the parent
496 // thread only; the canonical "is secure context" boolean is stored on the
497 // compartment of the worker global. The only reason we don't
498 // AssertIsOnParentThread() here is so we can assert that this value matches
499 // the one on the compartment, which has to be done from the worker thread.
500 bool IsSecureContext() const { return mIsSecureContext
; }
502 // Check whether we're running in automation.
503 bool IsInAutomation() const { return mIsInAutomation
; }
505 TimeStamp
CreationTimeStamp() const { return mCreationTimeStamp
; }
507 DOMHighResTimeStamp
CreationTime() const { return mCreationTimeHighRes
; }
509 DOMHighResTimeStamp
TimeStampToDOMHighRes(const TimeStamp
& aTimeStamp
) const {
510 MOZ_ASSERT(!aTimeStamp
.IsNull());
511 TimeDuration duration
= aTimeStamp
- mCreationTimeStamp
;
512 return duration
.ToMilliseconds();
515 LocationInfo
& GetLocationInfo() { return mLocationInfo
; }
517 void CopyJSSettings(workerinternals::JSSettings
& aSettings
) {
518 mozilla::MutexAutoLock
lock(mMutex
);
519 aSettings
= mJSSettings
;
522 void CopyJSRealmOptions(JS::RealmOptions
& aOptions
) {
523 mozilla::MutexAutoLock
lock(mMutex
);
524 aOptions
= IsChromeWorker() ? mJSSettings
.chrome
.realmOptions
525 : mJSSettings
.content
.realmOptions
;
528 // The ability to be a chrome worker is orthogonal to the type of
529 // worker [Dedicated|Shared|Service].
530 bool IsChromeWorker() const { return mIsChromeWorker
; }
532 WorkerPrivate
* GetParent() const { return mParent
; }
534 bool IsFrozen() const {
535 AssertIsOnParentThread();
536 return mParentFrozen
;
539 bool IsParentWindowPaused() const {
540 AssertIsOnParentThread();
541 return mParentWindowPaused
;
544 // When we debug a worker, we want to disconnect the window and the worker
545 // communication. This happens calling this method.
546 // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.
547 void ParentWindowPaused();
549 void ParentWindowResumed();
551 const nsString
& ScriptURL() const { return mScriptURL
; }
553 const nsString
& WorkerName() const { return mWorkerName
; }
555 WorkerType
Type() const { return mWorkerType
; }
557 bool IsDedicatedWorker() const { return mWorkerType
== WorkerTypeDedicated
; }
559 bool IsSharedWorker() const { return mWorkerType
== WorkerTypeShared
; }
561 bool IsServiceWorker() const { return mWorkerType
== WorkerTypeService
; }
563 nsContentPolicyType
ContentPolicyType() const {
564 return ContentPolicyType(mWorkerType
);
567 static nsContentPolicyType
ContentPolicyType(WorkerType aWorkerType
) {
568 switch (aWorkerType
) {
569 case WorkerTypeDedicated
:
570 return nsIContentPolicy::TYPE_INTERNAL_WORKER
;
571 case WorkerTypeShared
:
572 return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
;
573 case WorkerTypeService
:
574 return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER
;
576 MOZ_ASSERT_UNREACHABLE("Invalid worker type");
577 return nsIContentPolicy::TYPE_INVALID
;
581 nsIScriptContext
* GetScriptContext() const {
582 AssertIsOnMainThread();
583 return mLoadInfo
.mScriptContext
;
586 const nsCString
& Domain() const { return mLoadInfo
.mDomain
; }
588 bool IsFromWindow() const { return mLoadInfo
.mFromWindow
; }
590 nsLoadFlags
GetLoadFlags() const { return mLoadInfo
.mLoadFlags
; }
592 uint64_t WindowID() const { return mLoadInfo
.mWindowID
; }
594 uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); }
596 const nsCString
& ServiceWorkerScope() const {
597 return GetServiceWorkerDescriptor().Scope();
600 nsIURI
* GetBaseURI() const {
601 AssertIsOnMainThread();
602 return mLoadInfo
.mBaseURI
;
605 void SetBaseURI(nsIURI
* aBaseURI
);
607 nsIURI
* GetResolvedScriptURI() const {
608 AssertIsOnMainThread();
609 return mLoadInfo
.mResolvedScriptURI
;
612 const nsString
& ServiceWorkerCacheName() const {
613 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
614 AssertIsOnMainThread();
615 return mLoadInfo
.mServiceWorkerCacheName
;
618 const ServiceWorkerDescriptor
& GetServiceWorkerDescriptor() const {
619 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
620 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
621 return mLoadInfo
.mServiceWorkerDescriptor
.ref();
624 const ServiceWorkerRegistrationDescriptor
&
625 GetServiceWorkerRegistrationDescriptor() const {
626 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
627 MOZ_DIAGNOSTIC_ASSERT(
628 mLoadInfo
.mServiceWorkerRegistrationDescriptor
.isSome());
629 return mLoadInfo
.mServiceWorkerRegistrationDescriptor
.ref();
632 void UpdateServiceWorkerState(ServiceWorkerState aState
) {
633 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
634 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo
.mServiceWorkerDescriptor
.isSome());
635 return mLoadInfo
.mServiceWorkerDescriptor
.ref().SetState(aState
);
638 const Maybe
<ServiceWorkerDescriptor
>& GetParentController() const {
639 return mLoadInfo
.mParentController
;
642 const ChannelInfo
& GetChannelInfo() const { return mLoadInfo
.mChannelInfo
; }
644 void SetChannelInfo(const ChannelInfo
& aChannelInfo
) {
645 AssertIsOnMainThread();
646 MOZ_ASSERT(!mLoadInfo
.mChannelInfo
.IsInitialized());
647 MOZ_ASSERT(aChannelInfo
.IsInitialized());
648 mLoadInfo
.mChannelInfo
= aChannelInfo
;
651 void InitChannelInfo(nsIChannel
* aChannel
) {
652 mLoadInfo
.mChannelInfo
.InitFromChannel(aChannel
);
655 void InitChannelInfo(const ChannelInfo
& aChannelInfo
) {
656 mLoadInfo
.mChannelInfo
= aChannelInfo
;
659 nsIPrincipal
* GetPrincipal() const {
660 AssertIsOnMainThread();
661 return mLoadInfo
.mPrincipal
;
664 nsIPrincipal
* GetEffectiveStoragePrincipal() const {
665 AssertIsOnMainThread();
666 return mLoadInfo
.mStoragePrincipal
;
669 nsIPrincipal
* GetLoadingPrincipal() const {
670 AssertIsOnMainThread();
671 return mLoadInfo
.mLoadingPrincipal
;
674 const nsAString
& Origin() const { return mLoadInfo
.mOrigin
; }
676 nsILoadGroup
* GetLoadGroup() const {
677 AssertIsOnMainThread();
678 return mLoadInfo
.mLoadGroup
;
681 bool UsesSystemPrincipal() const { return mLoadInfo
.mPrincipalIsSystem
; }
683 const mozilla::ipc::PrincipalInfo
& GetPrincipalInfo() const {
684 return *mLoadInfo
.mPrincipalInfo
;
687 const mozilla::ipc::PrincipalInfo
& GetEffectiveStoragePrincipalInfo() const {
688 return *mLoadInfo
.mStoragePrincipalInfo
;
691 already_AddRefed
<nsIChannel
> ForgetWorkerChannel() {
692 AssertIsOnMainThread();
693 return mLoadInfo
.mChannel
.forget();
696 nsPIDOMWindowInner
* GetWindow() {
697 AssertIsOnMainThread();
698 return mLoadInfo
.mWindow
;
701 nsIContentSecurityPolicy
* GetCSP() const {
702 AssertIsOnMainThread();
703 return mLoadInfo
.mCSP
;
706 void SetCSP(nsIContentSecurityPolicy
* aCSP
);
708 nsresult
SetCSPFromHeaderValues(const nsACString
& aCSPHeaderValue
,
709 const nsACString
& aCSPReportOnlyHeaderValue
);
711 void StoreCSPOnClient();
713 const mozilla::ipc::CSPInfo
& GetCSPInfo() const {
714 return *mLoadInfo
.mCSPInfo
;
717 void SetReferrerPolicyFromHeaderValue(
718 const nsACString
& aReferrerPolicyHeaderValue
);
720 net::ReferrerPolicy
GetReferrerPolicy() const {
721 return mLoadInfo
.mReferrerPolicy
;
724 void SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy
) {
725 mLoadInfo
.mReferrerPolicy
= aReferrerPolicy
;
728 bool IsEvalAllowed() const { return mLoadInfo
.mEvalAllowed
; }
730 void SetEvalAllowed(bool aEvalAllowed
) {
731 mLoadInfo
.mEvalAllowed
= aEvalAllowed
;
734 bool GetReportCSPViolations() const { return mLoadInfo
.mReportCSPViolations
; }
736 void SetReportCSPViolations(bool aReport
) {
737 mLoadInfo
.mReportCSPViolations
= aReport
;
740 bool XHRParamsAllowed() const { return mLoadInfo
.mXHRParamsAllowed
; }
742 void SetXHRParamsAllowed(bool aAllowed
) {
743 mLoadInfo
.mXHRParamsAllowed
= aAllowed
;
746 mozilla::StorageAccess
StorageAccess() const {
747 AssertIsOnWorkerThread();
748 if (mLoadInfo
.mFirstPartyStorageAccessGranted
) {
749 return mozilla::StorageAccess::eAllow
;
752 return mLoadInfo
.mStorageAccess
;
755 nsICookieSettings
* CookieSettings() const {
757 MOZ_ASSERT(mLoadInfo
.mCookieSettings
);
758 return mLoadInfo
.mCookieSettings
;
761 const OriginAttributes
& GetOriginAttributes() const {
762 return mLoadInfo
.mOriginAttributes
;
765 // Determine if the SW testing per-window flag is set by devtools
766 bool ServiceWorkersTestingInWindow() const {
767 return mLoadInfo
.mServiceWorkersTestingInWindow
;
770 bool IsWatchedByDevtools() const { return mLoadInfo
.mWatchedByDevtools
; }
772 // Determine if the worker is currently loading its top level script.
773 bool IsLoadingWorkerScript() const { return mLoadingWorkerScript
; }
775 // Called by ScriptLoader to track when this worker is loading its
777 void SetLoadingWorkerScript(bool aLoadingWorkerScript
) {
779 mLoadingWorkerScript
= aLoadingWorkerScript
;
782 RemoteWorkerChild
* GetRemoteWorkerController();
784 void SetRemoteWorkerController(RemoteWorkerChild
* aController
);
786 // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
787 // as these are only used for globals going in and out of the bfcache.
788 bool Freeze(nsPIDOMWindowInner
* aWindow
);
790 bool Thaw(nsPIDOMWindowInner
* aWindow
);
792 void PropagateFirstPartyStorageAccessGranted();
794 void EnableDebugger();
796 void DisableDebugger();
798 already_AddRefed
<WorkerRunnable
> MaybeWrapAsWorkerRunnable(
799 already_AddRefed
<nsIRunnable
> aRunnable
);
801 bool ProxyReleaseMainThreadObjects();
803 void GarbageCollect(bool aShrinking
);
805 void CycleCollect(bool aDummy
);
807 nsresult
SetPrincipalsAndCSPOnMainThread(nsIPrincipal
* aPrincipal
,
808 nsIPrincipal
* aStoragePrincipal
,
809 nsILoadGroup
* aLoadGroup
,
810 nsIContentSecurityPolicy
* aCsp
);
812 nsresult
SetPrincipalsAndCSPFromChannel(nsIChannel
* aChannel
);
814 bool FinalChannelPrincipalIsValid(nsIChannel
* aChannel
);
816 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
817 bool PrincipalURIMatchesScriptURL();
820 void UpdateOverridenLoadGroup(nsILoadGroup
* aBaseLoadGroup
);
822 void WorkerScriptLoaded();
824 Document
* GetDocument() const;
826 void MemoryPressure(bool aDummy
);
828 void UpdateContextOptions(const JS::ContextOptions
& aContextOptions
);
830 void UpdateLanguages(const nsTArray
<nsString
>& aLanguages
);
832 void UpdateJSWorkerMemoryParameter(JSGCParamKey key
, uint32_t value
);
835 void UpdateGCZeal(uint8_t aGCZeal
, uint32_t aFrequency
);
838 void OfflineStatusChangeEvent(bool aIsOffline
);
840 nsresult
Dispatch(already_AddRefed
<WorkerRunnable
> aRunnable
,
841 nsIEventTarget
* aSyncLoopTarget
= nullptr);
843 nsresult
DispatchControlRunnable(
844 already_AddRefed
<WorkerControlRunnable
> aWorkerControlRunnable
);
846 nsresult
DispatchDebuggerRunnable(
847 already_AddRefed
<WorkerRunnable
> aDebuggerRunnable
);
850 void AssertIsOnParentThread() const;
852 void AssertInnerWindowIsCorrect() const;
854 void AssertIsOnParentThread() const {}
856 void AssertInnerWindowIsCorrect() const {}
859 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
860 bool PrincipalIsValid() const;
863 void StartCancelingTimer();
868 WorkerPrivate(WorkerPrivate
* aParent
, const nsAString
& aScriptURL
,
869 bool aIsChromeWorker
, WorkerType aWorkerType
,
870 const nsAString
& aWorkerName
,
871 const nsACString
& aServiceWorkerScope
,
872 WorkerLoadInfo
& aLoadInfo
);
876 bool MayContinueRunning() {
877 AssertIsOnWorkerThread();
881 MutexAutoLock
lock(mMutex
);
885 if (status
< Canceling
) {
892 void CancelAllTimeouts();
894 enum class ProcessAllControlRunnablesResult
{
895 // We did not process anything.
897 // We did process something, states may have changed, but we can keep
900 // We did process something, and should not continue executing script.
904 ProcessAllControlRunnablesResult
ProcessAllControlRunnables() {
905 MutexAutoLock
lock(mMutex
);
906 return ProcessAllControlRunnablesLocked();
909 ProcessAllControlRunnablesResult
ProcessAllControlRunnablesLocked();
911 void EnableMemoryReporter();
913 void DisableMemoryReporter();
915 void WaitForWorkerEvents();
917 // If the worker shutdown status is equal or greater then aFailStatus, this
918 // operation will fail and nullptr will be returned. See WorkerHolder.h for
919 // more information about the correct value to use.
920 already_AddRefed
<nsIEventTarget
> CreateNewSyncLoop(WorkerStatus aFailStatus
);
922 bool RunCurrentSyncLoop();
924 bool DestroySyncLoop(uint32_t aLoopIndex
);
926 void InitializeGCTimers();
928 enum GCTimerMode
{ PeriodicTimer
= 0, IdleTimer
, NoTimer
};
930 void SetGCTimerMode(GCTimerMode aMode
);
932 void ShutdownGCTimers();
934 bool AddHolder(WorkerHolder
* aHolder
, WorkerStatus aFailStatus
);
936 void RemoveHolder(WorkerHolder
* aHolder
);
938 void NotifyHolders(WorkerStatus aStatus
);
940 bool HasActiveHolders() {
941 MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible
, data
);
942 return !(data
->mChildWorkers
.IsEmpty() && data
->mTimeouts
.IsEmpty() &&
943 data
->mHolders
.IsEmpty());
946 // Internal logic to dispatch a runnable. This is separate from Dispatch()
947 // to allow runnables to be atomically dispatched in bulk.
948 nsresult
DispatchLockHeld(already_AddRefed
<WorkerRunnable
> aRunnable
,
949 nsIEventTarget
* aSyncLoopTarget
,
950 const MutexAutoLock
& aProofOfLock
);
952 // This method dispatches a simple runnable that starts the shutdown procedure
953 // after a self.close(). This method is called after a ClearMainEventQueue()
954 // to be sure that the canceling runnable is the only one in the queue. We
955 // need this async operation to be sure that all the current JS code is
957 void DispatchCancelingRunnable();
960 friend class EventTarget
;
961 friend class mozilla::dom::WorkerHolder
;
962 friend class AutoSyncLoopHolder
;
966 class MemoryReporter
;
967 friend class MemoryReporter
;
969 friend class mozilla::dom::WorkerThread
;
972 mozilla::CondVar mCondVar
;
974 WorkerPrivate
* mParent
;
978 // This is the worker name for shared workers and dedicated workers.
979 nsString mWorkerName
;
981 WorkerType mWorkerType
;
983 // The worker is owned by its thread, which is represented here. This is set
984 // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
985 // traversed by the cycle collector if the busy count is zero.
987 // There are 4 ways a worker can be terminated:
988 // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
989 // traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed
990 // Worker webidl object. Doing this, CC will be able to detect a cycle and
991 // Unlink is called. In Unlink, Worker calls Cancel().
992 // 2. Worker::Cancel() is called - the shutdown procedure starts immediately.
993 // 3. WorkerScope::Close() is called - Similar to point 2.
994 // 4. xpcom-shutdown notification - We call Kill().
995 RefPtr
<Worker
> mParentEventTargetRef
;
996 RefPtr
<WorkerPrivate
> mSelfRef
;
998 // The lifetime of these objects within LoadInfo is managed explicitly;
999 // they do not need to be cycle collected.
1000 WorkerLoadInfo mLoadInfo
;
1001 LocationInfo mLocationInfo
;
1003 // Protected by mMutex.
1004 workerinternals::JSSettings mJSSettings
;
1006 WorkerDebugger
* mDebugger
;
1008 workerinternals::Queue
<WorkerControlRunnable
*, 4> mControlQueue
;
1009 workerinternals::Queue
<WorkerRunnable
*, 4> mDebuggerQueue
;
1011 // Touched on multiple threads, protected with mMutex.
1012 JSContext
* mJSContext
;
1013 RefPtr
<WorkerThread
> mThread
;
1014 PRThread
* mPRThread
;
1016 // Accessed from main thread
1017 RefPtr
<ThrottledEventQueue
> mMainThreadEventTargetForMessaging
;
1018 RefPtr
<ThrottledEventQueue
> mMainThreadEventTarget
;
1020 // Accessed from worker thread and destructing thread
1021 RefPtr
<WorkerEventTarget
> mWorkerControlEventTarget
;
1022 RefPtr
<WorkerEventTarget
> mWorkerHybridEventTarget
;
1024 // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread.
1025 // See WorkerDebuggeeRunnable for details.
1026 RefPtr
<ThrottledEventQueue
> mMainThreadDebuggeeEventTarget
;
1028 struct SyncLoopInfo
{
1029 explicit SyncLoopInfo(EventTarget
* aEventTarget
);
1031 RefPtr
<EventTarget
> mEventTarget
;
1039 // This is only modified on the worker thread, but in DEBUG builds
1040 // AssertValidSyncLoop function iterates it on other threads. Therefore
1041 // modifications are done with mMutex held *only* in DEBUG builds.
1042 nsTArray
<nsAutoPtr
<SyncLoopInfo
>> mSyncLoopStack
;
1044 nsCOMPtr
<nsITimer
> mCancelingTimer
;
1046 // fired on the main thread if the worker script fails to load
1047 nsCOMPtr
<nsIRunnable
> mLoadFailedRunnable
;
1049 RefPtr
<PerformanceStorage
> mPerformanceStorage
;
1051 RefPtr
<WorkerCSPEventListener
> mCSPEventListener
;
1053 // Protected by mMutex.
1054 nsTArray
<RefPtr
<WorkerRunnable
>> mPreStartRunnables
;
1056 // Only touched on the parent thread. This is set only if IsSharedWorker().
1057 RefPtr
<RemoteWorkerChild
> mRemoteWorkerController
;
1059 JS::UniqueChars mDefaultLocale
; // nulled during worker JSContext init
1060 TimeStamp mKillTime
;
1061 WorkerStatus mParentStatus
;
1062 WorkerStatus mStatus
;
1064 // This is touched on parent thread only, but it can be read on a different
1065 // thread before crashing because hanging.
1066 Atomic
<uint64_t> mBusyCount
;
1068 Atomic
<bool> mLoadingWorkerScript
;
1070 TimeStamp mCreationTimeStamp
;
1071 DOMHighResTimeStamp mCreationTimeHighRes
;
1073 // Things touched on worker thread only.
1074 struct WorkerThreadAccessible
{
1075 explicit WorkerThreadAccessible(WorkerPrivate
* aParent
);
1077 RefPtr
<WorkerGlobalScope
> mScope
;
1078 RefPtr
<WorkerDebuggerGlobalScope
> mDebuggerScope
;
1079 nsTArray
<WorkerPrivate
*> mChildWorkers
;
1080 nsTObserverArray
<WorkerHolder
*> mHolders
;
1081 nsTArray
<nsAutoPtr
<TimeoutInfo
>> mTimeouts
;
1083 nsCOMPtr
<nsITimer
> mTimer
;
1084 nsCOMPtr
<nsITimerCallback
> mTimerRunnable
;
1086 nsCOMPtr
<nsITimer
> mGCTimer
;
1088 RefPtr
<MemoryReporter
> mMemoryReporter
;
1090 UniquePtr
<ClientSource
> mClientSource
;
1092 uint32_t mNumHoldersPreventingShutdownStart
;
1093 uint32_t mDebuggerEventLoopLevel
;
1095 uint32_t mErrorHandlerRecursionCount
;
1096 uint32_t mNextTimeoutId
;
1100 bool mRunningExpiredTimeouts
;
1101 bool mPeriodicGCTimerRunning
;
1102 bool mIdleGCTimerRunning
;
1105 ThreadBound
<WorkerThreadAccessible
> mWorkerThreadAccessible
;
1107 uint32_t mPostSyncLoopOperations
;
1109 // List of operations to do at the end of the last sync event loop.
1111 ePendingEventQueueClearing
= 0x01,
1112 eDispatchCancelingRunnable
= 0x02,
1115 bool mParentWindowPaused
;
1117 bool mCancelAllPendingRunnables
;
1118 bool mWorkerScriptExecutedSuccessfully
;
1119 bool mFetchHandlerWasAdded
;
1120 bool mMainThreadObjectsForgotten
;
1121 bool mIsChromeWorker
;
1124 // mIsSecureContext is set once in our constructor; after that it can be read
1125 // from various threads.
1127 // It's a bit unfortunate that we have to have an out-of-band boolean for
1128 // this, but we need access to this state from the parent thread, and we can't
1129 // use our global object's secure state there.
1130 const bool mIsSecureContext
;
1132 bool mDebuggerRegistered
;
1134 // During registration, this worker may be marked as not being ready to
1135 // execute debuggee runnables or content.
1137 // Protected by mMutex.
1138 bool mDebuggerReady
;
1139 nsTArray
<RefPtr
<WorkerRunnable
>> mDelayedDebuggeeRunnables
;
1141 // mIsInAutomation is true when we're running in test automation.
1142 // We expose some extra testing functions in that case.
1143 bool mIsInAutomation
;
1145 RefPtr
<mozilla::PerformanceCounter
> mPerformanceCounter
;
1150 class AutoSyncLoopHolder
{
1151 WorkerPrivate
* mWorkerPrivate
;
1152 nsCOMPtr
<nsIEventTarget
> mTarget
;
1156 // See CreateNewSyncLoop() for more information about the correct value to use
1158 AutoSyncLoopHolder(WorkerPrivate
* aWorkerPrivate
, WorkerStatus aFailStatus
)
1159 : mWorkerPrivate(aWorkerPrivate
),
1160 mTarget(aWorkerPrivate
->CreateNewSyncLoop(aFailStatus
)),
1161 mIndex(aWorkerPrivate
->mSyncLoopStack
.Length() - 1) {
1162 aWorkerPrivate
->AssertIsOnWorkerThread();
1165 ~AutoSyncLoopHolder() {
1166 if (mWorkerPrivate
&& mTarget
) {
1167 mWorkerPrivate
->AssertIsOnWorkerThread();
1168 mWorkerPrivate
->StopSyncLoop(mTarget
, false);
1169 mWorkerPrivate
->DestroySyncLoop(mIndex
);
1174 WorkerPrivate
* workerPrivate
= mWorkerPrivate
;
1175 mWorkerPrivate
= nullptr;
1177 workerPrivate
->AssertIsOnWorkerThread();
1179 return workerPrivate
->RunCurrentSyncLoop();
1182 nsIEventTarget
* GetEventTarget() const {
1183 // This can be null if CreateNewSyncLoop() fails.
1189 } // namespace mozilla
1191 #endif /* mozilla_dom_workers_workerprivate_h__ */