2016-08-22 15:52:19 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
#include "Timeout.h"
|
|
|
|
|
|
|
|
#include "nsGlobalWindow.h"
|
2016-10-05 15:26:08 +03:00
|
|
|
#include "nsITimeoutHandler.h"
|
2016-08-22 15:52:19 +03:00
|
|
|
#include "nsITimer.h"
|
2016-12-03 01:22:48 +03:00
|
|
|
#include "mozilla/dom/TimeoutManager.h"
|
2016-08-22 15:52:19 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
Timeout::Timeout()
|
|
|
|
: mCleared(false),
|
|
|
|
mRunning(false),
|
|
|
|
mIsInterval(false),
|
2016-12-22 06:34:52 +03:00
|
|
|
mIsTracking(false),
|
2016-08-22 16:07:50 +03:00
|
|
|
mReason(Reason::eTimeoutOrInterval),
|
|
|
|
mTimeoutId(0),
|
2016-08-22 15:52:19 +03:00
|
|
|
mInterval(0),
|
|
|
|
mFiringDepth(0),
|
|
|
|
mNestingLevel(0),
|
|
|
|
mPopupState(openAllowed)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(Timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
Timeout::~Timeout()
|
|
|
|
{
|
|
|
|
if (mTimer) {
|
|
|
|
mTimer->Cancel();
|
|
|
|
mTimer = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_COUNT_DTOR(Timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(Timeout)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Timeout)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptHandler)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Timeout)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Timeout, AddRef)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Timeout, Release)
|
|
|
|
|
2016-11-07 23:30:17 +03:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void
|
|
|
|
TimerCallback(nsITimer*, void* aClosure)
|
2016-08-22 15:52:19 +03:00
|
|
|
{
|
2016-11-07 23:30:17 +03:00
|
|
|
RefPtr<Timeout> timeout = (Timeout*)aClosure;
|
2016-12-03 01:22:48 +03:00
|
|
|
timeout->mWindow->AsInner()->TimeoutManager().RunTimeout(timeout);
|
2016-08-22 15:52:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-01-19 02:37:30 +03:00
|
|
|
TimerNameCallback(nsITimer* aTimer, bool aAnonymize, void* aClosure,
|
|
|
|
char* aBuf, size_t aLen)
|
2016-08-22 15:52:19 +03:00
|
|
|
{
|
|
|
|
RefPtr<Timeout> timeout = (Timeout*)aClosure;
|
|
|
|
|
2017-01-19 02:37:30 +03:00
|
|
|
// Filename and line-number information is privacy sensitive. If we're
|
|
|
|
// supposed to anonymize the data, don't include it.
|
|
|
|
if (aAnonymize) {
|
|
|
|
if (timeout->mIsInterval) {
|
|
|
|
snprintf(aBuf, aLen, "setInterval");
|
|
|
|
} else {
|
|
|
|
snprintf(aBuf, aLen, "setTimeout");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-22 15:52:19 +03:00
|
|
|
const char* filename;
|
|
|
|
uint32_t lineNum, column;
|
|
|
|
timeout->mScriptHandler->GetLocation(&filename, &lineNum, &column);
|
|
|
|
snprintf(aBuf, aLen, "[content] %s:%u:%u", filename, lineNum, column);
|
|
|
|
}
|
|
|
|
|
2016-11-07 23:30:17 +03:00
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
Timeout::InitTimer(nsIEventTarget* aTarget, uint32_t aDelay)
|
|
|
|
{
|
|
|
|
// If the given target does not match the timer's current target
|
|
|
|
// then we need to override it before the Init. Note that GetTarget()
|
|
|
|
// will return the current thread after setting the target to nullptr.
|
|
|
|
// So we need to special case the nullptr target comparison.
|
|
|
|
nsCOMPtr<nsIEventTarget> currentTarget;
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(mTimer->GetTarget(getter_AddRefs(currentTarget)));
|
|
|
|
if ((aTarget && currentTarget != aTarget) ||
|
|
|
|
(!aTarget && currentTarget != NS_GetCurrentThread())) {
|
|
|
|
// Always call Cancel() in case we are re-using a timer. Otherwise
|
|
|
|
// the subsequent SetTarget() may fail.
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(mTimer->Cancel());
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(mTimer->SetTarget(aTarget));
|
|
|
|
}
|
|
|
|
|
|
|
|
return mTimer->InitWithNameableFuncCallback(
|
|
|
|
TimerCallback, this, aDelay, nsITimer::TYPE_ONE_SHOT, TimerNameCallback);
|
|
|
|
}
|
2016-08-22 15:52:19 +03:00
|
|
|
|
Bug 1312514 - Part 1: Split tracking and non-tracking timeouts into two separate lists; r=bkelly
This will allow us to schedule these timers differently in the future.
This patch only performs the refactoring, and is not intended to change
any behavior. Specifically, this patch doesn't change the order in
which timeouts are fired -- they should still all be fired according to
the mWhen field.
The implementation works by splitting timeout storage per window into
two Timeouts objects, mNormalTimeouts and mTrackingTimeouts. The ForEach
helper methods are extended to deal with both of these objects, and as a
result, most of the algorithms operating on the list of timeouts work
correctly without any modification, with the notable exception of
RunTimeout.
In RunTimeout(), the order in which Timeout objects are processed does
matter, so for that case we use the OrderedTimeoutIterator class to
iterate over both linked lists simultaneously in the mWhen order. Also,
inserting the dummy timeout when running the timeouts is only necessary
for the linked list where the last expired timeout is coming from, so we
only inject the dummy timer into the corresponding list, therefore we
remember which list we picked the last expired timeout from when
looking for it.
2016-12-16 00:17:38 +03:00
|
|
|
// Return true if this timeout has a refcount of aCount. This is used to check
|
2016-08-22 15:52:19 +03:00
|
|
|
// that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool
|
Bug 1312514 - Part 1: Split tracking and non-tracking timeouts into two separate lists; r=bkelly
This will allow us to schedule these timers differently in the future.
This patch only performs the refactoring, and is not intended to change
any behavior. Specifically, this patch doesn't change the order in
which timeouts are fired -- they should still all be fired according to
the mWhen field.
The implementation works by splitting timeout storage per window into
two Timeouts objects, mNormalTimeouts and mTrackingTimeouts. The ForEach
helper methods are extended to deal with both of these objects, and as a
result, most of the algorithms operating on the list of timeouts work
correctly without any modification, with the notable exception of
RunTimeout.
In RunTimeout(), the order in which Timeout objects are processed does
matter, so for that case we use the OrderedTimeoutIterator class to
iterate over both linked lists simultaneously in the mWhen order. Also,
inserting the dummy timeout when running the timeouts is only necessary
for the linked list where the last expired timeout is coming from, so we
only inject the dummy timer into the corresponding list, therefore we
remember which list we picked the last expired timeout from when
looking for it.
2016-12-16 00:17:38 +03:00
|
|
|
Timeout::HasRefCnt(uint32_t aCount) const
|
2016-08-22 15:52:19 +03:00
|
|
|
{
|
Bug 1312514 - Part 1: Split tracking and non-tracking timeouts into two separate lists; r=bkelly
This will allow us to schedule these timers differently in the future.
This patch only performs the refactoring, and is not intended to change
any behavior. Specifically, this patch doesn't change the order in
which timeouts are fired -- they should still all be fired according to
the mWhen field.
The implementation works by splitting timeout storage per window into
two Timeouts objects, mNormalTimeouts and mTrackingTimeouts. The ForEach
helper methods are extended to deal with both of these objects, and as a
result, most of the algorithms operating on the list of timeouts work
correctly without any modification, with the notable exception of
RunTimeout.
In RunTimeout(), the order in which Timeout objects are processed does
matter, so for that case we use the OrderedTimeoutIterator class to
iterate over both linked lists simultaneously in the mWhen order. Also,
inserting the dummy timeout when running the timeouts is only necessary
for the linked list where the last expired timeout is coming from, so we
only inject the dummy timer into the corresponding list, therefore we
remember which list we picked the last expired timeout from when
looking for it.
2016-12-16 00:17:38 +03:00
|
|
|
return mRefCnt.get() == aCount;
|
2016-08-22 15:52:19 +03:00
|
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
|
2017-01-10 19:08:18 +03:00
|
|
|
void
|
|
|
|
Timeout::SetWhenOrTimeRemaining(const TimeStamp& aBaseTime,
|
|
|
|
const TimeDuration& aDelay)
|
|
|
|
{
|
|
|
|
// This must not be called on dummy timeouts. Instead use SetDummyWhen().
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(mWindow);
|
|
|
|
|
|
|
|
// If we are frozen simply set mTimeRemaining to be the "time remaining" in
|
|
|
|
// the timeout (i.e., the interval itself). This will be used to create a
|
|
|
|
// new mWhen time when the window is thawed. The end effect is that time does
|
|
|
|
// not appear to pass for frozen windows.
|
|
|
|
if (mWindow->IsFrozen()) {
|
|
|
|
mWhen = TimeStamp();
|
|
|
|
mTimeRemaining = aDelay;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since we are not frozen we must set a precise mWhen target wakeup
|
|
|
|
// time. Even if we are suspended we want to use this target time so
|
|
|
|
// that it appears time passes while suspended.
|
|
|
|
mWhen = aBaseTime + aDelay;
|
|
|
|
mTimeRemaining = TimeDuration(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Timeout::SetDummyWhen(const TimeStamp& aWhen)
|
|
|
|
{
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mWindow);
|
|
|
|
mWhen = aWhen;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TimeStamp&
|
|
|
|
Timeout::When() const
|
|
|
|
{
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mWhen.IsNull());
|
|
|
|
// Note, mWindow->IsFrozen() can be true here. The Freeze() method calls
|
|
|
|
// When() to calculate the delay to populate mTimeRemaining.
|
|
|
|
return mWhen;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TimeDuration&
|
|
|
|
Timeout::TimeRemaining() const
|
|
|
|
{
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(mWhen.IsNull());
|
|
|
|
// Note, mWindow->IsFrozen() can be false here. The Thaw() method calls
|
|
|
|
// TimeRemaining() to calculate the new When() value.
|
|
|
|
return mTimeRemaining;
|
|
|
|
}
|
|
|
|
|
2016-08-22 15:52:19 +03:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|