зеркало из https://github.com/mozilla/gecko-dev.git
195 строки
7.5 KiB
C++
195 строки
7.5 KiB
C++
/* -*- 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<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;
|
|
|
|
// 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
|