Line data Source code
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/. */
6 :
7 : #ifndef mozilla_dom_TimeoutManager_h__
8 : #define mozilla_dom_TimeoutManager_h__
9 :
10 : #include "mozilla/dom/Timeout.h"
11 : #include "nsTArray.h"
12 :
13 : class nsIEventTarget;
14 : class nsITimeoutHandler;
15 : class nsGlobalWindow;
16 :
17 : namespace mozilla {
18 : namespace dom {
19 :
20 : class OrderedTimeoutIterator;
21 : class TimeoutExecutor;
22 :
23 : // This class manages the timeouts in a Window's setTimeout/setInterval pool.
24 : class TimeoutManager final
25 : {
26 : public:
27 : explicit TimeoutManager(nsGlobalWindow& aWindow);
28 : ~TimeoutManager();
29 : TimeoutManager(const TimeoutManager& rhs) = delete;
30 : void operator=(const TimeoutManager& rhs) = delete;
31 :
32 : bool IsRunningTimeout() const;
33 :
34 8 : static uint32_t GetNestingLevel() { return sNestingLevel; }
35 16 : static void SetNestingLevel(uint32_t aLevel) { sNestingLevel = aLevel; }
36 :
37 0 : bool HasTimeouts() const
38 : {
39 0 : return !mNormalTimeouts.IsEmpty() ||
40 0 : !mTrackingTimeouts.IsEmpty();
41 : }
42 :
43 : nsresult SetTimeout(nsITimeoutHandler* aHandler,
44 : int32_t interval, bool aIsInterval,
45 : mozilla::dom::Timeout::Reason aReason,
46 : int32_t* aReturn);
47 : void ClearTimeout(int32_t aTimerId,
48 : mozilla::dom::Timeout::Reason aReason);
49 :
50 : // The timeout implementation functions.
51 : void RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadline);
52 :
53 : void ClearAllTimeouts();
54 : uint32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);
55 :
56 : TimeDuration CalculateDelay(Timeout* aTimeout) const;
57 :
58 : // aTimeout is the timeout that we're about to start running. This function
59 : // returns the current timeout.
60 : mozilla::dom::Timeout* BeginRunningTimeout(mozilla::dom::Timeout* aTimeout);
61 : // aTimeout is the last running timeout.
62 : void EndRunningTimeout(mozilla::dom::Timeout* aTimeout);
63 :
64 : void UnmarkGrayTimers();
65 :
66 : // These four methods are intended to be called from the corresponding methods
67 : // on nsGlobalWindow.
68 : void Suspend();
69 : void Resume();
70 : void Freeze();
71 : void Thaw();
72 :
73 : // This should be called by nsGlobalWindow when the window might have moved
74 : // to the background or foreground.
75 : void UpdateBackgroundState();
76 :
77 : // Initialize TimeoutManager before the first time it is accessed.
78 : static void Initialize();
79 :
80 : // Exposed only for testing
81 : bool IsTimeoutTracking(uint32_t aTimeoutId);
82 :
83 : // The document finished loading
84 : void OnDocumentLoaded();
85 : void StartThrottlingTimeouts();
86 :
87 : // Run some code for each Timeout in our list. Note that this function
88 : // doesn't guarantee that Timeouts are iterated in any particular order.
89 : template <class Callable>
90 4 : void ForEachUnorderedTimeout(Callable c)
91 : {
92 4 : mNormalTimeouts.ForEach(c);
93 4 : mTrackingTimeouts.ForEach(c);
94 4 : }
95 :
96 : // Run some code for each Timeout in our list, but let the callback cancel the
97 : // iteration by returning true. Note that this function doesn't guarantee
98 : // that Timeouts are iterated in any particular order.
99 : template <class Callable>
100 2 : void ForEachUnorderedTimeoutAbortable(Callable c)
101 : {
102 2 : if (!mNormalTimeouts.ForEachAbortable(c)) {
103 0 : mTrackingTimeouts.ForEachAbortable(c);
104 : }
105 2 : }
106 :
107 : void BeginSyncOperation();
108 : void EndSyncOperation();
109 :
110 : nsIEventTarget*
111 : EventTarget();
112 :
113 : static const uint32_t InvalidFiringId;
114 :
115 : private:
116 : void MaybeStartThrottleTimeout();
117 :
118 : // Return true if |aTimeout| needs to be reinserted into the timeout list.
119 : bool RescheduleTimeout(mozilla::dom::Timeout* aTimeout,
120 : const TimeStamp& aLastCallbackTime,
121 : const TimeStamp& aCurrentNow);
122 :
123 : bool IsBackground() const;
124 :
125 : bool IsActive() const;
126 :
127 : uint32_t
128 : CreateFiringId();
129 :
130 : void
131 : DestroyFiringId(uint32_t aFiringId);
132 :
133 : bool
134 : IsValidFiringId(uint32_t aFiringId) const;
135 :
136 : bool
137 : IsInvalidFiringId(uint32_t aFiringId) const;
138 :
139 : TimeDuration
140 : MinSchedulingDelay() const;
141 :
142 : nsresult MaybeSchedule(const TimeStamp& aWhen,
143 0 : const TimeStamp& aNow = TimeStamp::Now());
144 :
145 : void RecordExecution(Timeout* aRunningTimeout,
146 : Timeout* aTimeout);
147 :
148 : void UpdateBudget(const TimeStamp& aNow,
149 : const TimeDuration& aDuration = TimeDuration());
150 :
151 : private:
152 0 : struct Timeouts {
153 14 : explicit Timeouts(const TimeoutManager& aManager)
154 14 : : mManager(aManager)
155 : {
156 14 : }
157 :
158 : // Insert aTimeout into the list, before all timeouts that would
159 : // fire after it, but no earlier than the last Timeout with a
160 : // valid FiringId.
161 : enum class SortBy
162 : {
163 : TimeRemaining,
164 : TimeWhen
165 : };
166 : void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
167 :
168 : const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
169 10 : Timeout* GetFirst() { return mTimeoutList.getFirst(); }
170 : const Timeout* GetLast() const { return mTimeoutList.getLast(); }
171 13 : Timeout* GetLast() { return mTimeoutList.getLast(); }
172 0 : bool IsEmpty() const { return mTimeoutList.isEmpty(); }
173 4 : void InsertFront(Timeout* aTimeout) { mTimeoutList.insertFront(aTimeout); }
174 6 : void Clear() { mTimeoutList.clear(); }
175 :
176 : template <class Callable>
177 8 : void ForEach(Callable c)
178 : {
179 14 : for (Timeout* timeout = GetFirst();
180 : timeout;
181 6 : timeout = timeout->getNext()) {
182 6 : c(timeout);
183 : }
184 8 : }
185 :
186 : // Returns true when a callback aborts iteration.
187 : template <class Callable>
188 2 : bool ForEachAbortable(Callable c)
189 : {
190 2 : for (Timeout* timeout = GetFirst();
191 : timeout;
192 0 : timeout = timeout->getNext()) {
193 2 : if (c(timeout)) {
194 2 : return true;
195 : }
196 : }
197 0 : return false;
198 : }
199 :
200 : friend class OrderedTimeoutIterator;
201 :
202 : private:
203 : // The TimeoutManager that owns this Timeouts structure. This is
204 : // mainly used to call state inspecting methods like IsValidFiringId().
205 : const TimeoutManager& mManager;
206 :
207 : typedef mozilla::LinkedList<RefPtr<Timeout>> TimeoutList;
208 :
209 : // mTimeoutList is generally sorted by mWhen, but new values are always
210 : // inserted after any Timeouts with a valid FiringId.
211 : TimeoutList mTimeoutList;
212 : };
213 :
214 : friend class OrderedTimeoutIterator;
215 :
216 : // Each nsGlobalWindow object has a TimeoutManager member. This reference
217 : // points to that holder object.
218 : nsGlobalWindow& mWindow;
219 : // The executor is specific to the nsGlobalWindow/TimeoutManager, but it
220 : // can live past the destruction of the window if its scheduled. Therefore
221 : // it must be a separate ref-counted object.
222 : RefPtr<TimeoutExecutor> mExecutor;
223 : // The list of timeouts coming from non-tracking scripts.
224 : Timeouts mNormalTimeouts;
225 : // The list of timeouts coming from scripts on the tracking protection list.
226 : Timeouts mTrackingTimeouts;
227 : uint32_t mTimeoutIdCounter;
228 : uint32_t mNextFiringId;
229 : AutoTArray<uint32_t, 2> mFiringIdStack;
230 : mozilla::dom::Timeout* mRunningTimeout;
231 :
232 : // The current idle request callback timeout handle
233 : uint32_t mIdleCallbackTimeoutCounter;
234 :
235 : nsCOMPtr<nsITimer> mThrottleTimeoutsTimer;
236 : mozilla::TimeStamp mLastBudgetUpdate;
237 : mozilla::TimeDuration mExecutionBudget;
238 :
239 : bool mThrottleTimeouts;
240 : bool mThrottleTrackingTimeouts;
241 : bool mBudgetThrottleTimeouts;
242 :
243 : static uint32_t sNestingLevel;
244 : };
245 :
246 : }
247 : }
248 :
249 : #endif
|