Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / base / TimeoutManager.h
blob105c084253e2de4b62f4b6621523dd4912bf2ddd
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_TimeoutManager_h__
8 #define mozilla_dom_TimeoutManager_h__
10 #include "mozilla/dom/Timeout.h"
11 #include "nsTArray.h"
12 #include "nsISerialEventTarget.h"
14 class nsIEventTarget;
15 class nsITimer;
16 class nsIGlobalObject;
18 namespace mozilla {
20 namespace dom {
22 class TimeoutExecutor;
23 class TimeoutHandler;
25 // This class manages the timeouts in a Window's setTimeout/setInterval pool.
26 class TimeoutManager final {
27 private:
28 struct Timeouts;
30 public:
31 TimeoutManager(nsIGlobalObject& aHandle, uint32_t aMaxIdleDeferMS,
32 nsISerialEventTarget* aEventTarget);
33 ~TimeoutManager();
34 TimeoutManager(const TimeoutManager& rhs) = delete;
35 void operator=(const TimeoutManager& rhs) = delete;
37 bool IsRunningTimeout() const;
39 uint32_t GetNestingLevel() {
40 return mGlobalObject.GetAsInnerWindow() ? sNestingLevel : mNestingLevel;
43 void SetNestingLevel(uint32_t aLevel) {
44 if (mGlobalObject.GetAsInnerWindow()) {
45 sNestingLevel = aLevel;
46 } else {
47 mNestingLevel = aLevel;
51 bool HasTimeouts() const {
52 return !mTimeouts.IsEmpty() || !mIdleTimeouts.IsEmpty();
55 nsresult SetTimeout(TimeoutHandler* aHandler, int32_t interval,
56 bool aIsInterval, mozilla::dom::Timeout::Reason aReason,
57 int32_t* aReturn);
58 void ClearTimeout(int32_t aTimerId, mozilla::dom::Timeout::Reason aReason);
59 bool ClearTimeoutInternal(int32_t aTimerId,
60 mozilla::dom::Timeout::Reason aReason,
61 bool aIsIdle);
63 // The timeout implementation functions.
64 MOZ_CAN_RUN_SCRIPT
65 void RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadline,
66 bool aProcessIdle);
68 void ClearAllTimeouts();
69 int32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);
71 TimeDuration CalculateDelay(Timeout* aTimeout) const;
73 // aTimeout is the timeout that we're about to start running. This function
74 // returns the current timeout.
75 mozilla::dom::Timeout* BeginRunningTimeout(mozilla::dom::Timeout* aTimeout);
76 // aTimeout is the last running timeout.
77 void EndRunningTimeout(mozilla::dom::Timeout* aTimeout);
79 void UnmarkGrayTimers();
81 // These four methods are intended to be called from the corresponding methods
82 // on nsGlobalWindow.
83 void Suspend();
84 void Resume();
85 void Freeze();
86 void Thaw();
88 // This should be called by nsGlobalWindow when the window might have moved
89 // to the background or foreground.
90 void UpdateBackgroundState();
92 // The document finished loading
93 void OnDocumentLoaded();
94 void StartThrottlingTimeouts();
96 // Run some code for each Timeout in our list. Note that this function
97 // doesn't guarantee that Timeouts are iterated in any particular order.
98 template <class Callable>
99 void ForEachUnorderedTimeout(Callable c) {
100 mIdleTimeouts.ForEach(c);
101 mTimeouts.ForEach(c);
104 void BeginSyncOperation();
105 void EndSyncOperation();
107 nsIEventTarget* EventTarget();
109 bool BudgetThrottlingEnabled(bool aIsBackground) const;
111 static const uint32_t InvalidFiringId;
113 void SetLoading(bool value);
115 private:
116 void MaybeStartThrottleTimeout();
118 // get nsGlobalWindowInner
119 // if the method returns nullptr, then we have a worker,
120 // which should be handled differently according to TimeoutManager logic
121 nsGlobalWindowInner* GetInnerWindow() const {
122 return nsGlobalWindowInner::Cast(mGlobalObject.GetAsInnerWindow());
125 // Return true if |aTimeout| needs to be reinserted into the timeout list.
126 bool RescheduleTimeout(mozilla::dom::Timeout* aTimeout,
127 const TimeStamp& aLastCallbackTime,
128 const TimeStamp& aCurrentNow);
130 void MoveIdleToActive();
132 bool IsBackground() const;
134 bool IsActive() const;
136 uint32_t CreateFiringId();
138 void DestroyFiringId(uint32_t aFiringId);
140 bool IsValidFiringId(uint32_t aFiringId) const;
142 bool IsInvalidFiringId(uint32_t aFiringId) const;
144 TimeDuration MinSchedulingDelay() const;
146 nsresult MaybeSchedule(const TimeStamp& aWhen,
147 const TimeStamp& aNow = TimeStamp::Now());
149 void RecordExecution(Timeout* aRunningTimeout, Timeout* aTimeout);
151 void UpdateBudget(const TimeStamp& aNow,
152 const TimeDuration& aDuration = TimeDuration());
154 private:
155 struct Timeouts {
156 explicit Timeouts(const TimeoutManager& aManager)
157 : mManager(aManager), mTimeouts(new Timeout::TimeoutSet()) {}
159 // Insert aTimeout into the list, before all timeouts that would
160 // fire after it, but no earlier than the last Timeout with a
161 // valid FiringId.
162 enum class SortBy { TimeRemaining, TimeWhen };
163 void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
165 const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
166 Timeout* GetFirst() { return mTimeoutList.getFirst(); }
167 const Timeout* GetLast() const { return mTimeoutList.getLast(); }
168 Timeout* GetLast() { return mTimeoutList.getLast(); }
169 bool IsEmpty() const { return mTimeoutList.isEmpty(); }
170 void InsertFront(Timeout* aTimeout) {
171 aTimeout->SetTimeoutContainer(mTimeouts);
172 mTimeoutList.insertFront(aTimeout);
174 void InsertBack(Timeout* aTimeout) {
175 aTimeout->SetTimeoutContainer(mTimeouts);
176 mTimeoutList.insertBack(aTimeout);
178 void Clear() {
179 mTimeouts->Clear();
180 mTimeoutList.clear();
183 template <class Callable>
184 void ForEach(Callable c) {
185 for (Timeout* timeout = GetFirst(); timeout;
186 timeout = timeout->getNext()) {
187 c(timeout);
191 // Returns true when a callback aborts iteration.
192 template <class Callable>
193 bool ForEachAbortable(Callable c) {
194 for (Timeout* timeout = GetFirst(); timeout;
195 timeout = timeout->getNext()) {
196 if (c(timeout)) {
197 return true;
200 return false;
203 Timeout* GetTimeout(int32_t aTimeoutId, Timeout::Reason aReason) {
204 Timeout::TimeoutIdAndReason key = {aTimeoutId, aReason};
205 return mTimeouts->Get(key);
208 private:
209 // The TimeoutManager that owns this Timeouts structure. This is
210 // mainly used to call state inspecting methods like IsValidFiringId().
211 const TimeoutManager& mManager;
213 using TimeoutList = mozilla::LinkedList<RefPtr<Timeout>>;
215 // mTimeoutList is generally sorted by mWhen, but new values are always
216 // inserted after any Timeouts with a valid FiringId.
217 TimeoutList mTimeoutList;
219 // mTimeouts is a set of all the timeouts in the mTimeoutList.
220 // It let's one to have O(1) check whether a timeout id/reason is in the
221 // list.
222 RefPtr<Timeout::TimeoutSet> mTimeouts;
225 // Each nsIGlobalObject object has a TimeoutManager member. This
226 // reference points to that holder object.
227 nsIGlobalObject& mGlobalObject;
228 // The executor is specific to the nsGlobalWindow/TimeoutManager, but it
229 // can live past the destruction of the window if its scheduled. Therefore
230 // it must be a separate ref-counted object.
231 RefPtr<TimeoutExecutor> mExecutor;
232 // For timeouts run off the idle queue
233 RefPtr<TimeoutExecutor> mIdleExecutor;
234 // The list of timeouts coming from non-tracking scripts.
235 Timeouts mTimeouts;
236 int32_t mTimeoutIdCounter;
237 uint32_t mNextFiringId;
238 #ifdef DEBUG
239 int64_t mFiringIndex;
240 int64_t mLastFiringIndex;
241 #endif
242 AutoTArray<uint32_t, 2> mFiringIdStack;
243 mozilla::dom::Timeout* mRunningTimeout;
245 // Timeouts that would have fired but are being deferred until MainThread
246 // is idle (because we're loading)
247 Timeouts mIdleTimeouts;
249 // The current idle request callback timeout handle
250 int32_t mIdleCallbackTimeoutCounter;
252 nsCOMPtr<nsITimer> mThrottleTimeoutsTimer;
253 mozilla::TimeStamp mLastBudgetUpdate;
254 mozilla::TimeDuration mExecutionBudget;
256 bool mThrottleTimeouts;
257 bool mThrottleTrackingTimeouts;
258 bool mBudgetThrottleTimeouts;
260 bool mIsLoading;
261 nsCOMPtr<nsISerialEventTarget> mEventTarget;
263 uint32_t mNestingLevel{0};
264 static uint32_t sNestingLevel;
267 } // namespace dom
268 } // namespace mozilla
270 #endif