mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 00:35:44 +00:00
7326630b5d
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.
113 lines
3.2 KiB
C++
113 lines
3.2 KiB
C++
/* -*- 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"
|
|
#include "nsITimeoutHandler.h"
|
|
#include "nsITimer.h"
|
|
#include "mozilla/dom/TimeoutManager.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
Timeout::Timeout()
|
|
: mCleared(false),
|
|
mRunning(false),
|
|
mIsInterval(false),
|
|
mReason(Reason::eTimeoutOrInterval),
|
|
mTimeoutId(0),
|
|
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)
|
|
|
|
namespace {
|
|
|
|
void
|
|
TimerCallback(nsITimer*, void* aClosure)
|
|
{
|
|
RefPtr<Timeout> timeout = (Timeout*)aClosure;
|
|
timeout->mWindow->AsInner()->TimeoutManager().RunTimeout(timeout);
|
|
}
|
|
|
|
void
|
|
TimerNameCallback(nsITimer* aTimer, void* aClosure, char* aBuf, size_t aLen)
|
|
{
|
|
RefPtr<Timeout> timeout = (Timeout*)aClosure;
|
|
|
|
const char* filename;
|
|
uint32_t lineNum, column;
|
|
timeout->mScriptHandler->GetLocation(&filename, &lineNum, &column);
|
|
snprintf(aBuf, aLen, "[content] %s:%u:%u", filename, lineNum, column);
|
|
}
|
|
|
|
} // 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);
|
|
}
|
|
|
|
// Return true if this timeout has a refcount of aCount. This is used to check
|
|
// that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
|
|
#ifdef DEBUG
|
|
bool
|
|
Timeout::HasRefCnt(uint32_t aCount) const
|
|
{
|
|
return mRefCnt.get() == aCount;
|
|
}
|
|
#endif // DEBUG
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|