Backed out 6 changesets (bug 1835907) for causing multiple failures. CLOSED TREE
[gecko.git] / dom / workers / WorkerPrivate.h
blobe78423f757d81bebf6a82ad261348f15af30f063
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 <bitset>
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;
52 namespace JS {
53 struct RuntimeStats;
56 namespace mozilla {
57 class ThrottledEventQueue;
58 namespace dom {
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 };
67 class ClientInfo;
68 class ClientSource;
69 class Function;
70 class JSExecutionManager;
71 class MessagePort;
72 class UniqueMessagePortId;
73 class PerformanceStorage;
74 class TimeoutHandler;
75 class WorkerControlRunnable;
76 class WorkerCSPEventListener;
77 class WorkerDebugger;
78 class WorkerDebuggerGlobalScope;
79 class WorkerErrorReport;
80 class WorkerEventTarget;
81 class WorkerGlobalScope;
82 class WorkerRef;
83 class WorkerRunnable;
84 class WorkerDebuggeeRunnable;
85 class WorkerThread;
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
89 // Mutex&.
90 class MOZ_CAPABILITY("mutex") SharedMutex {
91 using Mutex = mozilla::Mutex;
93 class MOZ_CAPABILITY("mutex") RefCountedMutex final : public Mutex {
94 public:
95 explicit RefCountedMutex(const char* aName) : Mutex(aName) {}
97 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex)
99 private:
100 ~RefCountedMutex() = default;
103 const RefPtr<RefCountedMutex> mMutex;
105 public:
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>> {
131 public:
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
143 // that call.
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)
173 // use.
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.
186 // ### Details
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
201 // things.
202 using TerminationCallback = std::function<void(void)>;
204 struct LocationInfo {
205 nsCString mHref;
206 nsCString mProtocol;
207 nsCString mHost;
208 nsCString mHostname;
209 nsCString mPort;
210 nsCString mPathname;
211 nsCString mSearch;
212 nsCString mHash;
213 nsString mOrigin;
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;
248 mSelfRef = nullptr;
251 // May be called on any thread...
252 bool Start();
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() {
274 return (
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;
287 mCondVar.Notify();
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) {
301 mCondVar.Wait();
305 nsresult SetIsDebuggerReady(bool aReady);
307 WorkerDebugger* Debugger() const {
308 AssertIsOnMainThread();
310 MOZ_ASSERT(mDebugger);
311 return 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();
346 MOZ_CAN_RUN_SCRIPT
347 void DoRunLoop(JSContext* aCx);
349 void UnrootGlobalScopes();
351 bool InterruptCallback(JSContext* aCx);
353 bool IsOnCurrentThread();
355 void CloseInternal();
357 bool FreezeInternal();
359 bool ThawInternal();
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,
375 ErrorResult& aRv);
377 void PostMessageToParentMessagePort(JSContext* aCx,
378 JS::Handle<JS::Value> aMessage,
379 const Sequence<JSObject*>& aTransferable,
380 ErrorResult& aRv);
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,
405 ErrorResult& aRv);
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);
427 #ifdef JS_GC_ZEAL
428 void UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal,
429 uint32_t aFrequency);
430 #endif
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();
462 return mJSContext;
465 WorkerGlobalScope* GlobalScope() const {
466 auto data = mWorkerThreadAccessible.Access();
467 return data->mScope;
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
494 #ifdef DEBUG
496 #else
499 #endif
501 // This may block!
502 void BeginCTypesCall();
504 // This may block!
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)
539 #ifdef DEBUG
541 #else
544 #endif
546 void AssertIsNotPotentiallyLastGCCCRunning() {
547 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
548 auto data = mWorkerThreadAccessible.Access();
549 MOZ_DIAGNOSTIC_ASSERT(!data->mIsPotentiallyLastGCCCRunning);
550 #endif
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
652 // shutting down.
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;
742 default:
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 {
955 // Any thread.
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();
1023 #endif
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);
1039 #ifdef JS_GC_ZEAL
1040 void UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency);
1041 #endif
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);
1054 #ifdef DEBUG
1055 void AssertIsOnParentThread() const;
1057 void AssertInnerWindowIsCorrect() const;
1058 #else
1059 void AssertIsOnParentThread() const {}
1061 void AssertInnerWindowIsCorrect() const {}
1062 #endif
1064 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1065 bool PrincipalIsValid() const;
1066 #endif
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;
1087 * COEP Methods
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
1106 // `aRequest`.
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;
1139 private:
1140 WorkerPrivate(
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);
1150 ~WorkerPrivate();
1152 struct AgentClusterIdAndCoop {
1153 nsID mId;
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);
1167 status = mStatus;
1170 if (status < Canceling) {
1171 return true;
1174 return false;
1177 void CancelAllTimeouts();
1179 enum class ProcessAllControlRunnablesResult {
1180 // We did not process anything.
1181 Nothing,
1182 // We did process something, states may have changed, but we can keep
1183 // executing script.
1184 MayContinue,
1185 // We did process something, and should not continue executing script.
1186 Abort
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);
1219 public:
1220 void CancelGCTimers() { SetGCTimerMode(NoTimer); }
1222 private:
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
1256 // executed.
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();
1277 class EventTarget;
1278 friend class EventTarget;
1279 friend class AutoSyncLoopHolder;
1281 struct TimeoutInfo;
1283 class MemoryReporter;
1284 friend class MemoryReporter;
1286 friend class mozilla::dom::WorkerThread;
1288 SharedMutex mMutex;
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
1340 // worker thread
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
1346 // here
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;
1365 nsresult mResult;
1366 bool mCompleted;
1367 #ifdef DEBUG
1368 bool mHasRun;
1369 #endif
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
1447 // thread.
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;
1478 bool mFrozen;
1479 bool mTimerRunning;
1480 bool mRunningExpiredTimeouts;
1481 bool mPeriodicGCTimerRunning;
1482 bool mIdleGCTimerRunning;
1483 bool mOnLine;
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;
1491 #endif
1493 ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible;
1495 class MOZ_RAII AutoPushEventLoopGlobal {
1496 public:
1497 AutoPushEventLoopGlobal(WorkerPrivate* aWorkerPrivate, JSContext* aCx);
1498 ~AutoPushEventLoopGlobal();
1500 private:
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.
1511 enum {
1512 eDispatchCancelingRunnable = 0x02,
1515 bool mParentWindowPaused;
1517 bool mWorkerScriptExecutedSuccessfully;
1518 bool mFetchHandlerWasAdded;
1519 bool mMainThreadObjectsForgotten;
1520 bool mIsChromeWorker;
1521 bool mParentFrozen;
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
1545 // are met.
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;
1552 nsString mId;
1554 // This is used to check if it's allowed to share the memory across the agent
1555 // cluster.
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;
1587 uint32_t mIndex;
1589 public:
1590 // See CreateNewSyncLoop() for more information about the correct value to use
1591 // for aFailStatus.
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);
1607 nsresult Run() {
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.
1618 return mTarget;
1622 } // namespace dom
1623 } // namespace mozilla
1625 #endif /* mozilla_dom_workers_workerprivate_h__ */