tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TimeoutManager.h (8783B)


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