summaryrefslogtreecommitdiffstats
path: root/dom/base/TimeoutManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/TimeoutManager.h')
-rw-r--r--dom/base/TimeoutManager.h250
1 files changed, 250 insertions, 0 deletions
diff --git a/dom/base/TimeoutManager.h b/dom/base/TimeoutManager.h
new file mode 100644
index 0000000000..fd04a1b215
--- /dev/null
+++ b/dom/base/TimeoutManager.h
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_TimeoutManager_h__
+#define mozilla_dom_TimeoutManager_h__
+
+#include "mozilla/dom/Timeout.h"
+#include "nsTArray.h"
+
+class nsIEventTarget;
+class nsITimer;
+class nsGlobalWindowInner;
+
+namespace mozilla {
+
+namespace dom {
+
+class TimeoutExecutor;
+class TimeoutHandler;
+
+// This class manages the timeouts in a Window's setTimeout/setInterval pool.
+class TimeoutManager final {
+ private:
+ struct Timeouts;
+
+ public:
+ TimeoutManager(nsGlobalWindowInner& aWindow, uint32_t aMaxIdleDeferMS);
+ ~TimeoutManager();
+ TimeoutManager(const TimeoutManager& rhs) = delete;
+ void operator=(const TimeoutManager& rhs) = delete;
+
+ bool IsRunningTimeout() const;
+
+ static uint32_t GetNestingLevel() { return sNestingLevel; }
+ static void SetNestingLevel(uint32_t aLevel) { sNestingLevel = aLevel; }
+
+ bool HasTimeouts() const {
+ return !mTimeouts.IsEmpty() || !mIdleTimeouts.IsEmpty();
+ }
+
+ nsresult SetTimeout(TimeoutHandler* aHandler, int32_t interval,
+ bool aIsInterval, mozilla::dom::Timeout::Reason aReason,
+ int32_t* aReturn);
+ void ClearTimeout(int32_t aTimerId, mozilla::dom::Timeout::Reason aReason);
+ bool ClearTimeoutInternal(int32_t aTimerId,
+ mozilla::dom::Timeout::Reason aReason,
+ bool aIsIdle);
+
+ // The timeout implementation functions.
+ MOZ_CAN_RUN_SCRIPT
+ void RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadline,
+ bool aProcessIdle);
+
+ void ClearAllTimeouts();
+ uint32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);
+
+ TimeDuration CalculateDelay(Timeout* aTimeout) const;
+
+ // aTimeout is the timeout that we're about to start running. This function
+ // returns the current timeout.
+ mozilla::dom::Timeout* BeginRunningTimeout(mozilla::dom::Timeout* aTimeout);
+ // aTimeout is the last running timeout.
+ void EndRunningTimeout(mozilla::dom::Timeout* aTimeout);
+
+ void UnmarkGrayTimers();
+
+ // These four methods are intended to be called from the corresponding methods
+ // on nsGlobalWindow.
+ void Suspend();
+ void Resume();
+ void Freeze();
+ void Thaw();
+
+ // This should be called by nsGlobalWindow when the window might have moved
+ // to the background or foreground.
+ void UpdateBackgroundState();
+
+ // The document finished loading
+ void OnDocumentLoaded();
+ void StartThrottlingTimeouts();
+
+ // Run some code for each Timeout in our list. Note that this function
+ // doesn't guarantee that Timeouts are iterated in any particular order.
+ template <class Callable>
+ void ForEachUnorderedTimeout(Callable c) {
+ mIdleTimeouts.ForEach(c);
+ mTimeouts.ForEach(c);
+ }
+
+ void BeginSyncOperation();
+ void EndSyncOperation();
+
+ nsIEventTarget* EventTarget();
+
+ bool BudgetThrottlingEnabled(bool aIsBackground) const;
+
+ static const uint32_t InvalidFiringId;
+
+ void SetLoading(bool value);
+
+ private:
+ void MaybeStartThrottleTimeout();
+
+ // Return true if |aTimeout| needs to be reinserted into the timeout list.
+ bool RescheduleTimeout(mozilla::dom::Timeout* aTimeout,
+ const TimeStamp& aLastCallbackTime,
+ const TimeStamp& aCurrentNow);
+
+ void MoveIdleToActive();
+
+ bool IsBackground() const;
+
+ bool IsActive() const;
+
+ uint32_t CreateFiringId();
+
+ void DestroyFiringId(uint32_t aFiringId);
+
+ bool IsValidFiringId(uint32_t aFiringId) const;
+
+ bool IsInvalidFiringId(uint32_t aFiringId) const;
+
+ TimeDuration MinSchedulingDelay() const;
+
+ nsresult MaybeSchedule(const TimeStamp& aWhen,
+ const TimeStamp& aNow = TimeStamp::Now());
+
+ void RecordExecution(Timeout* aRunningTimeout, Timeout* aTimeout);
+
+ void UpdateBudget(const TimeStamp& aNow,
+ const TimeDuration& aDuration = TimeDuration());
+
+ private:
+ struct Timeouts {
+ explicit Timeouts(const TimeoutManager& aManager)
+ : mManager(aManager), mTimeouts(new Timeout::TimeoutSet()) {}
+
+ // Insert aTimeout into the list, before all timeouts that would
+ // fire after it, but no earlier than the last Timeout with a
+ // valid FiringId.
+ enum class SortBy { TimeRemaining, TimeWhen };
+ void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
+
+ const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
+ Timeout* GetFirst() { return mTimeoutList.getFirst(); }
+ const Timeout* GetLast() const { return mTimeoutList.getLast(); }
+ Timeout* GetLast() { return mTimeoutList.getLast(); }
+ bool IsEmpty() const { return mTimeoutList.isEmpty(); }
+ void InsertFront(Timeout* aTimeout) {
+ aTimeout->SetTimeoutContainer(mTimeouts);
+ mTimeoutList.insertFront(aTimeout);
+ }
+ void InsertBack(Timeout* aTimeout) {
+ aTimeout->SetTimeoutContainer(mTimeouts);
+ mTimeoutList.insertBack(aTimeout);
+ }
+ void Clear() {
+ mTimeouts->Clear();
+ mTimeoutList.clear();
+ }
+
+ template <class Callable>
+ void ForEach(Callable c) {
+ for (Timeout* timeout = GetFirst(); timeout;
+ timeout = timeout->getNext()) {
+ c(timeout);
+ }
+ }
+
+ // Returns true when a callback aborts iteration.
+ template <class Callable>
+ bool ForEachAbortable(Callable c) {
+ for (Timeout* timeout = GetFirst(); timeout;
+ timeout = timeout->getNext()) {
+ if (c(timeout)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Timeout* GetTimeout(uint32_t aTimeoutId, Timeout::Reason aReason) {
+ Timeout::TimeoutIdAndReason key = {aTimeoutId, aReason};
+ return mTimeouts->Get(key);
+ }
+
+ private:
+ // The TimeoutManager that owns this Timeouts structure. This is
+ // mainly used to call state inspecting methods like IsValidFiringId().
+ const TimeoutManager& mManager;
+
+ using TimeoutList = mozilla::LinkedList<RefPtr<Timeout>>;
+
+ // mTimeoutList is generally sorted by mWhen, but new values are always
+ // inserted after any Timeouts with a valid FiringId.
+ TimeoutList mTimeoutList;
+
+ // mTimeouts is a set of all the timeouts in the mTimeoutList.
+ // It let's one to have O(1) check whether a timeout id/reason is in the
+ // list.
+ RefPtr<Timeout::TimeoutSet> mTimeouts;
+ };
+
+ // Each nsGlobalWindowInner object has a TimeoutManager member. This
+ // reference points to that holder object.
+ nsGlobalWindowInner& mWindow;
+ // The executor is specific to the nsGlobalWindow/TimeoutManager, but it
+ // can live past the destruction of the window if its scheduled. Therefore
+ // it must be a separate ref-counted object.
+ RefPtr<TimeoutExecutor> mExecutor;
+ // For timeouts run off the idle queue
+ RefPtr<TimeoutExecutor> mIdleExecutor;
+ // The list of timeouts coming from non-tracking scripts.
+ Timeouts mTimeouts;
+ uint32_t mTimeoutIdCounter;
+ uint32_t mNextFiringId;
+#ifdef DEBUG
+ int64_t mFiringIndex;
+ int64_t mLastFiringIndex;
+#endif
+ AutoTArray<uint32_t, 2> mFiringIdStack;
+ mozilla::dom::Timeout* mRunningTimeout;
+
+ // Timeouts that would have fired but are being deferred until MainThread
+ // is idle (because we're loading)
+ Timeouts mIdleTimeouts;
+
+ // The current idle request callback timeout handle
+ uint32_t mIdleCallbackTimeoutCounter;
+
+ nsCOMPtr<nsITimer> mThrottleTimeoutsTimer;
+ mozilla::TimeStamp mLastBudgetUpdate;
+ mozilla::TimeDuration mExecutionBudget;
+
+ bool mThrottleTimeouts;
+ bool mThrottleTrackingTimeouts;
+ bool mBudgetThrottleTimeouts;
+
+ bool mIsLoading;
+
+ static uint32_t sNestingLevel;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif