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