/* -*- 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 class nsIIdlePeriod; namespace mozilla { class TaskManager; namespace ipc { class IdleSchedulerChild; } // namespace ipc class IdlePeriodState { public: explicit IdlePeriodState(already_AddRefed&& 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 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 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