summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/IdlePeriodState.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/IdlePeriodState.h')
-rw-r--r--xpcom/threads/IdlePeriodState.h196
1 files changed, 196 insertions, 0 deletions
diff --git a/xpcom/threads/IdlePeriodState.h b/xpcom/threads/IdlePeriodState.h
new file mode 100644
index 0000000000..94d6615677
--- /dev/null
+++ b/xpcom/threads/IdlePeriodState.h
@@ -0,0 +1,196 @@
+/* -*- 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);
+ }
+
+ // If we have local idle deadline, but don't have an idle token, this will
+ // request such from the parent process when this is called in a child
+ // process.
+ void RequestIdleDeadlineIfNeeded(const MutexAutoUnlock& aProofOfUnlock) {
+ 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<mozilla::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;
+
+ // mActive is true when the PrioritizedEventQueue or TaskController we are
+ // associated with is running tasks.
+ bool mActive = true;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_IdlePeriodState_h