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