DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
/* -*- 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_IdlePeriodState_h
#define mozilla_IdlePeriodState_h

/**
 * A class for tracking the state of our idle period.  This includes keeping
 * track of both the state of our process-local idle period estimate and, for
 * content processes, managing communication with the parent process for
 * cross-pprocess idle detection.
 */

#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"

#include <stdint.h>

class nsIIdlePeriod;

namespace mozilla {
class TaskManager;
namespace ipc {
class IdleSchedulerChild;
}  // namespace ipc

class IdlePeriodState {
 public:
  explicit IdlePeriodState(already_AddRefed<nsIIdlePeriod>&& aIdlePeriod);

  ~IdlePeriodState();

  // Integration with memory reporting.
  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;

  // Notification that whoever we are tracking idle state for has found a
  // non-idle task to process.
  //
  // Must not be called while holding any locks.
  void FlagNotIdle();

  // Notification that whoever we are tracking idle state for has no more
  // tasks (idle or not) to process.
  //
  // aProofOfUnlock is the proof that our caller unlocked its mutex.
  void RanOutOfTasks(const MutexAutoUnlock& aProofOfUnlock);

  // Notification that whoever we are tracking idle state has idle tasks that
  // they are considering ready to run and that we should keep claiming they are
  // ready to run until they call ForgetPendingTaskGuarantee().
  void EnforcePendingTaskGuarantee() {
    mHasPendingEventsPromisedIdleEvent = true;
  }

  // Notification that whoever we are tracking idle state for is done with our
  // "we have an idle event ready to run" guarantee.  When this happens, we can
  // reset mHasPendingEventsPromisedIdleEvent to false, because we have
  // fulfilled our contract.
  void ForgetPendingTaskGuarantee() {
    mHasPendingEventsPromisedIdleEvent = false;
  }

  // Update our cached idle deadline so consumers can use it while holding
  // locks. Consumers must ClearCachedIdleDeadline() once they are done.
  void UpdateCachedIdleDeadline(const MutexAutoUnlock& aProofOfUnlock) {
    mCachedIdleDeadline = GetIdleDeadlineInternal(false, aProofOfUnlock);
  }

  // Reset our cached idle deadline, so we stop allowing idle runnables to run.
  void ClearCachedIdleDeadline() { mCachedIdleDeadline = TimeStamp(); }

  // Get the current cached idle deadline.  This may return a null timestamp.
  TimeStamp GetCachedIdleDeadline() { return mCachedIdleDeadline; }

  // Peek our current idle deadline into mCachedIdleDeadline.  This can cause
  // mCachedIdleDeadline to be a null timestamp (which means we are not idle
  // right now).  This method does not have any side-effects on our state, apart
  // from guaranteeing that if it returns non-null then GetDeadlineForIdleTask
  // will return non-null until ForgetPendingTaskGuarantee() is called, and its
  // effects on mCachedIdleDeadline.
  //
  // aProofOfUnlock is the proof that our caller unlocked its mutex.
  void CachePeekedIdleDeadline(const MutexAutoUnlock& aProofOfUnlock) {
    mCachedIdleDeadline = GetIdleDeadlineInternal(true, aProofOfUnlock);
  }

  void SetIdleToken(uint64_t aId, TimeDuration aDuration);

  bool IsActive() { return mActive; }

 protected:
  void EnsureIsActive() {
    if (!mActive) {
      SetActive();
    }
  }

  void EnsureIsPaused(const MutexAutoUnlock& aProofOfUnlock) {
    if (mActive) {
      SetPaused(aProofOfUnlock);
    }
  }

  // Returns a null TimeStamp if we're not in the idle period.
  TimeStamp GetLocalIdleDeadline(bool& aShuttingDown,
                                 const MutexAutoUnlock& aProofOfUnlock);

  // Gets the idle token, which is the end time of the idle period.
  //
  // aProofOfUnlock is the proof that our caller unlocked its mutex.
  TimeStamp GetIdleToken(TimeStamp aLocalIdlePeriodHint,
                         const MutexAutoUnlock& aProofOfUnlock);

  // In case of child processes, requests idle time from the cross-process
  // idle scheduler.
  void RequestIdleToken(TimeStamp aLocalIdlePeriodHint);

  // Mark that we don't have idle time to use, nor are expecting to get an idle
  // token from the idle scheduler.  This must be called while not holding any
  // locks, but some of the callers aren't holding locks to start with, so
  // consumers just need to make sure they are not holding locks when they call
  // this.
  void ClearIdleToken();

  // SetActive should be called when the event queue is running any type of
  // tasks.
  void SetActive();
  // SetPaused should be called once the event queue doesn't have more
  // tasks to process, or is waiting for the idle token.
  //
  // aProofOfUnlock is the proof that our caller unlocked its mutex.
  void SetPaused(const MutexAutoUnlock& aProofOfUnlock);

  // Get or peek our idle deadline.  When peeking, we generally don't change any
  // of our internal state.  When getting, we may request an idle token as
  // needed.
  //
  // aProofOfUnlock is the proof that our caller unlocked its mutex.
  TimeStamp GetIdleDeadlineInternal(bool aIsPeek,
                                    const MutexAutoUnlock& aProofOfUnlock);

  // Whether we should be getting an idle token (i.e. are a content process
  // and are using cross process idle scheduling).
  bool ShouldGetIdleToken();

  // Set to true if we have claimed we have a ready-to-run idle task when asked.
  // In that case, we will ensure that we allow at least one task to run when
  // someone tries to run a task, even if we have run out of idle period at that
  // point.  This ensures that we never fail to produce a task to run if we
  // claim we have a task ready to run.
  bool mHasPendingEventsPromisedIdleEvent = false;

  // mIdlePeriod keeps track of the current idle period. Calling
  // mIdlePeriod->GetIdlePeriodHint() will give an estimate of when
  // the current idle period will end.
  nsCOMPtr<nsIIdlePeriod> mIdlePeriod;

  // If non-null, this timestamp represents the end time of the idle period.  An
  // idle period starts when we get the idle token from the parent process and
  // ends when either there are no more things we want to run at idle priority
  // or mIdleToken < TimeStamp::Now(), so we have reached our idle deadline.
  TimeStamp mIdleToken;

  // The id of the last idle request to the cross-process idle scheduler.
  uint64_t mIdleRequestId = 0;

  // If we're in a content process, we use mIdleScheduler to communicate with
  // the parent process for purposes of cross-process idle tracking.
  RefPtr<ipc::IdleSchedulerChild> mIdleScheduler;

  // Our cached idle deadline.  This is set by UpdateCachedIdleDeadline() and
  // cleared by ClearCachedIdleDeadline().  Consumers should do the former while
  // not holding any locks, but may do the latter while holding locks.
  TimeStamp mCachedIdleDeadline;

  // mIdleSchedulerInitialized is true if our mIdleScheduler has been
  // initialized.  It may be null even after initialiazation, in various
  // situations.
  bool mIdleSchedulerInitialized = false;

  // mActive is true when the PrioritizedEventQueue or TaskController we are
  // associated with is running tasks.
  bool mActive = true;
};

}  // namespace mozilla

#endif  // mozilla_IdlePeriodState_h