summaryrefslogtreecommitdiff
path: root/xpcom/threads/nsTimerImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/nsTimerImpl.cpp')
-rw-r--r--xpcom/threads/nsTimerImpl.cpp354
1 files changed, 234 insertions, 120 deletions
diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp
index 5a624794d..9fa8987e0 100644
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -10,12 +10,18 @@
#include "nsThreadManager.h"
#include "nsThreadUtils.h"
#include "plarena.h"
+#include "pratom.h"
#include "GoannaProfiler.h"
+#include "mozilla/Atomics.h"
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+using mozilla::Atomic;
using mozilla::TimeDuration;
using mozilla::TimeStamp;
-static int32_t gGenerator = 0;
+static Atomic<int32_t> gGenerator;
static TimerThread* gThread = nullptr;
#ifdef DEBUG_TIMERS
@@ -23,9 +29,10 @@ static TimerThread* gThread = nullptr;
PRLogModuleInfo*
GetTimerLog()
{
- static PRLogModuleInfo *sLog;
- if (!sLog)
+ static PRLogModuleInfo* sLog;
+ if (!sLog) {
sLog = PR_NewLogModule("nsTimerImpl");
+ }
return sLog;
}
@@ -37,16 +44,17 @@ double nsTimerImpl::sDeltaNum = 0;
static void
myNS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
- double *meanResult, double *stdDevResult)
+ double* meanResult, double* stdDevResult)
{
double mean = 0.0, var = 0.0, stdDev = 0.0;
if (n > 0.0 && sumOfValues >= 0) {
mean = sumOfValues / n;
double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
- if (temp < 0.0 || n <= 1)
+ if (temp < 0.0 || n <= 1) {
var = 0.0;
- else
+ } else {
var = temp / (n * (n - 1));
+ }
// for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
stdDev = var != 0.0 ? sqrt(var) : 0.0;
}
@@ -74,7 +82,8 @@ namespace {
class TimerEventAllocator
{
private:
- struct FreeEntry {
+ struct FreeEntry
+ {
FreeEntry* mNext;
};
@@ -84,8 +93,8 @@ private:
public:
TimerEventAllocator()
- : mFirstFree(nullptr),
- mMonitor("TimerEventAllocator")
+ : mFirstFree(nullptr)
+ , mMonitor("TimerEventAllocator")
{
PL_InitArenaPool(&mPool, "TimerEventPool", 4096, /* align = */ 0);
}
@@ -101,7 +110,8 @@ public:
} // anonymous namespace
-class nsTimerEvent : public nsRunnable {
+class nsTimerEvent : public nsRunnable
+{
public:
NS_IMETHOD Run();
@@ -114,7 +124,7 @@ public:
MOZ_ASSERT(gThread->IsOnTimerThread(),
"nsTimer must always be allocated on the timer thread");
- PR_ATOMIC_INCREMENT(&sAllocatorUsers);
+ sAllocatorUsers++;
}
#ifdef DEBUG_TIMERS
@@ -125,11 +135,13 @@ public:
static void Shutdown();
static void DeleteAllocatorIfNeeded();
- static void* operator new(size_t size) CPP_THROW_NEW {
- return sAllocator->Alloc(size);
+ static void* operator new(size_t aSize) CPP_THROW_NEW
+ {
+ return sAllocator->Alloc(aSize);
}
- void operator delete(void* p) {
- sAllocator->Free(p);
+ void operator delete(void* aPtr)
+ {
+ sAllocator->Free(aPtr);
DeleteAllocatorIfNeeded();
}
@@ -145,29 +157,31 @@ public:
}
private:
- ~nsTimerEvent() {
+ ~nsTimerEvent()
+ {
MOZ_COUNT_DTOR(nsTimerEvent);
MOZ_ASSERT(!sCanDeleteAllocator || sAllocatorUsers > 0,
"This will result in us attempting to deallocate the nsTimerEvent allocator twice");
- PR_ATOMIC_DECREMENT(&sAllocatorUsers);
+ sAllocatorUsers--;
}
nsRefPtr<nsTimerImpl> mTimer;
int32_t mGeneration;
static TimerEventAllocator* sAllocator;
- static int32_t sAllocatorUsers;
+ static Atomic<int32_t> sAllocatorUsers;
static bool sCanDeleteAllocator;
};
TimerEventAllocator* nsTimerEvent::sAllocator = nullptr;
-int32_t nsTimerEvent::sAllocatorUsers = 0;
+Atomic<int32_t> nsTimerEvent::sAllocatorUsers;
bool nsTimerEvent::sCanDeleteAllocator = false;
namespace {
-void* TimerEventAllocator::Alloc(size_t aSize)
+void*
+TimerEventAllocator::Alloc(size_t aSize)
{
MOZ_ASSERT(aSize == sizeof(nsTimerEvent));
@@ -177,17 +191,18 @@ void* TimerEventAllocator::Alloc(size_t aSize)
if (mFirstFree) {
p = mFirstFree;
mFirstFree = mFirstFree->mNext;
- }
- else {
+ } else {
PL_ARENA_ALLOCATE(p, &mPool, aSize);
- if (!p)
+ if (!p) {
return nullptr;
+ }
}
return p;
}
-void TimerEventAllocator::Free(void* aPtr)
+void
+TimerEventAllocator::Free(void* aPtr)
{
mozilla::MonitorAutoLock lock(mMonitor);
@@ -199,15 +214,16 @@ void TimerEventAllocator::Free(void* aPtr)
} // anonymous namespace
-NS_IMPL_THREADSAFE_QUERY_INTERFACE1(nsTimerImpl, nsITimer)
-NS_IMPL_THREADSAFE_ADDREF(nsTimerImpl)
+NS_IMPL_QUERY_INTERFACE(nsTimerImpl, nsITimer)
+NS_IMPL_ADDREF(nsTimerImpl)
-NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Release(void)
+NS_IMETHODIMP_(MozExternalRefCountType)
+nsTimerImpl::Release(void)
{
nsrefcnt count;
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
- count = NS_AtomicDecrementRefcnt(mRefCnt);
+ count = --mRefCnt;
NS_LOG_RELEASE(this, count, "nsTimerImpl");
if (count == 0) {
mRefCnt = 1; /* stabilize */
@@ -251,8 +267,9 @@ NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Release(void)
mCanceled = true;
MOZ_ASSERT(gThread, "Armed timer exists after the thread timer stopped.");
- if (NS_SUCCEEDED(gThread->RemoveTimer(this)))
+ if (NS_SUCCEEDED(gThread->RemoveTimer(this))) {
return 0;
+ }
}
return count;
@@ -287,7 +304,9 @@ nsTimerImpl::Startup()
nsTimerEvent::Init();
gThread = new TimerThread();
- if (!gThread) return NS_ERROR_OUT_OF_MEMORY;
+ if (!gThread) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
NS_ADDREF(gThread);
rv = gThread->InitLocks();
@@ -299,20 +318,25 @@ nsTimerImpl::Startup()
return rv;
}
-void nsTimerImpl::Shutdown()
+void
+nsTimerImpl::Shutdown()
{
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
double mean = 0, stddev = 0;
myNS_MeanAndStdDev(sDeltaNum, sDeltaSum, sDeltaSumSquared, &mean, &stddev);
- PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n", sDeltaNum, sDeltaSum, sDeltaSumSquared));
- PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("mean: %fms, stddev: %fms\n", mean, stddev));
+ PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
+ ("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n",
+ sDeltaNum, sDeltaSum, sDeltaSumSquared));
+ PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
+ ("mean: %fms, stddev: %fms\n", mean, stddev));
}
#endif
- if (!gThread)
+ if (!gThread) {
return;
+ }
gThread->Shutdown();
NS_RELEASE(gThread);
@@ -321,18 +345,23 @@ void nsTimerImpl::Shutdown()
}
-nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
+nsresult
+nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
{
nsresult rv;
- NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED);
+ if (NS_WARN_IF(!gThread)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
if (!mEventTarget) {
NS_ERROR("mEventTarget is NULL");
return NS_ERROR_NOT_INITIALIZED;
}
rv = gThread->Init();
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
/**
* In case of re-Init, both with and without a preceding Cancel, clear the
@@ -348,11 +377,12 @@ nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
* be cleared by another CPU whose store hasn't reached our CPU's cache),
* because RemoveTimer is idempotent.
*/
- if (mArmed)
+ if (mArmed) {
gThread->RemoveTimer(this);
+ }
mCanceled = false;
mTimeout = TimeStamp();
- mGeneration = PR_ATOMIC_INCREMENT(&gGenerator);
+ mGeneration = gGenerator++;
mType = (uint8_t)aType;
SetDelayInternal(aDelay);
@@ -360,13 +390,16 @@ nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay)
return gThread->AddTimer(this);
}
-NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
- void *aClosure,
- uint32_t aDelay,
- uint32_t aType)
+NS_IMETHODIMP
+nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
+ void* aClosure,
+ uint32_t aDelay,
+ uint32_t aType)
{
- NS_ENSURE_ARG_POINTER(aFunc);
-
+ if (NS_WARN_IF(!aFunc)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
ReleaseCallback();
mCallbackType = CALLBACK_TYPE_FUNC;
mCallback.c = aFunc;
@@ -375,11 +408,14 @@ NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
return InitCommon(aType, aDelay);
}
-NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback,
- uint32_t aDelay,
- uint32_t aType)
+NS_IMETHODIMP
+nsTimerImpl::InitWithCallback(nsITimerCallback* aCallback,
+ uint32_t aDelay,
+ uint32_t aType)
{
- NS_ENSURE_ARG_POINTER(aCallback);
+ if (NS_WARN_IF(!aCallback)) {
+ return NS_ERROR_INVALID_ARG;
+ }
ReleaseCallback();
mCallbackType = CALLBACK_TYPE_INTERFACE;
@@ -389,11 +425,12 @@ NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback,
return InitCommon(aType, aDelay);
}
-NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver,
- uint32_t aDelay,
- uint32_t aType)
+NS_IMETHODIMP
+nsTimerImpl::Init(nsIObserver* aObserver, uint32_t aDelay, uint32_t aType)
{
- NS_ENSURE_ARG_POINTER(aObserver);
+ if (NS_WARN_IF(!aObserver)) {
+ return NS_ERROR_INVALID_ARG;
+ }
ReleaseCallback();
mCallbackType = CALLBACK_TYPE_OBSERVER;
@@ -403,19 +440,22 @@ NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver,
return InitCommon(aType, aDelay);
}
-NS_IMETHODIMP nsTimerImpl::Cancel()
+NS_IMETHODIMP
+nsTimerImpl::Cancel()
{
mCanceled = true;
- if (gThread)
+ if (gThread) {
gThread->RemoveTimer(this);
+ }
ReleaseCallback();
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::SetDelay(uint32_t aDelay)
+NS_IMETHODIMP
+nsTimerImpl::SetDelay(uint32_t aDelay)
{
if (mCallbackType == CALLBACK_TYPE_UNKNOWN && mType == TYPE_ONE_SHOT) {
// This may happen if someone tries to re-use a one-shot timer
@@ -425,21 +465,30 @@ NS_IMETHODIMP nsTimerImpl::SetDelay(uint32_t aDelay)
return NS_ERROR_NOT_INITIALIZED;
}
+ // If we're already repeating precisely, update mTimeout now so that the
+ // new delay takes effect in the future.
+ if (!mTimeout.IsNull() && mType == TYPE_REPEATING_PRECISE) {
+ mTimeout = TimeStamp::Now();
+ }
+
SetDelayInternal(aDelay);
- if (!mFiring && gThread)
+ if (!mFiring && gThread) {
gThread->TimerDelayChanged(this);
+ }
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::GetDelay(uint32_t* aDelay)
+NS_IMETHODIMP
+nsTimerImpl::GetDelay(uint32_t* aDelay)
{
*aDelay = mDelay;
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::SetType(uint32_t aType)
+NS_IMETHODIMP
+nsTimerImpl::SetType(uint32_t aType)
{
mType = (uint8_t)aType;
// XXX if this is called, we should change the actual type.. this could effect
@@ -448,62 +497,87 @@ NS_IMETHODIMP nsTimerImpl::SetType(uint32_t aType)
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::GetType(uint32_t* aType)
+NS_IMETHODIMP
+nsTimerImpl::GetType(uint32_t* aType)
{
*aType = mType;
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::GetClosure(void** aClosure)
+NS_IMETHODIMP
+nsTimerImpl::GetClosure(void** aClosure)
{
*aClosure = mClosure;
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::GetCallback(nsITimerCallback **aCallback)
+NS_IMETHODIMP
+nsTimerImpl::GetCallback(nsITimerCallback** aCallback)
{
- if (mCallbackType == CALLBACK_TYPE_INTERFACE)
+ if (mCallbackType == CALLBACK_TYPE_INTERFACE) {
NS_IF_ADDREF(*aCallback = mCallback.i);
- else if (mTimerCallbackWhileFiring)
+ } else if (mTimerCallbackWhileFiring) {
NS_ADDREF(*aCallback = mTimerCallbackWhileFiring);
- else
+ } else {
*aCallback = nullptr;
+ }
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::GetTarget(nsIEventTarget** aTarget)
+NS_IMETHODIMP
+nsTimerImpl::GetTarget(nsIEventTarget** aTarget)
{
NS_IF_ADDREF(*aTarget = mEventTarget);
return NS_OK;
}
-NS_IMETHODIMP nsTimerImpl::SetTarget(nsIEventTarget* aTarget)
+NS_IMETHODIMP
+nsTimerImpl::SetTarget(nsIEventTarget* aTarget)
{
- NS_ENSURE_TRUE(mCallbackType == CALLBACK_TYPE_UNKNOWN,
- NS_ERROR_ALREADY_INITIALIZED);
+ if (NS_WARN_IF(mCallbackType != CALLBACK_TYPE_UNKNOWN)) {
+ return NS_ERROR_ALREADY_INITIALIZED;
+ }
- if (aTarget)
+ if (aTarget) {
mEventTarget = aTarget;
- else
+ } else {
mEventTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread());
+ }
return NS_OK;
}
-void nsTimerImpl::Fire()
+void
+nsTimerImpl::Fire()
{
- if (mCanceled)
+ if (mCanceled) {
return;
+ }
- PROFILER_LABEL("Timer", "Fire");
+#ifdef MOZ_NUWA_PROCESS
+ if (IsNuwaProcess() && IsNuwaReady()) {
+ // A timer event fired after Nuwa frozen can freeze main thread.
+ return;
+ }
+#endif
+
+ PROFILER_LABEL("Timer", "Fire",
+ js::ProfileEntry::Category::OTHER);
+
+#ifdef MOZ_TASK_TRACER
+ // mTracedTask is an instance of FakeTracedTask created by
+ // DispatchTracedTask(). AutoRunFakeTracedTask logs the begin/end time of the
+ // timer/FakeTracedTask instance in ctor/dtor.
+ mozilla::tasktracer::AutoRunFakeTracedTask runTracedTask(mTracedTask);
+#endif
- TimeStamp now = TimeStamp::Now();
#ifdef DEBUG_TIMERS
+ TimeStamp now = TimeStamp::Now();
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
TimeDuration a = now - mStart; // actual delay in intervals
TimeDuration b = TimeDuration::FromMilliseconds(mDelay); // expected delay in intervals
@@ -513,10 +587,16 @@ void nsTimerImpl::Fire()
sDeltaSumSquared += double(d) * double(d);
sDeltaNum++;
- PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] expected delay time %4ums\n", this, mDelay));
- PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] actual delay time %fms\n", this, a.ToMilliseconds()));
- PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType));
- PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (int32_t)d : -(int32_t)d));
+ PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
+ ("[this=%p] expected delay time %4ums\n", this, mDelay));
+ PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
+ ("[this=%p] actual delay time %fms\n", this,
+ a.ToMilliseconds()));
+ PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
+ ("[this=%p] (mType is %d) -------\n", this, mType));
+ PR_LOG(GetTimerLog(), PR_LOG_DEBUG,
+ ("[this=%p] delta %4dms\n",
+ this, (a > b) ? (int32_t)d : -(int32_t)d));
mStart = mStart2;
mStart2 = TimeStamp();
@@ -530,18 +610,20 @@ void nsTimerImpl::Fire()
timeout -= TimeDuration::FromMilliseconds(mDelay);
}
- if (mCallbackType == CALLBACK_TYPE_INTERFACE)
+ if (mCallbackType == CALLBACK_TYPE_INTERFACE) {
mTimerCallbackWhileFiring = mCallback.i;
+ }
mFiring = true;
-
+
// Handle callbacks that re-init the timer, but avoid leaking.
// See bug 330128.
CallbackUnion callback = mCallback;
unsigned callbackType = mCallbackType;
- if (callbackType == CALLBACK_TYPE_INTERFACE)
+ if (callbackType == CALLBACK_TYPE_INTERFACE) {
NS_ADDREF(callback.i);
- else if (callbackType == CALLBACK_TYPE_OBSERVER)
+ } else if (callbackType == CALLBACK_TYPE_OBSERVER) {
NS_ADDREF(callback.o);
+ }
ReleaseCallback();
switch (callbackType) {
@@ -556,7 +638,8 @@ void nsTimerImpl::Fire()
NS_TIMER_CALLBACK_TOPIC,
nullptr);
break;
- default:;
+ default:
+ ;
}
// If the callback didn't re-init the timer, and it's not a one-shot timer,
@@ -567,10 +650,11 @@ void nsTimerImpl::Fire()
mCallbackType = callbackType;
} else {
// The timer was a one-shot, or the callback was reinitialized.
- if (callbackType == CALLBACK_TYPE_INTERFACE)
+ if (callbackType == CALLBACK_TYPE_INTERFACE) {
NS_RELEASE(callback.i);
- else if (callbackType == CALLBACK_TYPE_OBSERVER)
+ } else if (callbackType == CALLBACK_TYPE_OBSERVER) {
NS_RELEASE(callback.o);
+ }
}
mFiring = false;
@@ -584,30 +668,36 @@ void nsTimerImpl::Fire()
}
#endif
- // Reschedule repeating timers, but make sure that we aren't armed already
- // (which can happen if the callback reinitialized the timer).
- if (IsRepeating() && !mArmed) {
- if (mType == TYPE_REPEATING_SLACK)
- SetDelayInternal(mDelay); // force mTimeout to be recomputed. For
- // REPEATING_PRECISE_CAN_SKIP timers this has
- // already happened.
- if (gThread)
+ // Reschedule repeating timers, except REPEATING_PRECISE which already did
+ // that in PostTimerEvent, but make sure that we aren't armed already (which
+ // can happen if the callback reinitialized the timer).
+ if (IsRepeating() && mType != TYPE_REPEATING_PRECISE && !mArmed) {
+ if (mType == TYPE_REPEATING_SLACK) {
+ SetDelayInternal(mDelay); // force mTimeout to be recomputed. For
+ }
+ // REPEATING_PRECISE_CAN_SKIP timers this has
+ // already happened.
+ if (gThread) {
gThread->AddTimer(this);
+ }
}
}
-void nsTimerEvent::Init()
+void
+nsTimerEvent::Init()
{
sAllocator = new TimerEventAllocator();
}
-void nsTimerEvent::Shutdown()
+void
+nsTimerEvent::Shutdown()
{
sCanDeleteAllocator = true;
DeleteAllocatorIfNeeded();
}
-void nsTimerEvent::DeleteAllocatorIfNeeded()
+void
+nsTimerEvent::DeleteAllocatorIfNeeded()
{
if (sCanDeleteAllocator && sAllocatorUsers == 0) {
delete sAllocator;
@@ -615,10 +705,12 @@ void nsTimerEvent::DeleteAllocatorIfNeeded()
}
}
-NS_IMETHODIMP nsTimerEvent::Run()
+NS_IMETHODIMP
+nsTimerEvent::Run()
{
- if (mGeneration != mTimer->GetGeneration())
+ if (mGeneration != mTimer->GetGeneration()) {
return NS_OK;
+ }
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
@@ -639,7 +731,8 @@ NS_IMETHODIMP nsTimerEvent::Run()
return NS_OK;
}
-already_AddRefed<nsTimerImpl> nsTimerImpl::PostTimerEvent(already_AddRefed<nsTimerImpl> aTimerRef)
+already_AddRefed<nsTimerImpl>
+nsTimerImpl::PostTimerEvent(already_AddRefed<nsTimerImpl> aTimerRef)
{
nsRefPtr<nsTimerImpl> timer(aTimerRef);
if (!timer->mEventTarget) {
@@ -658,8 +751,9 @@ already_AddRefed<nsTimerImpl> nsTimerImpl::PostTimerEvent(already_AddRefed<nsTim
// Note: We override operator new for this class, and the override is
// fallible!
nsRefPtr<nsTimerEvent> event = new nsTimerEvent;
- if (!event)
+ if (!event) {
return timer.forget();
+ }
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
@@ -668,9 +762,17 @@ already_AddRefed<nsTimerImpl> nsTimerImpl::PostTimerEvent(already_AddRefed<nsTim
#endif
// If this is a repeating precise timer, we need to calculate the time for
- // the next timer to fire before we make the callback. But don't re-arm.
+ // the next timer to fire before we make the callback.
if (timer->IsRepeatingPrecisely()) {
timer->SetDelayInternal(timer->mDelay);
+
+ // But only re-arm REPEATING_PRECISE timers.
+ if (gThread && timer->mType == TYPE_REPEATING_PRECISE) {
+ nsresult rv = gThread->AddTimer(timer);
+ if (NS_FAILED(rv)) {
+ return timer.forget();
+ }
+ }
}
nsIEventTarget* target = timer->mEventTarget;
@@ -679,52 +781,64 @@ already_AddRefed<nsTimerImpl> nsTimerImpl::PostTimerEvent(already_AddRefed<nsTim
nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
timer = event->ForgetTimer();
- if (gThread)
+ if (gThread) {
gThread->RemoveTimer(timer);
}
return timer.forget();
+ }
return nullptr;
}
-void nsTimerImpl::SetDelayInternal(uint32_t aDelay)
+void
+nsTimerImpl::SetDelayInternal(uint32_t aDelay)
{
TimeDuration delayInterval = TimeDuration::FromMilliseconds(aDelay);
mDelay = aDelay;
TimeStamp now = TimeStamp::Now();
- mTimeout = now;
+ if (mTimeout.IsNull() || mType != TYPE_REPEATING_PRECISE) {
+ mTimeout = now;
+ }
mTimeout += delayInterval;
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(GetTimerLog(), PR_LOG_DEBUG)) {
- if (mStart.IsNull())
+ if (mStart.IsNull()) {
mStart = now;
- else
+ } else {
mStart2 = now;
+ }
}
#endif
}
+size_t
+nsTimerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+ return aMallocSizeOf(this);
+}
+
// NOT FOR PUBLIC CONSUMPTION!
nsresult
-NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure,
+NS_NewTimer(nsITimer** aResult, nsTimerCallbackFunc aCallback, void* aClosure,
uint32_t aDelay, uint32_t aType)
{
- nsTimerImpl* timer = new nsTimerImpl();
- if (timer == nullptr)
- return NS_ERROR_OUT_OF_MEMORY;
- NS_ADDREF(timer);
+ nsTimerImpl* timer = new nsTimerImpl();
+ if (!timer) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ NS_ADDREF(timer);
- nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure,
- aDelay, aType);
- if (NS_FAILED(rv)) {
- NS_RELEASE(timer);
- return rv;
- }
+ nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure,
+ aDelay, aType);
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(timer);
+ return rv;
+ }
- *aResult = timer;
- return NS_OK;
+ *aResult = timer;
+ return NS_OK;
}