Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / serviceworkers / ServiceWorkerShutdownBlocker.h
bloba200325c5b83207dad5680b012249ced0c4ed526
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_serviceworkershutdownblocker_h__
8 #define mozilla_dom_serviceworkershutdownblocker_h__
10 #include "nsCOMPtr.h"
11 #include "nsIAsyncShutdown.h"
12 #include "nsISupportsImpl.h"
13 #include "nsITimer.h"
15 #include "ServiceWorkerShutdownState.h"
16 #include "mozilla/InitializedOnce.h"
17 #include "mozilla/MozPromise.h"
18 #include "mozilla/NotNull.h"
19 #include "mozilla/HashTable.h"
21 namespace mozilla::dom {
23 class ServiceWorkerManager;
25 /**
26 * Main thread only.
28 * A ServiceWorkerShutdownBlocker will "accept promises", and each of these
29 * promises will be a "pending promise" while it hasn't settled. At some point,
30 * `StopAcceptingPromises()` should be called and the state will change to "not
31 * accepting promises" (this is a one way state transition). The shutdown phase
32 * of the shutdown client the blocker is created with will be blocked until
33 * there are no more pending promises.
35 * It doesn't matter whether the state changes to "not accepting promises"
36 * before or during the associated shutdown phase.
38 * In beta/release builds there will be an additional timer that starts ticking
39 * once both the shutdown phase has been reached and the state is "not accepting
40 * promises". If when the timer expire there are still pending promises,
41 * shutdown will be forcefully unblocked.
43 class ServiceWorkerShutdownBlocker final : public nsIAsyncShutdownBlocker,
44 public nsITimerCallback,
45 public nsINamed {
46 public:
47 using Progress = ServiceWorkerShutdownState::Progress;
48 static const uint32_t kInvalidShutdownStateId = 0;
50 NS_DECL_ISUPPORTS
51 NS_DECL_NSIASYNCSHUTDOWNBLOCKER
52 NS_DECL_NSITIMERCALLBACK
53 NS_DECL_NSINAMED
55 /**
56 * Returns the registered shutdown blocker if registration succeeded and
57 * nullptr otherwise.
59 static already_AddRefed<ServiceWorkerShutdownBlocker> CreateAndRegisterOn(
60 nsIAsyncShutdownClient& aShutdownBarrier,
61 ServiceWorkerManager& aServiceWorkerManager);
63 /**
64 * Blocks shutdown until `aPromise` settles.
66 * Can be called multiple times, and shutdown will be blocked until all the
67 * calls' promises settle, but all of these calls must happen before
68 * `StopAcceptingPromises()` is called (assertions will enforce this).
70 * See `CreateShutdownState` for aShutdownStateId, which is needed to clear
71 * the shutdown state if the shutdown process aborts for some reason.
73 void WaitOnPromise(GenericNonExclusivePromise* aPromise,
74 uint32_t aShutdownStateId);
76 /**
77 * Once this is called, shutdown will be blocked until all promises
78 * passed to `WaitOnPromise()` settle, and there must be no more calls to
79 * `WaitOnPromise()` (assertions will enforce this).
81 void StopAcceptingPromises();
83 /**
84 * Start tracking the shutdown of an individual ServiceWorker for hang
85 * reporting purposes. Returns a "shutdown state ID" that should be used
86 * in subsequent calls to ReportShutdownProgress. The shutdown of an
87 * individual ServiceWorker is presumed to be completed when its `Progress`
88 * reaches `Progress::ShutdownCompleted`.
90 uint32_t CreateShutdownState();
92 void ReportShutdownProgress(uint32_t aShutdownStateId, Progress aProgress);
94 private:
95 explicit ServiceWorkerShutdownBlocker(
96 ServiceWorkerManager& aServiceWorkerManager);
98 ~ServiceWorkerShutdownBlocker();
101 * No-op if any of the following are true:
102 * 1) `BlockShutdown()` hasn't been called yet, or
103 * 2) `StopAcceptingPromises()` hasn't been called yet, or
104 * 3) `StopAcceptingPromises()` HAS been called, but there are still pending
105 * promises.
107 void MaybeUnblockShutdown();
110 * Requires `BlockShutdown()` to have been called.
112 void UnblockShutdown();
115 * Returns the remaining pending promise count (i.e. excluding the promise
116 * that just settled).
118 uint32_t PromiseSettled();
120 bool IsAcceptingPromises() const;
122 uint32_t GetPendingPromises() const;
125 * Initializes a timer that will unblock shutdown unconditionally once it's
126 * expired (even if there are still pending promises). No-op if:
127 * 1) not a beta or release build, or
128 * 2) shutdown is not being blocked or `StopAcceptingPromises()` has not been
129 * called.
131 void MaybeInitUnblockShutdownTimer();
133 struct AcceptingPromises {
134 uint32_t mPendingPromises = 0;
137 struct NotAcceptingPromises {
138 explicit NotAcceptingPromises(AcceptingPromises aPreviousState);
140 uint32_t mPendingPromises = 0;
143 Variant<AcceptingPromises, NotAcceptingPromises> mState;
145 nsCOMPtr<nsIAsyncShutdownClient> mShutdownClient;
147 HashMap<uint32_t, ServiceWorkerShutdownState> mShutdownStates;
149 nsCOMPtr<nsITimer> mTimer;
150 LazyInitializedOnceEarlyDestructible<
151 const NotNull<RefPtr<ServiceWorkerManager>>>
152 mServiceWorkerManager;
155 } // namespace mozilla::dom
157 #endif // mozilla_dom_serviceworkershutdownblocker_h__