Bug 1437064 - Remove tracking timeouts list from TimeoutManager. r=chutten,Ehsan

Differential Revision: https://phabricator.services.mozilla.com/D7878

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andreas Farre 2018-10-12 18:01:19 +00:00
Родитель 50a1f611cf
Коммит c9272ef398
16 изменённых файлов: 71 добавлений и 530 удалений

Просмотреть файл

@ -1,173 +0,0 @@
/* -*- 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_dom_OrderedTimeoutIterator_h__
#define mozilla_dom_OrderedTimeoutIterator_h__
#include "mozilla/RefPtr.h"
#include "mozilla/dom/Timeout.h"
#include "mozilla/dom/TimeoutManager.h"
namespace mozilla {
namespace dom {
// This class implements and iterator which iterates the normal and tracking
// timeouts lists simultaneously in the mWhen order.
class MOZ_STACK_CLASS OrderedTimeoutIterator final {
public:
typedef TimeoutManager::Timeouts Timeouts;
typedef Timeouts::TimeoutList TimeoutList;
OrderedTimeoutIterator(Timeouts& aNormalTimeouts,
Timeouts& aTrackingTimeouts)
: mNormalTimeouts(aNormalTimeouts.mTimeoutList),
mTrackingTimeouts(aTrackingTimeouts.mTimeoutList),
mNormalIter(mNormalTimeouts.getFirst()),
mTrackingIter(mTrackingTimeouts.getFirst()),
mKind(Kind::None),
mUpdateIteratorCalled(true)
{
}
// Return the current timeout and move to the next one.
// Unless this is the first time calling Next(), you must call
// UpdateIterator() before calling this method.
Timeout* Next()
{
MOZ_ASSERT(mUpdateIteratorCalled);
MOZ_ASSERT_IF(mNormalIter, mNormalIter->isInList());
MOZ_ASSERT_IF(mTrackingIter, mTrackingIter->isInList());
mUpdateIteratorCalled = false;
mKind = Kind::None;
Timeout* timeout = nullptr;
if (!mNormalIter) {
if (!mTrackingIter) {
// We have reached the end of both lists. Bail out!
return nullptr;
} else {
// We have reached the end of the normal timeout list, select the next
// tracking timeout.
timeout = mTrackingIter;
mKind = Kind::Tracking;
}
} else if (!mTrackingIter) {
// We have reached the end of the tracking timeout list, select the next
// normal timeout.
timeout = mNormalIter;
mKind = Kind::Normal;
} else {
// If we have a normal and a tracking timer, return the one with the
// smaller mWhen (and prefer the timeout with a lower ID in case they are
// equal.) Otherwise, return whichever iterator has an item left,
// preferring a non-tracking timeout again. Note that in practice, even
// if a web page calls setTimeout() twice in a row, it should get
// different mWhen values, so in practice we shouldn't fall back to
// comparing timeout IDs.
if (mNormalIter && mTrackingIter &&
(mTrackingIter->When() < mNormalIter->When() ||
(mTrackingIter->When() == mNormalIter->When() &&
mTrackingIter->mTimeoutId < mNormalIter->mTimeoutId))) {
timeout = mTrackingIter;
mKind = Kind::Tracking;
} else if (mNormalIter) {
timeout = mNormalIter;
mKind = Kind::Normal;
} else if (mTrackingIter) {
timeout = mTrackingIter;
mKind = Kind::Tracking;
}
}
if (!timeout) {
// We didn't find any suitable iterator. This can happen for example
// when getNext() in UpdateIterator() returns nullptr and then Next()
// gets called. Bail out!
return nullptr;
}
MOZ_ASSERT(mKind != Kind::None);
// Record the current timeout we just found.
mCurrent = timeout;
MOZ_ASSERT(mCurrent);
return mCurrent;
}
// Prepare the iterator for the next call to Next().
// This method can be called as many times as needed. Calling this more than
// once is helpful in cases where we expect the timeouts list has been
// modified before we got a chance to call Next().
void UpdateIterator()
{
MOZ_ASSERT(mKind != Kind::None);
// Update the winning iterator to point to the next element. Also check to
// see if the other iterator is still valid, otherwise reset it to the
// beginning of the list. This is needed in case a timeout handler removes
// the timeout pointed to from one of our iterators.
if (mKind == Kind::Normal) {
mNormalIter = mCurrent->getNext();
if (mTrackingIter && !mTrackingIter->isInList()) {
mTrackingIter = mTrackingTimeouts.getFirst();
}
} else {
mTrackingIter = mCurrent->getNext();
if (mNormalIter && !mNormalIter->isInList()) {
mNormalIter = mNormalTimeouts.getFirst();
}
}
mUpdateIteratorCalled = true;
}
// This function resets the iterator to a defunct state. It should only be
// used when we want to forcefully sever all of the strong references this
// class holds.
void Clear()
{
// Release all strong references.
mNormalIter = nullptr;
mTrackingIter = nullptr;
mCurrent = nullptr;
mKind = Kind::None;
mUpdateIteratorCalled = true;
}
// Returns true if the previous call to Next() picked a normal timeout.
// Cannot be called before Next() has been called. Note that the result of
// this method is only affected by Next() and not UpdateIterator(), so calling
// UpdateIterator() before calling this is allowed.
bool PickedNormalIter() const
{
MOZ_ASSERT(mKind != Kind::None);
return mKind == Kind::Normal;
}
// Returns true if the previous call to Next() picked a tracking timeout.
// Cannot be called before Next() has been called. Note that the result of
// this method is only affected by Next() and not UpdateIterator(), so calling
// UpdateIterator() before calling this is allowed.
bool PickedTrackingIter() const
{
MOZ_ASSERT(mKind != Kind::None);
return mKind == Kind::Tracking;
}
private:
TimeoutList& mNormalTimeouts; // The list of normal timeouts.
TimeoutList& mTrackingTimeouts; // The list of tracking timeouts.
RefPtr<Timeout> mNormalIter; // The iterator over the normal timeout list.
RefPtr<Timeout> mTrackingIter; // The iterator over the tracking timeout list.
RefPtr<Timeout> mCurrent; // The current timeout that Next() just found.
enum class Kind { Normal, Tracking, None };
Kind mKind; // The kind of iterator picked the last time.
DebugOnly<bool> mUpdateIteratorCalled; // Whether we have called UpdateIterator() before calling Next().
};
}
}
#endif

Просмотреть файл

@ -19,8 +19,7 @@ Timeout::Timeout()
mNestingLevel(0),
mCleared(false),
mRunning(false),
mIsInterval(false),
mIsTracking(false)
mIsInterval(false)
{
}

Просмотреть файл

@ -104,9 +104,6 @@ public:
// True if this is a repeating/interval timer
bool mIsInterval;
// True if this is a timeout coming from a tracking script
bool mIsTracking;
};
} // namespace dom

Просмотреть файл

@ -11,9 +11,6 @@
namespace mozilla {
namespace dom {
// Time between sampling timeout execution time.
const uint32_t kTelemetryPeriodMS = 1000;
/* static */ TimeoutBudgetManager&
TimeoutBudgetManager::Get()
{
@ -35,8 +32,7 @@ TimeoutBudgetManager::StopRecording()
TimeDuration
TimeoutBudgetManager::RecordExecution(const TimeStamp& aNow,
const Timeout* aTimeout,
bool aIsBackground)
const Timeout* aTimeout)
{
if (!mStart) {
// If we've started a sync operation mStart might be null, in
@ -44,53 +40,7 @@ TimeoutBudgetManager::RecordExecution(const TimeStamp& aNow,
return TimeDuration();
}
TimeDuration duration = aNow - mStart;
if (aIsBackground) {
if (aTimeout->mIsTracking) {
mTelemetryData.mBackgroundTracking += duration;
} else {
mTelemetryData.mBackgroundNonTracking += duration;
}
} else {
if (aTimeout->mIsTracking) {
mTelemetryData.mForegroundTracking += duration;
} else {
mTelemetryData.mForegroundNonTracking += duration;
}
}
return duration;
}
void
TimeoutBudgetManager::Accumulate(Telemetry::HistogramID aId,
const TimeDuration& aSample)
{
uint32_t sample = std::round(aSample.ToMilliseconds());
if (sample) {
Telemetry::Accumulate(aId, sample);
}
}
void
TimeoutBudgetManager::MaybeCollectTelemetry(const TimeStamp& aNow)
{
if ((aNow - mLastCollection).ToMilliseconds() < kTelemetryPeriodMS) {
return;
}
Accumulate(Telemetry::TIMEOUT_EXECUTION_FG_TRACKING_MS,
mTelemetryData.mForegroundTracking);
Accumulate(Telemetry::TIMEOUT_EXECUTION_FG_MS,
mTelemetryData.mForegroundNonTracking);
Accumulate(Telemetry::TIMEOUT_EXECUTION_BG_TRACKING_MS,
mTelemetryData.mBackgroundTracking);
Accumulate(Telemetry::TIMEOUT_EXECUTION_BG_MS,
mTelemetryData.mBackgroundNonTracking);
mTelemetryData = TelemetryData();
mLastCollection = aNow;
return aNow - mStart;
}
} // namespace dom

Просмотреть файл

@ -7,7 +7,6 @@
#ifndef mozilla_dom_timeoutbudgetmanager_h
#define mozilla_dom_timeoutbudgetmanager_h
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
namespace mozilla {
@ -22,24 +21,11 @@ public:
void StartRecording(const TimeStamp& aNow);
void StopRecording();
TimeDuration RecordExecution(const TimeStamp& aNow,
const Timeout* aTimeout,
bool aIsBackground);
void MaybeCollectTelemetry(const TimeStamp& aNow);
const Timeout* aTimeout);
private:
TimeoutBudgetManager() : mLastCollection(TimeStamp::Now()) {}
struct TelemetryData
{
TimeDuration mForegroundTracking;
TimeDuration mForegroundNonTracking;
TimeDuration mBackgroundTracking;
TimeDuration mBackgroundNonTracking;
};
TimeoutBudgetManager() = default;
void Accumulate(Telemetry::HistogramID aId, const TimeDuration& aSample);
TelemetryData mTelemetryData;
TimeStamp mStart;
TimeStamp mLastCollection;
};
} // namespace dom

Просмотреть файл

@ -18,7 +18,6 @@
#include "nsITimeoutHandler.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/TabGroup.h"
#include "OrderedTimeoutIterator.h"
#include "TimeoutExecutor.h"
#include "TimeoutBudgetManager.h"
#include "mozilla/net/WebSocketEventService.h"
@ -293,11 +292,6 @@ TimeoutManager::CalculateDelay(Timeout* aTimeout) const {
result, TimeDuration::FromMilliseconds(gMinClampTimeoutValue));
}
if (aTimeout->mIsTracking && mThrottleTrackingTimeouts) {
result = TimeDuration::Max(
result, TimeDuration::FromMilliseconds(gMinTrackingTimeoutValue));
}
return result;
}
@ -332,9 +326,7 @@ TimeoutManager::RecordExecution(Timeout* aRunningTimeout,
if (aRunningTimeout) {
// If we're running a timeout callback, record any execution until
// now.
TimeDuration duration = budgetManager.RecordExecution(
now, aRunningTimeout, mWindow.IsBackgroundInternal());
budgetManager.MaybeCollectTelemetry(now);
TimeDuration duration = budgetManager.RecordExecution(now, aRunningTimeout);
UpdateBudget(now, duration);
@ -396,13 +388,6 @@ TimeoutManager::UpdateBudget(const TimeStamp& aNow, const TimeDuration& aDuratio
mLastBudgetUpdate = aNow;
}
#define TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY 0 // Consider all timeouts coming from tracking scripts as tracking
// These strategies are useful for testing.
#define ALL_NORMAL_TIMEOUT_BUCKETING_STRATEGY 1 // Consider all timeouts as normal
#define ALTERNATE_TIMEOUT_BUCKETING_STRATEGY 2 // Put every other timeout in the list of tracking timeouts
#define RANDOM_TIMEOUT_BUCKETING_STRATEGY 3 // Put timeouts into either the normal or tracking timeouts list randomly
static int32_t gTimeoutBucketingStrategy = 0;
#define DEFAULT_TIMEOUT_THROTTLING_DELAY -1 // Only positive integers cause us to introduce a delay for
// timeout throttling.
@ -430,8 +415,7 @@ int32_t gDisableOpenClickDelay;
TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow)
: mWindow(aWindow),
mExecutor(new TimeoutExecutor(this)),
mNormalTimeouts(*this),
mTrackingTimeouts(*this),
mTimeouts(*this),
mTimeoutIdCounter(1),
mNextFiringId(InvalidFiringId + 1),
mRunningTimeout(nullptr),
@ -474,9 +458,6 @@ TimeoutManager::Initialize()
Preferences::AddIntVarCache(&gMinTrackingBackgroundTimeoutValue,
"dom.min_tracking_background_timeout_value",
DEFAULT_MIN_TRACKING_BACKGROUND_TIMEOUT_VALUE);
Preferences::AddIntVarCache(&gTimeoutBucketingStrategy,
"dom.timeout_bucketing_strategy",
TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY);
Preferences::AddIntVarCache(&gTimeoutThrottlingDelay,
"dom.timeout.throttling_delay",
DEFAULT_TIMEOUT_THROTTLING_DELAY);
@ -563,43 +544,6 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
// No popups from timeouts by default
timeout->mPopupState = openAbused;
switch (gTimeoutBucketingStrategy) {
default:
case TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY: {
const char* filename = nullptr;
uint32_t dummyLine = 0, dummyColumn = 0;
aHandler->GetLocation(&filename, &dummyLine, &dummyColumn);
timeout->mIsTracking = doc->IsScriptTracking(nsDependentCString(filename));
MOZ_LOG(gLog, LogLevel::Debug,
("Classified timeout %p set from %s as %stracking\n",
timeout.get(), filename, timeout->mIsTracking ? "" : "non-"));
break;
}
case ALL_NORMAL_TIMEOUT_BUCKETING_STRATEGY:
// timeout->mIsTracking is already false!
MOZ_DIAGNOSTIC_ASSERT(!timeout->mIsTracking);
MOZ_LOG(gLog, LogLevel::Debug,
("Classified timeout %p unconditionally as normal\n",
timeout.get()));
break;
case ALTERNATE_TIMEOUT_BUCKETING_STRATEGY:
timeout->mIsTracking = (mTimeoutIdCounter % 2) == 0;
MOZ_LOG(gLog, LogLevel::Debug,
("Classified timeout %p as %stracking (alternating mode)\n",
timeout.get(), timeout->mIsTracking ? "" : "non-"));
break;
case RANDOM_TIMEOUT_BUCKETING_STRATEGY:
timeout->mIsTracking = (rand() % 2) == 0;
MOZ_LOG(gLog, LogLevel::Debug,
("Classified timeout %p as %stracking (random mode)\n",
timeout.get(), timeout->mIsTracking ? "" : "non-"));
break;
}
timeout->mNestingLevel = sNestingLevel < DOM_CLAMP_TIMEOUT_NESTING_LEVEL
? sNestingLevel + 1 : sNestingLevel;
@ -633,11 +577,7 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
Timeouts::SortBy sort(mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
: Timeouts::SortBy::TimeWhen);
if (timeout->mIsTracking) {
mTrackingTimeouts.Insert(timeout, sort);
} else {
mNormalTimeouts.Insert(timeout, sort);
}
mTimeouts.Insert(timeout, sort);
timeout->mTimeoutId = GetTimeoutId(aReason);
*aReturn = timeout->mTimeoutId;
@ -646,7 +586,7 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
LogLevel::Debug,
("Set%s(TimeoutManager=%p, timeout=%p, delay=%i, "
"minimum=%f, throttling=%s, state=%s(%s), realInterval=%f) "
"returned %stracking timeout ID %u, budget=%d\n",
"returned timeout ID %u, budget=%d\n",
aIsInterval ? "Interval" : "Timeout",
this, timeout.get(), interval,
(CalculateDelay(timeout) - timeout->mInterval).ToMilliseconds(),
@ -656,7 +596,6 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
IsActive() ? "active" : "inactive",
mWindow.IsBackgroundInternal() ? "background" : "foreground",
realInterval.ToMilliseconds(),
timeout->mIsTracking ? "" : "non-",
timeout->mTimeoutId,
int(mExecutionBudget.ToMilliseconds())));
@ -671,11 +610,10 @@ TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason)
bool firstTimeout = true;
bool deferredDeletion = false;
ForEachUnorderedTimeoutAbortable([&](Timeout* aTimeout) {
mTimeouts.ForEachAbortable([&](Timeout* aTimeout) {
MOZ_LOG(gLog, LogLevel::Debug,
("Clear%s(TimeoutManager=%p, timeout=%p, aTimerId=%u, ID=%u, tracking=%d)\n", aTimeout->mIsInterval ? "Interval" : "Timeout",
this, aTimeout, timerId, aTimeout->mTimeoutId,
int(aTimeout->mIsTracking)));
("Clear%s(TimeoutManager=%p, timeout=%p, aTimerId=%u, ID=%u)\n", aTimeout->mIsInterval ? "Interval" : "Timeout",
this, aTimeout, timerId, aTimeout->mTimeoutId));
if (aTimeout->mTimeoutId == timerId && aTimeout->mReason == aReason) {
if (aTimeout->mRunning) {
@ -712,8 +650,7 @@ TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason)
// Stop the executor and restart it at the next soonest deadline.
mExecutor->Cancel();
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
Timeout* nextTimeout = iter.Next();
Timeout* nextTimeout = mTimeouts.GetFirst();
if (nextTimeout) {
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextTimeout->When()));
}
@ -787,39 +724,30 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
// if the timer fired early. So we can stop walking if we get to timeouts
// whose When() is greater than deadline, since once that happens we know
// nothing past that point is expired.
{
// Use a nested scope in order to make sure the strong references held by
// the iterator are freed after the loop.
OrderedTimeoutIterator expiredIter(mNormalTimeouts, mTrackingTimeouts);
for (Timeout* timeout = mTimeouts.GetFirst();
timeout != nullptr;
timeout = timeout->getNext()) {
if (totalTimeLimit.IsZero() || timeout->When() > deadline) {
nextDeadline = timeout->When();
break;
}
while (true) {
Timeout* timeout = expiredIter.Next();
if (!timeout || totalTimeLimit.IsZero() || timeout->When() > deadline) {
if (timeout) {
if (IsInvalidFiringId(timeout->mFiringId)) {
// Mark any timeouts that are on the list to be fired with the
// firing depth so that we can reentrantly run timeouts
timeout->mFiringId = firingId;
numTimersToRun += 1;
// Run only a limited number of timers based on the configured maximum.
if (numTimersToRun % kNumTimersPerInitialElapsedCheck == 0) {
now = TimeStamp::Now();
TimeDuration elapsed(now - start);
if (elapsed >= initialTimeLimit) {
nextDeadline = timeout->When();
}
break;
}
if (IsInvalidFiringId(timeout->mFiringId)) {
// Mark any timeouts that are on the list to be fired with the
// firing depth so that we can reentrantly run timeouts
timeout->mFiringId = firingId;
numTimersToRun += 1;
// Run only a limited number of timers based on the configured maximum.
if (numTimersToRun % kNumTimersPerInitialElapsedCheck == 0) {
now = TimeStamp::Now();
TimeDuration elapsed(now - start);
if (elapsed >= initialTimeLimit) {
nextDeadline = timeout->When();
break;
}
break;
}
}
expiredIter.UpdateIterator();
}
}
@ -853,17 +781,18 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
// next item after the last timeout we looked at or nullptr if we have
// exhausted the entire list while looking for the last expired timeout.
{
// Use a nested scope in order to make sure the strong references held by
// the iterator are freed after the loop.
OrderedTimeoutIterator runIter(mNormalTimeouts, mTrackingTimeouts);
while (true) {
RefPtr<Timeout> timeout = runIter.Next();
if (!timeout) {
// We have run out of timeouts!
break;
}
runIter.UpdateIterator();
// Use a nested scope in order to make sure the strong references held while
// iterating are freed after the loop.
// The next timeout to run. This is used to advance the loop, but
// we cannot set it until we've run the current timeout, since
// running the current timeout might remove the immediate next
// timeout.
RefPtr<Timeout> next;
for (RefPtr<Timeout> timeout = mTimeouts.GetFirst();
timeout != nullptr;
timeout = next) {
// We should only execute callbacks for the set of expired Timeout
// objects we computed above.
if (timeout->mFiringId != firingId) {
@ -907,15 +836,18 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
// This timeout is good to run
bool timeout_was_cleared = mWindow.RunTimeoutHandler(timeout, scx);
MOZ_LOG(gLog, LogLevel::Debug,
("Run%s(TimeoutManager=%p, timeout=%p, tracking=%d) returned %d\n", timeout->mIsInterval ? "Interval" : "Timeout",
this, timeout.get(),
int(timeout->mIsTracking),
!!timeout_was_cleared));
MOZ_LOG(
gLog,
LogLevel::Debug,
("Run%s(TimeoutManager=%p, timeout=%p) returned %d\n",
timeout->mIsInterval ? "Interval" : "Timeout",
this,
timeout.get(),
!!timeout_was_cleared));
if (timeout_was_cleared) {
// Make sure the iterator isn't holding any Timeout objects alive.
runIter.Clear();
// Make sure we're not holding any Timeout objects alive.
next = nullptr;
// Since ClearAllTimeouts() was called the lists should be empty.
MOZ_DIAGNOSTIC_ASSERT(!HasTimeouts());
@ -936,22 +868,16 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
// Running a timeout can cause another timeout to be deleted, so
// we need to reset the pointer to the following timeout.
runIter.UpdateIterator();
next = timeout->getNext();
timeout->remove();
if (needsReinsertion) {
// Insert interval timeout onto the corresponding list sorted in
// deadline order. AddRefs timeout.
if (runIter.PickedTrackingIter()) {
mTrackingTimeouts.Insert(timeout,
mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
: Timeouts::SortBy::TimeWhen);
} else {
mNormalTimeouts.Insert(timeout,
mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
: Timeouts::SortBy::TimeWhen);
}
mTimeouts.Insert(timeout,
mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
: Timeouts::SortBy::TimeWhen);
}
// Check to see if we have run out of time to execute timeout handlers.
@ -963,8 +889,7 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
// however, that the last timeout handler suspended the window. If
// that happened then we must skip this step.
if (!mWindow.IsSuspended()) {
RefPtr<Timeout> timeout = runIter.Next();
if (timeout) {
if (next) {
// If we ran out of execution budget we need to force a
// reschedule. By cancelling the executor we will not run
// immediately, but instead reschedule to the minimum
@ -973,7 +898,7 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
mExecutor->Cancel();
}
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(timeout->When(), now));
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(next->When(), now));
}
}
break;
@ -1056,8 +981,7 @@ TimeoutManager::ClearAllTimeouts()
});
// Clear out our list
mNormalTimeouts.Clear();
mTrackingTimeouts.Clear();
mTimeouts.Clear();
}
void
@ -1149,8 +1073,7 @@ TimeoutManager::Resume()
MaybeStartThrottleTimeout();
}
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
Timeout* nextTimeout = iter.Next();
Timeout* nextTimeout = mTimeouts.GetFirst();
if (nextTimeout) {
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextTimeout->When()));
}
@ -1202,8 +1125,7 @@ TimeoutManager::UpdateBackgroundState()
// changed. Only do this if the window is not suspended and we
// actually have a timeout.
if (!mWindow.IsSuspended()) {
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
Timeout* nextTimeout = iter.Next();
Timeout* nextTimeout = mTimeouts.GetFirst();
if (nextTimeout) {
mExecutor->Cancel();
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextTimeout->When()));
@ -1211,14 +1133,6 @@ TimeoutManager::UpdateBackgroundState()
}
}
bool
TimeoutManager::IsTimeoutTracking(uint32_t aTimeoutId)
{
return mTrackingTimeouts.ForEachAbortable([&](Timeout* aTimeout) {
return aTimeout->mTimeoutId == aTimeoutId;
});
}
namespace {
class ThrottleTimeoutsCallback final : public nsITimerCallback

Просмотреть файл

@ -21,7 +21,6 @@ class PerformanceCounter;
namespace dom {
class OrderedTimeoutIterator;
class TimeoutExecutor;
// This class manages the timeouts in a Window's setTimeout/setInterval pool.
@ -40,8 +39,7 @@ public:
bool HasTimeouts() const
{
return !mNormalTimeouts.IsEmpty() ||
!mTrackingTimeouts.IsEmpty();
return !mTimeouts.IsEmpty();
}
nsresult SetTimeout(nsITimeoutHandler* aHandler,
@ -81,9 +79,6 @@ public:
// Initialize TimeoutManager before the first time it is accessed.
static void Initialize();
// Exposed only for testing
bool IsTimeoutTracking(uint32_t aTimeoutId);
// The document finished loading
void OnDocumentLoaded();
void StartThrottlingTimeouts();
@ -93,19 +88,7 @@ public:
template <class Callable>
void ForEachUnorderedTimeout(Callable c)
{
mNormalTimeouts.ForEach(c);
mTrackingTimeouts.ForEach(c);
}
// Run some code for each Timeout in our list, but let the callback cancel the
// iteration by returning true. Note that this function doesn't guarantee
// that Timeouts are iterated in any particular order.
template <class Callable>
void ForEachUnorderedTimeoutAbortable(Callable c)
{
if (!mNormalTimeouts.ForEachAbortable(c)) {
mTrackingTimeouts.ForEachAbortable(c);
}
mTimeouts.ForEach(c);
}
void BeginSyncOperation();
@ -204,8 +187,6 @@ private:
return false;
}
friend class OrderedTimeoutIterator;
private:
// The TimeoutManager that owns this Timeouts structure. This is
// mainly used to call state inspecting methods like IsValidFiringId().
@ -218,8 +199,6 @@ private:
TimeoutList mTimeoutList;
};
friend class OrderedTimeoutIterator;
// Each nsGlobalWindowInner object has a TimeoutManager member. This reference
// points to that holder object.
nsGlobalWindowInner& mWindow;
@ -228,9 +207,7 @@ private:
// it must be a separate ref-counted object.
RefPtr<TimeoutExecutor> mExecutor;
// The list of timeouts coming from non-tracking scripts.
Timeouts mNormalTimeouts;
// The list of timeouts coming from scripts on the tracking protection list.
Timeouts mTrackingTimeouts;
Timeouts mTimeouts;
uint32_t mTimeoutIdCounter;
uint32_t mNextFiringId;
AutoTArray<uint32_t, 2> mFiringIdStack;

Просмотреть файл

@ -4250,21 +4250,6 @@ nsDOMWindowUtils::GetGpuProcessPid(int32_t* aPid)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::IsTimeoutTracking(uint32_t aTimeoutId, bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = false;
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
nsCOMPtr<nsPIDOMWindowInner> innerWindow = window->GetCurrentInnerWindow();
NS_ENSURE_STATE(innerWindow);
*aResult = innerWindow->TimeoutManager().IsTimeoutTracking(aTimeoutId);
return NS_OK;
}
struct StateTableEntry
{
const char* mStateString;
@ -4493,4 +4478,3 @@ nsDOMWindowUtils::IsCssPropertyRecordedInUseCounter(const nsACString& aPropName,
&knownProp);
return knownProp ? NS_OK : NS_ERROR_FAILURE;
}

Просмотреть файл

@ -3,25 +3,15 @@
<body>
<script>
let count = 0;
let last_timer_set = 0;
let last_timer_observed = 0;
function cb(timer_observed) {
if (timer_observed > last_timer_observed) {
// In order to make the test more efficient, we don't use the SimpleTest
// ok() function to avoid generating one test assertion per one of these
// checks. We only send a message to the parent which fails the test if
// we detect out of order firing of timeouts.
window.parent.postMessage('OUT_OF_ORDER', '*');
}
last_timer_observed = timer_observed;
function cb() {
count += 1;
// Notify our parent that we are ready once the timer flood has
// warmed up.
if (count === 10000) {
window.parent.postMessage('STARTED', '*');
}
last_timer_set = setTimeout(cb.bind(last_timer_set), 0);
last_timer_set = setTimeout(cb.bind(last_timer_set), 0);
setTimeout(cb, 0);
setTimeout(cb, 0);
}
addEventListener('load', cb);
</script>

Просмотреть файл

@ -22,24 +22,15 @@ function onLoad() {
});
}
function setPrefs() {
// Put timeouts randomly in the tracking or normal buffer. We do this in order to
// test to ensure that by default, this will not change the scheduling of timeouts.
return SpecialPowers.pushPrefEnv({"set": [["dom.timeout_bucketing_strategy", 3]]});
}
// Create a frame that executes a timer flood. The frame signals
// that is ready once the flood has had a chance to warm up.
function withFloodFrame() {
return new Promise((resolve, reject) => {
return new Promise(resolve => {
let frame = document.createElement('iframe');
addEventListener('message', function onMsg(evt) {
if (evt.data === 'STARTED') {
removeEventListener('message', onMsg);
resolve(frame);
} else if (evt.data == 'OUT_OF_ORDER') {
ok(false, "Out of order timeout observed");
reject();
}
});
frame.src = 'file_timer_flood.html';
@ -86,9 +77,7 @@ function testRequestAnimationFrame() {
let floodFrame;
onLoad()
.then(setPrefs)
.then(_ => {
onLoad().then(_ => {
// Start a timer flood in a frame.
return withFloodFrame();
}).then(frame => {
@ -122,8 +111,6 @@ onLoad()
ok(true, 'completed tests without timing out');
floodFrame.remove();
SimpleTest.finish();
}).catch(_ => {
SimpleTest.finish();
});
</script>
</pre>

Просмотреть файл

@ -1876,12 +1876,6 @@ interface nsIDOMWindowUtils : nsISupports {
*/
readonly attribute int32_t gpuProcessPid;
/**
* Returns true if the given timeout ID is in the list of tracking
* timeouts.
*/
boolean isTimeoutTracking(in unsigned long timeoutId);
/**
* Adds an EventStates bit to the element.
*

Просмотреть файл

@ -13179,51 +13179,6 @@
"keyed": true,
"description": "Measures the number of milliseconds we spend waiting for sync message manager IPC messages to finish sending, keyed by message name. Note: only messages that wait for more than 500 microseconds are included in this probe."
},
"TIMEOUT_EXECUTION_FG_MS":
{
"record_in_processes": ["main", "content"],
"alert_emails": ["farre@mozilla.com"],
"bug_numbers": [1355480],
"expires_in_version": "61",
"kind": "exponential",
"high": 1000,
"n_buckets": 20,
"description": "Time in ms used to execute callbacks from setTimeout/setInterval, when the script belongs to a tab in the foreground and the script is not on the tracking list. Multiple events are aggregated over a 1s interval."
},
"TIMEOUT_EXECUTION_FG_TRACKING_MS":
{
"record_in_processes": ["main", "content"],
"alert_emails": ["farre@mozilla.com"],
"bug_numbers": [1355480],
"expires_in_version": "61",
"kind": "exponential",
"high": 1000,
"n_buckets": 20,
"description": "Time in ms used to execute callbacks from setTimeout/setInterval, when the script belongs to a tab in the foreground and the script is on the tracking list. Multiple events are aggregated over a 1s interval."
},
"TIMEOUT_EXECUTION_BG_MS":
{
"record_in_processes": ["main", "content"],
"alert_emails": ["farre@mozilla.com"],
"bug_numbers": [1355480],
"expires_in_version": "61",
"kind": "exponential",
"high": 1000,
"n_buckets": 20,
"description": "Time in ms used to execute callbacks from setTimeout/setInterval, when the script belongs to a tab in the background and the script is not on the tracking list. Multiple events are aggregated over a 1s interval."
},
"TIMEOUT_EXECUTION_BG_TRACKING_MS":
{
"record_in_processes": ["main", "content"],
"alert_emails": ["farre@mozilla.com"],
"bug_numbers": [1355480],
"expires_in_version": "61",
"kind": "exponential",
"low": 1,
"high": 1000,
"n_buckets": 10,
"description": "Time in ms used to execute callbacks from setTimeout/setInterval, when the script belongs to a tab in the background and the script is on the tracking list. Multiple events are aggregated over a 1s interval."
},
"TIME_TO_DOM_LOADING_MS": {
"record_in_processes": ["content"],
"alert_emails": ["hbambas@mozilla.com", "vgosu@mozilla.com", "jduell@mozilla.com"],

Просмотреть файл

@ -42,7 +42,6 @@ support-files =
!/toolkit/components/url-classifier/tests/mochitest/bad.css
!/toolkit/components/url-classifier/tests/mochitest/bad.css^headers^
!/toolkit/components/url-classifier/tests/mochitest/gethashFrame.html
!/toolkit/components/url-classifier/tests/mochitest/tracker.js
!/toolkit/components/url-classifier/tests/mochitest/seek.webm
!/toolkit/components/url-classifier/tests/mochitest/cache.sjs

Просмотреть файл

@ -32,17 +32,6 @@ function checkLoads() {
return;
}
let dwu = window.parent.SpecialPowers.getDOMWindowUtils(window);
let timer1 = window.setTimeout(function() {}, 0);
window.parent.ok(!dwu.isTimeoutTracking(timer1),
"Timeout set from main script should not be considered as tracking");
/* global getTrackerTimeout */
let timer2 = getTrackerTimeout();
window.parent.ok(dwu.isTimeoutTracking(timer2),
"Timeout set from included script should be considered as tracking");
window.clearTimeout(timer1);
window.clearTimeout(timer2);
// End (parent) test.
window.parent.SimpleTest.finish();
}
@ -52,9 +41,6 @@ function checkLoads() {
<!-- Try loading from a malware javascript URI -->
<script type="text/javascript" src="http://malware.example.com/tests/toolkit/components/url-classifier/tests/mochitest/evil.js"></script>
<!-- Try loading from a tracker javascript URI -->
<script type="text/javascript" src="http://tracking.example.com/tests/toolkit/components/url-classifier/tests/mochitest/tracker.js"></script>
<!-- Try loading from an uwanted software css URI -->
<link rel="stylesheet" type="text/css" href="http://unwanted.example.com/tests/toolkit/components/url-classifier/tests/mochitest/evil.css"></link>

Просмотреть файл

@ -30,7 +30,6 @@ support-files =
bad.css^headers^
gethash.sjs
gethashFrame.html
tracker.js
seek.webm
cache.sjs

Просмотреть файл

@ -1,3 +0,0 @@
function getTrackerTimeout() {
return window.setTimeout(function() {}, 0);
}