mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1897400 - prepare TimeoutManager for reuse in workers via nsIGlobalObject, r=smaug
- methods IsBackgroundInternal(), IsRunningTimeout(), TimeoutManager() were moved to nsIGlobalObject Differential Revision: https://phabricator.services.mozilla.com/D211008
This commit is contained in:
parent
878964c6d3
commit
f31528cc43
@ -208,9 +208,11 @@ static void SetTimeoutForGlobal(GlobalObject& aGlobal, TimeoutHandler& aHandler,
|
||||
}
|
||||
|
||||
int32_t handle;
|
||||
nsresult rv = innerWindow->TimeoutManager().SetTimeout(
|
||||
&aHandler, timeout, /* aIsInterval */ false,
|
||||
Timeout::Reason::eAbortSignalTimeout, &handle);
|
||||
nsresult rv =
|
||||
nsGlobalWindowInner::Cast(innerWindow)
|
||||
->GetTimeoutManager()
|
||||
->SetTimeout(&aHandler, timeout, /* aIsInterval */ false,
|
||||
Timeout::Reason::eAbortSignalTimeout, &handle);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
|
@ -16719,15 +16719,17 @@ nsAutoSyncOperation::nsAutoSyncOperation(Document* aDoc,
|
||||
}
|
||||
|
||||
void nsAutoSyncOperation::SuppressDocument(Document* aDoc) {
|
||||
if (nsCOMPtr<nsPIDOMWindowInner> win = aDoc->GetInnerWindow()) {
|
||||
win->TimeoutManager().BeginSyncOperation();
|
||||
if (RefPtr<nsGlobalWindowInner> win =
|
||||
nsGlobalWindowInner::Cast(aDoc->GetInnerWindow())) {
|
||||
win->GetTimeoutManager()->BeginSyncOperation();
|
||||
}
|
||||
aDoc->SetIsInSyncOperation(true);
|
||||
}
|
||||
|
||||
void nsAutoSyncOperation::UnsuppressDocument(Document* aDoc) {
|
||||
if (nsCOMPtr<nsPIDOMWindowInner> win = aDoc->GetInnerWindow()) {
|
||||
win->TimeoutManager().EndSyncOperation();
|
||||
if (RefPtr<nsGlobalWindowInner> win =
|
||||
nsGlobalWindowInner::Cast(aDoc->GetInnerWindow())) {
|
||||
win->GetTimeoutManager()->EndSyncOperation();
|
||||
}
|
||||
aDoc->SetIsInSyncOperation(false);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TimeoutManager.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/ProfilerMarkers.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
@ -86,7 +86,12 @@ TimeDuration GetMinBudget(bool aIsBackground) {
|
||||
//
|
||||
|
||||
bool TimeoutManager::IsBackground() const {
|
||||
return !IsActive() && mWindow.IsBackgroundInternal();
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
if (!window) {
|
||||
// TODO(aiunusov): consider workers case here
|
||||
return !IsActive();
|
||||
}
|
||||
return !IsActive() && window->IsBackgroundInternal();
|
||||
}
|
||||
|
||||
bool TimeoutManager::IsActive() const {
|
||||
@ -97,12 +102,18 @@ bool TimeoutManager::IsActive() const {
|
||||
// Note that a window can be considered active if it is either in the
|
||||
// foreground or in the background.
|
||||
|
||||
if (mWindow.IsChromeWindow()) {
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
|
||||
if (!window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (window->IsChromeWindow()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we're playing audio
|
||||
if (mWindow.IsPlayingAudio()) {
|
||||
if (window->IsPlayingAudio()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -144,19 +155,24 @@ void TimeoutManager::MoveIdleToActive() {
|
||||
TimeDuration elapsed = now - timeout->SubmitTime();
|
||||
TimeDuration target = timeout->When() - timeout->SubmitTime();
|
||||
TimeDuration delta = now - timeout->When();
|
||||
nsPrintfCString marker(
|
||||
"Releasing deferred setTimeout() for %dms (original target time was "
|
||||
"%dms (%dms delta))",
|
||||
int(elapsed.ToMilliseconds()), int(target.ToMilliseconds()),
|
||||
int(delta.ToMilliseconds()));
|
||||
// don't have end before start...
|
||||
PROFILER_MARKER_TEXT(
|
||||
"setTimeout deferred release", DOM,
|
||||
MarkerOptions(
|
||||
MarkerTiming::Interval(
|
||||
delta.ToMilliseconds() >= 0 ? timeout->When() : now, now),
|
||||
MarkerInnerWindowId(mWindow.WindowID())),
|
||||
marker);
|
||||
if (mGlobalObject.GetAsInnerWindow()) {
|
||||
nsPrintfCString marker(
|
||||
"Releasing deferred setTimeout() for %dms (original target time "
|
||||
"was "
|
||||
"%dms (%dms delta))",
|
||||
int(elapsed.ToMilliseconds()), int(target.ToMilliseconds()),
|
||||
int(delta.ToMilliseconds()));
|
||||
// don't have end before start...
|
||||
PROFILER_MARKER_TEXT(
|
||||
"setTimeout deferred release", DOM,
|
||||
MarkerOptions(
|
||||
MarkerTiming::Interval(
|
||||
delta.ToMilliseconds() >= 0 ? timeout->When() : now, now),
|
||||
MarkerInnerWindowId(
|
||||
mGlobalObject.GetAsInnerWindow()->WindowID())),
|
||||
marker);
|
||||
}
|
||||
// TODO: add separate marker for Workers case
|
||||
}
|
||||
num++;
|
||||
}
|
||||
@ -195,7 +211,8 @@ TimeDuration TimeoutManager::MinSchedulingDelay() const {
|
||||
return TimeDuration();
|
||||
}
|
||||
|
||||
bool isBackground = mWindow.IsBackgroundInternal();
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
bool isBackground = window && window->IsBackgroundInternal();
|
||||
|
||||
// If a window isn't active as defined by TimeoutManager::IsActive()
|
||||
// and we're throttling timeouts using an execution budget, we
|
||||
@ -244,7 +261,11 @@ TimeDuration TimeoutManager::MinSchedulingDelay() const {
|
||||
bool budgetThrottlingEnabled = BudgetThrottlingEnabled(isBackground);
|
||||
if (budgetThrottlingEnabled && mExecutionBudget < TimeDuration()) {
|
||||
// Only throttle if execution budget is less than 0
|
||||
double factor = 1.0 / GetRegenerationFactor(mWindow.IsBackgroundInternal());
|
||||
|
||||
// TODO(aiunusov): change the logic accordingly for the workers,
|
||||
// once we have the "is in background" in workers
|
||||
double factor =
|
||||
1.0 / GetRegenerationFactor(window && window->IsBackgroundInternal());
|
||||
return TimeDuration::Max(unthrottled, -mExecutionBudget.MultDouble(factor));
|
||||
}
|
||||
if (!budgetThrottlingEnabled && isBackground) {
|
||||
@ -340,7 +361,12 @@ void TimeoutManager::RecordExecution(Timeout* aRunningTimeout,
|
||||
|
||||
void TimeoutManager::UpdateBudget(const TimeStamp& aNow,
|
||||
const TimeDuration& aDuration) {
|
||||
if (mWindow.IsChromeWindow()) {
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->IsChromeWindow()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -351,7 +377,7 @@ void TimeoutManager::UpdateBudget(const TimeStamp& aNow,
|
||||
// window is active or not. If throttling is enabled and the window
|
||||
// is active and then becomes inactive, an overdrawn budget will
|
||||
// still be counted against the minimum delay.
|
||||
bool isBackground = mWindow.IsBackgroundInternal();
|
||||
bool isBackground = window->IsBackgroundInternal();
|
||||
if (BudgetThrottlingEnabled(isBackground)) {
|
||||
double factor = GetRegenerationFactor(isBackground);
|
||||
TimeDuration regenerated = (aNow - mLastBudgetUpdate).MultDouble(factor);
|
||||
@ -381,9 +407,9 @@ void TimeoutManager::UpdateBudget(const TimeStamp& aNow,
|
||||
|
||||
uint32_t TimeoutManager::sNestingLevel = 0;
|
||||
|
||||
TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow,
|
||||
TimeoutManager::TimeoutManager(nsIGlobalObject& aHandle,
|
||||
uint32_t aMaxIdleDeferMS)
|
||||
: mWindow(aWindow),
|
||||
: mGlobalObject(aHandle),
|
||||
mExecutor(new TimeoutExecutor(this, false, 0)),
|
||||
mIdleExecutor(new TimeoutExecutor(this, true, aMaxIdleDeferMS)),
|
||||
mTimeouts(*this),
|
||||
@ -397,7 +423,8 @@ TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow,
|
||||
mIdleTimeouts(*this),
|
||||
mIdleCallbackTimeoutCounter(1),
|
||||
mLastBudgetUpdate(TimeStamp::Now()),
|
||||
mExecutionBudget(GetMaxBudget(mWindow.IsBackgroundInternal())),
|
||||
mExecutionBudget(GetMaxBudget(GetInnerWindow() &&
|
||||
GetInnerWindow()->IsBackgroundInternal())),
|
||||
mThrottleTimeouts(false),
|
||||
mThrottleTrackingTimeouts(false),
|
||||
mBudgetThrottleTimeouts(false),
|
||||
@ -410,7 +437,7 @@ TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow,
|
||||
}
|
||||
|
||||
TimeoutManager::~TimeoutManager() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mWindow.IsDying());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mGlobalObject.IsDying());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mThrottleTimeoutsTimer);
|
||||
|
||||
mExecutor->Shutdown();
|
||||
@ -439,11 +466,15 @@ nsresult TimeoutManager::SetTimeout(TimeoutHandler* aHandler, int32_t interval,
|
||||
int32_t* aReturn) {
|
||||
// If we don't have a document (we could have been unloaded since
|
||||
// the call to setTimeout was made), do nothing.
|
||||
nsCOMPtr<Document> doc = mWindow.GetExtantDoc();
|
||||
if (!doc || mWindow.IsDying()) {
|
||||
return NS_OK;
|
||||
if (mGlobalObject.GetAsInnerWindow()) {
|
||||
nsCOMPtr<Document> doc = mGlobalObject.GetAsInnerWindow()->GetExtantDoc();
|
||||
if (!doc || mGlobalObject.IsDying()) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
|
||||
// Disallow negative intervals.
|
||||
interval = std::max(0, interval);
|
||||
|
||||
@ -459,7 +490,7 @@ nsresult TimeoutManager::SetTimeout(TimeoutHandler* aHandler, int32_t interval,
|
||||
#ifdef DEBUG
|
||||
timeout->mFiringIndex = -1;
|
||||
#endif
|
||||
timeout->mWindow = &mWindow;
|
||||
timeout->mWindow = window;
|
||||
timeout->mIsInterval = aIsInterval;
|
||||
timeout->mInterval = TimeDuration::FromMilliseconds(interval);
|
||||
timeout->mScriptHandler = aHandler;
|
||||
@ -483,7 +514,7 @@ nsresult TimeoutManager::SetTimeout(TimeoutHandler* aHandler, int32_t interval,
|
||||
timeout->SetWhenOrTimeRemaining(now, realInterval);
|
||||
|
||||
// If we're not suspended, then set the timer.
|
||||
if (!mWindow.IsSuspended()) {
|
||||
if (window && !window->IsSuspended()) {
|
||||
nsresult rv = MaybeSchedule(timeout->When(), now);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
@ -505,8 +536,9 @@ nsresult TimeoutManager::SetTimeout(TimeoutHandler* aHandler, int32_t interval,
|
||||
}
|
||||
}
|
||||
|
||||
Timeouts::SortBy sort(mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
|
||||
: Timeouts::SortBy::TimeWhen);
|
||||
Timeouts::SortBy sort(window && window->IsFrozen()
|
||||
? Timeouts::SortBy::TimeRemaining
|
||||
: Timeouts::SortBy::TimeWhen);
|
||||
|
||||
timeout->mTimeoutId = GetTimeoutId(aReason);
|
||||
mTimeouts.Insert(timeout, sort);
|
||||
@ -522,7 +554,7 @@ nsresult TimeoutManager::SetTimeout(TimeoutHandler* aHandler, int32_t interval,
|
||||
(CalculateDelay(timeout) - timeout->mInterval).ToMilliseconds(),
|
||||
mThrottleTimeouts ? "yes" : (mThrottleTimeoutsTimer ? "pending" : "no"),
|
||||
IsActive() ? "active" : "inactive",
|
||||
mWindow.IsBackgroundInternal() ? "background" : "foreground",
|
||||
window && window->IsBackgroundInternal() ? "background" : "foreground",
|
||||
realInterval.ToMilliseconds(), timeout->mTimeoutId,
|
||||
int(mExecutionBudget.ToMilliseconds())));
|
||||
|
||||
@ -556,6 +588,8 @@ bool TimeoutManager::ClearTimeoutInternal(int32_t aTimerId,
|
||||
}
|
||||
bool firstTimeout = timeout == timeouts.GetFirst();
|
||||
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("%s(TimeoutManager=%p, timeout=%p, ID=%u)\n",
|
||||
timeout->mReason == Timeout::Reason::eIdleCallbackTimeout
|
||||
@ -583,7 +617,7 @@ bool TimeoutManager::ClearTimeoutInternal(int32_t aTimerId,
|
||||
// RunTimeout() will handle rescheduling the executor.
|
||||
// * If the window has become suspended then we should not start executing
|
||||
// Timeouts.
|
||||
if (!firstTimeout || deferredDeletion || mWindow.IsSuspended()) {
|
||||
if (!firstTimeout || deferredDeletion || (window && window->IsSuspended())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -608,8 +642,19 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aNow.IsNull());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aTargetDeadline.IsNull());
|
||||
|
||||
MOZ_ASSERT_IF(mWindow.IsFrozen(), mWindow.IsSuspended());
|
||||
if (mWindow.IsSuspended()) {
|
||||
// Make sure that the window and the script context don't go away as
|
||||
// a result of running timeouts
|
||||
RefPtr<nsGlobalWindowInner> window = GetInnerWindow();
|
||||
|
||||
if (!window) {
|
||||
// we have a workers case here
|
||||
// TODO(aiunusov): change the code accordigly to cover workers usecase
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(window->IsFrozen(), window->IsSuspended());
|
||||
|
||||
if (window->IsSuspended()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -639,10 +684,7 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
uint32_t firingId = CreateFiringId();
|
||||
auto guard = MakeScopeExit([&] { DestroyFiringId(firingId); });
|
||||
|
||||
// Make sure that the window and the script context don't go away as
|
||||
// a result of running timeouts
|
||||
RefPtr<nsGlobalWindowInner> window(&mWindow);
|
||||
// Accessing members of mWindow here is safe, because the lifetime of
|
||||
// Accessing members of mGlobalObject here is safe, because the lifetime of
|
||||
// TimeoutManager is the same as the lifetime of the containing
|
||||
// nsGlobalWindow.
|
||||
|
||||
@ -716,7 +758,7 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
// Note, we verified the window is not suspended at the top of
|
||||
// method and the window should not have been suspended while
|
||||
// executing the loop above since it doesn't call out to js.
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mWindow.IsSuspended());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!window->IsSuspended());
|
||||
if (aProcessIdle) {
|
||||
// We don't want to update timing budget for idle queue firings, and
|
||||
// all timeouts in the IdleTimeouts list have hit their deadlines,
|
||||
@ -803,8 +845,8 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(mWindow.IsFrozen(), mWindow.IsSuspended());
|
||||
if (mWindow.IsSuspended()) {
|
||||
MOZ_ASSERT_IF(window->IsFrozen(), window->IsSuspended());
|
||||
if (window->IsSuspended()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -851,7 +893,7 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
|
||||
// Get the script context (a strong ref to prevent it going away)
|
||||
// for this timeout and ensure the script language is enabled.
|
||||
nsCOMPtr<nsIScriptContext> scx = mWindow.GetContextInternal();
|
||||
nsCOMPtr<nsIScriptContext> scx = window->GetContextInternal();
|
||||
|
||||
if (!scx) {
|
||||
// No context means this window was closed or never properly
|
||||
@ -876,7 +918,10 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
mLastFiringIndex = timeout->mFiringIndex;
|
||||
#endif
|
||||
// This timeout is good to run.
|
||||
bool timeout_was_cleared = window->RunTimeoutHandler(timeout, scx);
|
||||
bool timeout_was_cleared = false;
|
||||
if (window) {
|
||||
timeout_was_cleared = window->RunTimeoutHandler(timeout, scx);
|
||||
}
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("Run%s(TimeoutManager=%p, timeout=%p) returned %d\n",
|
||||
timeout->mIsInterval ? "Interval" : "Timeout", this,
|
||||
@ -914,7 +959,7 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
// Insert interval timeout onto the corresponding list sorted in
|
||||
// deadline order. AddRefs timeout.
|
||||
// Always re-insert into the normal time queue!
|
||||
mTimeouts.Insert(timeout, mWindow.IsFrozen()
|
||||
mTimeouts.Insert(timeout, window->IsFrozen()
|
||||
? Timeouts::SortBy::TimeRemaining
|
||||
: Timeouts::SortBy::TimeWhen);
|
||||
}
|
||||
@ -927,7 +972,7 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
// run immediately for the next timer, if it exists. Its possible,
|
||||
// however, that the last timeout handler suspended the window. If
|
||||
// that happened then we must skip this step.
|
||||
if (!mWindow.IsSuspended()) {
|
||||
if (!window->IsSuspended()) {
|
||||
if (next) {
|
||||
if (aProcessIdle) {
|
||||
// We don't want to update timing budget for idle queue firings,
|
||||
@ -990,8 +1035,9 @@ bool TimeoutManager::RescheduleTimeout(Timeout* aTimeout,
|
||||
}
|
||||
|
||||
aTimeout->SetWhenOrTimeRemaining(aCurrentNow, delay);
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
|
||||
if (mWindow.IsSuspended()) {
|
||||
if (window && window->IsSuspended()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1103,11 +1149,12 @@ void TimeoutManager::Suspend() {
|
||||
|
||||
void TimeoutManager::Resume() {
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug, ("Resume(TimeoutManager=%p)\n", this));
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
|
||||
// When Suspend() has been called after IsDocumentLoaded(), but the
|
||||
// throttle tracking timer never managed to fire, start the timer
|
||||
// again.
|
||||
if (mWindow.IsDocumentLoaded() && !mThrottleTimeouts) {
|
||||
if (window && window->IsDocumentLoaded() && !mThrottleTimeouts) {
|
||||
MaybeStartThrottleTimeout();
|
||||
}
|
||||
|
||||
@ -1167,13 +1214,14 @@ void TimeoutManager::Thaw() {
|
||||
}
|
||||
|
||||
void TimeoutManager::UpdateBackgroundState() {
|
||||
mExecutionBudget = GetMaxBudget(mWindow.IsBackgroundInternal());
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
mExecutionBudget = GetMaxBudget(window && window->IsBackgroundInternal());
|
||||
|
||||
// When the window moves to the background or foreground we should
|
||||
// reschedule the TimeoutExecutor in case the MinSchedulingDelay()
|
||||
// changed. Only do this if the window is not suspended and we
|
||||
// actually have a timeout.
|
||||
if (!mWindow.IsSuspended()) {
|
||||
if (window && !window->IsSuspended()) {
|
||||
Timeout* nextTimeout = mTimeouts.GetFirst();
|
||||
if (nextTimeout) {
|
||||
mExecutor->Cancel();
|
||||
@ -1198,8 +1246,8 @@ namespace {
|
||||
class ThrottleTimeoutsCallback final : public nsITimerCallback,
|
||||
public nsINamed {
|
||||
public:
|
||||
explicit ThrottleTimeoutsCallback(nsGlobalWindowInner* aWindow)
|
||||
: mWindow(aWindow) {}
|
||||
explicit ThrottleTimeoutsCallback(nsIGlobalObject* aHandle)
|
||||
: mGlobalObject(aHandle) {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
@ -1215,15 +1263,19 @@ class ThrottleTimeoutsCallback final : public nsITimerCallback,
|
||||
private:
|
||||
// The strong reference here keeps the Window and hence the TimeoutManager
|
||||
// object itself alive.
|
||||
RefPtr<nsGlobalWindowInner> mWindow;
|
||||
RefPtr<nsIGlobalObject> mGlobalObject;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ThrottleTimeoutsCallback, nsITimerCallback, nsINamed)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleTimeoutsCallback::Notify(nsITimer* aTimer) {
|
||||
mWindow->TimeoutManager().StartThrottlingTimeouts();
|
||||
mWindow = nullptr;
|
||||
if (nsGlobalWindowInner::Cast(mGlobalObject->GetAsInnerWindow())) {
|
||||
nsGlobalWindowInner::Cast(mGlobalObject->GetAsInnerWindow())
|
||||
->GetTimeoutManager()
|
||||
->StartThrottlingTimeouts();
|
||||
}
|
||||
mGlobalObject = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1249,17 +1301,19 @@ bool TimeoutManager::BudgetThrottlingEnabled(bool aIsBackground) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
|
||||
// Check if there are any active IndexedDB databases
|
||||
if (mWindow.HasActiveIndexedDBDatabases()) {
|
||||
if (window && window->HasActiveIndexedDBDatabases()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we have active PeerConnection
|
||||
if (mWindow.HasActivePeerConnections()) {
|
||||
if (window && window->HasActivePeerConnections()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mWindow.HasOpenWebSockets()) {
|
||||
if (window && window->HasOpenWebSockets()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1291,8 +1345,9 @@ void TimeoutManager::OnDocumentLoaded() {
|
||||
}
|
||||
|
||||
void TimeoutManager::MaybeStartThrottleTimeout() {
|
||||
if (StaticPrefs::dom_timeout_throttling_delay() <= 0 || mWindow.IsDying() ||
|
||||
mWindow.IsSuspended()) {
|
||||
nsGlobalWindowInner* win = GetInnerWindow();
|
||||
if (StaticPrefs::dom_timeout_throttling_delay() <= 0 || !win ||
|
||||
win->IsDying() || win->IsSuspended()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1302,7 +1357,8 @@ void TimeoutManager::MaybeStartThrottleTimeout() {
|
||||
("TimeoutManager %p delaying tracking timeout throttling by %dms\n",
|
||||
this, StaticPrefs::dom_timeout_throttling_delay()));
|
||||
|
||||
nsCOMPtr<nsITimerCallback> callback = new ThrottleTimeoutsCallback(&mWindow);
|
||||
nsCOMPtr<nsITimerCallback> callback =
|
||||
new ThrottleTimeoutsCallback(&mGlobalObject);
|
||||
|
||||
NS_NewTimerWithCallback(getter_AddRefs(mThrottleTimeoutsTimer), callback,
|
||||
StaticPrefs::dom_timeout_throttling_delay(),
|
||||
@ -1325,5 +1381,9 @@ void TimeoutManager::EndSyncOperation() {
|
||||
}
|
||||
|
||||
nsIEventTarget* TimeoutManager::EventTarget() {
|
||||
return mWindow.GetBrowsingContextGroup()->GetTimerEventQueue();
|
||||
nsGlobalWindowInner* window = GetInnerWindow();
|
||||
if (window) {
|
||||
return window->GetBrowsingContextGroup()->GetTimerEventQueue();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
class nsIEventTarget;
|
||||
class nsITimer;
|
||||
class nsGlobalWindowInner;
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -27,7 +27,7 @@ class TimeoutManager final {
|
||||
struct Timeouts;
|
||||
|
||||
public:
|
||||
TimeoutManager(nsGlobalWindowInner& aWindow, uint32_t aMaxIdleDeferMS);
|
||||
TimeoutManager(nsIGlobalObject& aHandle, uint32_t aMaxIdleDeferMS);
|
||||
~TimeoutManager();
|
||||
TimeoutManager(const TimeoutManager& rhs) = delete;
|
||||
void operator=(const TimeoutManager& rhs) = delete;
|
||||
@ -104,6 +104,13 @@ class TimeoutManager final {
|
||||
private:
|
||||
void MaybeStartThrottleTimeout();
|
||||
|
||||
// get nsGlobalWindowInner
|
||||
// if the method returns nullptr, then we have a worker,
|
||||
// which should be handled differently according to TimeoutManager logic
|
||||
nsGlobalWindowInner* GetInnerWindow() const {
|
||||
return nsGlobalWindowInner::Cast(mGlobalObject.GetAsInnerWindow());
|
||||
}
|
||||
|
||||
// Return true if |aTimeout| needs to be reinserted into the timeout list.
|
||||
bool RescheduleTimeout(mozilla::dom::Timeout* aTimeout,
|
||||
const TimeStamp& aLastCallbackTime,
|
||||
@ -204,9 +211,9 @@ class TimeoutManager final {
|
||||
RefPtr<Timeout::TimeoutSet> mTimeouts;
|
||||
};
|
||||
|
||||
// Each nsGlobalWindowInner object has a TimeoutManager member. This
|
||||
// Each nsIGlobalObject object has a TimeoutManager member. This
|
||||
// reference points to that holder object.
|
||||
nsGlobalWindowInner& mWindow;
|
||||
nsIGlobalObject& mGlobalObject;
|
||||
// The executor is specific to the nsGlobalWindow/TimeoutManager, but it
|
||||
// can live past the destruction of the window if its scheduled. Therefore
|
||||
// it must be a separate ref-counted object.
|
||||
|
@ -191,7 +191,7 @@ void MarkDocumentViewer(nsIDocumentViewer* aViewer, bool aCleanupJS) {
|
||||
if (elm) {
|
||||
elm->MarkForCC();
|
||||
}
|
||||
win->TimeoutManager().UnmarkGrayTimers();
|
||||
win->GetTimeoutManager()->UnmarkGrayTimers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -606,7 +606,7 @@ nsresult IdleRequestExecutor::Cancel() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mDelayedExecutorHandle && mWindow) {
|
||||
mWindow->TimeoutManager().ClearTimeout(
|
||||
mWindow->GetTimeoutManager()->ClearTimeout(
|
||||
mDelayedExecutorHandle.value(), Timeout::Reason::eIdleCallbackTimeout);
|
||||
}
|
||||
|
||||
@ -671,7 +671,7 @@ void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) {
|
||||
MOZ_ASSERT(mWindow);
|
||||
MOZ_ASSERT(mDelayedExecutorHandle.isNothing());
|
||||
int32_t handle;
|
||||
mWindow->TimeoutManager().SetTimeout(
|
||||
mWindow->GetTimeoutManager()->SetTimeout(
|
||||
mDelayedExecutorDispatcher, aDelay, false,
|
||||
Timeout::Reason::eIdleCallbackTimeout, &handle);
|
||||
mDelayedExecutorHandle = Some(handle);
|
||||
@ -2773,12 +2773,12 @@ bool nsPIDOMWindowInner::IsPlayingAudio() {
|
||||
|
||||
bool nsPIDOMWindowInner::IsDocumentLoaded() const { return mIsDocumentLoaded; }
|
||||
|
||||
mozilla::dom::TimeoutManager& nsPIDOMWindowInner::TimeoutManager() {
|
||||
return *mTimeoutManager;
|
||||
mozilla::dom::TimeoutManager* nsGlobalWindowInner::GetTimeoutManager() {
|
||||
return mTimeoutManager.get();
|
||||
}
|
||||
|
||||
bool nsPIDOMWindowInner::IsRunningTimeout() {
|
||||
return TimeoutManager().IsRunningTimeout();
|
||||
bool nsGlobalWindowInner::IsRunningTimeout() {
|
||||
return GetTimeoutManager()->IsRunningTimeout();
|
||||
}
|
||||
|
||||
void nsPIDOMWindowInner::TryToCacheTopInnerWindow() {
|
||||
|
@ -272,6 +272,10 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
||||
|
||||
virtual nsIPrincipal* PartitionedPrincipal() override;
|
||||
|
||||
mozilla::dom::TimeoutManager* GetTimeoutManager() override;
|
||||
|
||||
bool IsRunningTimeout() override;
|
||||
|
||||
// nsIDOMWindow
|
||||
NS_DECL_NSIDOMWINDOW
|
||||
|
||||
@ -1168,7 +1172,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
||||
friend class nsPIDOMWindowInner;
|
||||
friend class nsPIDOMWindowOuter;
|
||||
|
||||
bool IsBackgroundInternal() const;
|
||||
bool IsBackgroundInternal() const override;
|
||||
|
||||
// NOTE: Chrome Only
|
||||
void DisconnectAndClearGroupMessageManagers() {
|
||||
|
@ -283,6 +283,9 @@ class nsIGlobalObject : public nsISupports {
|
||||
* is not a suspendable worker.
|
||||
*/
|
||||
virtual bool IsEligibleForMessaging() { return false; };
|
||||
virtual bool IsBackgroundInternal() const { return false; }
|
||||
virtual mozilla::dom::TimeoutManager* GetTimeoutManager() { return nullptr; }
|
||||
virtual bool IsRunningTimeout() { return false; }
|
||||
|
||||
protected:
|
||||
virtual ~nsIGlobalObject();
|
||||
|
@ -354,10 +354,6 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
||||
|
||||
bool IsDocumentLoaded() const;
|
||||
|
||||
mozilla::dom::TimeoutManager& TimeoutManager();
|
||||
|
||||
bool IsRunningTimeout();
|
||||
|
||||
// To cache top inner-window if available after constructed for tab-wised
|
||||
// indexedDB counters.
|
||||
void TryToCacheTopInnerWindow();
|
||||
|
@ -38,9 +38,10 @@ nsresult WebTaskSchedulerMainThread::SetTimeoutForDelayedTask(WebTask* aTask,
|
||||
int32_t delay = aDelay > INT32_MAX ? INT32_MAX : (int32_t)aDelay;
|
||||
|
||||
int32_t handle;
|
||||
return global->GetAsInnerWindow()->TimeoutManager().SetTimeout(
|
||||
handler, delay, /* aIsInterval */ false,
|
||||
Timeout::Reason::eDelayedWebTaskTimeout, &handle);
|
||||
return nsGlobalWindowInner::Cast(global->GetAsInnerWindow())
|
||||
->GetTimeoutManager()
|
||||
->SetTimeout(handler, delay, /* aIsInterval */ false,
|
||||
Timeout::Reason::eDelayedWebTaskTimeout, &handle);
|
||||
}
|
||||
|
||||
bool WebTaskSchedulerMainThread::DispatchEventLoopRunnable() {
|
||||
|
@ -297,7 +297,8 @@ static bool IsPresContextInScriptAnimationCallback(
|
||||
}
|
||||
// Treat timeouts/setintervals as scripted animation callbacks for our
|
||||
// purposes.
|
||||
nsPIDOMWindowInner* win = aPresContext->Document()->GetInnerWindow();
|
||||
nsGlobalWindowInner* win =
|
||||
nsGlobalWindowInner::Cast(aPresContext->Document()->GetInnerWindow());
|
||||
return win && win->IsRunningTimeout();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user