Backported to icecat-31.8 from the upstream esr38 branch. From 1a7eac06fab3b8ffca09936498887f99e233bcba Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Thu, 9 Jul 2015 20:18:34 -0400 Subject: [PATCH] Bug 1178890 - Update timer arrays after sleep to account for time sleeping. r=bwc, r=froydnj, a=sledru --- icecat-31.8.0/xpcom/threads/TimerThread.cpp.orig 1969-12-31 19:00:00.000000000 -0500 +++ icecat-31.8.0/xpcom/threads/TimerThread.cpp 2015-08-12 16:38:11.789371171 -0400 @@ -28,7 +28,8 @@ mShutdown(false), mWaiting(false), mNotified(false), - mSleeping(false) + mSleeping(false), + mLastTimerEventLoopRun(TimeStamp::Now()) { } @@ -222,6 +223,7 @@ } else { waitFor = PR_INTERVAL_NO_TIMEOUT; TimeStamp now = TimeStamp::Now(); + mLastTimerEventLoopRun = now; nsTimerImpl *timer = nullptr; if (!mTimers.IsEmpty()) { @@ -411,6 +413,7 @@ // This function must be called from within a lock int32_t TimerThread::AddTimerInternal(nsTimerImpl *aTimer) { + mMonitor.AssertCurrentThreadOwns(); if (mShutdown) return -1; @@ -434,6 +437,7 @@ bool TimerThread::RemoveTimerInternal(nsTimerImpl *aTimer) { + mMonitor.AssertCurrentThreadOwns(); if (!mTimers.RemoveElement(aTimer)) return false; @@ -443,6 +447,10 @@ void TimerThread::ReleaseTimerInternal(nsTimerImpl *aTimer) { + if (!mShutdown) { + // copied to a local array before releasing in shutdown + mMonitor.AssertCurrentThreadOwns(); + } // Order is crucial here -- see nsTimerImpl::Release. aTimer->mArmed = false; NS_RELEASE(aTimer); @@ -450,21 +458,39 @@ void TimerThread::DoBeforeSleep() { + // Mainthread + MonitorAutoLock lock(mMonitor); + mLastTimerEventLoopRun = TimeStamp::Now(); mSleeping = true; } +// Note: wake may be notified without preceding sleep notification void TimerThread::DoAfterSleep() { - mSleeping = true; // wake may be notified without preceding sleep notification + // Mainthread + TimeStamp now = TimeStamp::Now(); + + MonitorAutoLock lock(mMonitor); + + // an over-estimate of time slept, usually small + TimeDuration slept = now - mLastTimerEventLoopRun; + + // Adjust all old timers to expire roughly similar times in the future + // compared to when we went to sleep, by adding the time we slept to the + // target time. It's slightly possible a few will end up slightly in the + // past and fire immediately, but ordering should be preserved. All + // timers retain the exact same order (and relative times) as before + // going to sleep. for (uint32_t i = 0; i < mTimers.Length(); i ++) { nsTimerImpl *timer = mTimers[i]; - // get and set the delay to cause its timeout to be recomputed - uint32_t delay; - timer->GetDelay(&delay); - timer->SetDelay(delay); + timer->mTimeout += slept; } - mSleeping = false; + mLastTimerEventLoopRun = now; + + // Wake up the timer thread to process the updated array + mNotified = true; + mMonitor.Notify(); } --- icecat-31.8.0/xpcom/threads/TimerThread.h.orig 1969-12-31 19:00:00.000000000 -0500 +++ icecat-31.8.0/xpcom/threads/TimerThread.h 2015-08-12 16:38:38.542408062 -0400 @@ -59,7 +59,7 @@ mozilla::Atomic mInitInProgress; bool mInitialized; - // These two internal helper methods must be called while mLock is held. + // These two internal helper methods must be called while mMonitor is held. // AddTimerInternal returns the position where the timer was added in the // list, or -1 if it failed. int32_t AddTimerInternal(nsTimerImpl *aTimer); @@ -73,6 +73,7 @@ bool mWaiting; bool mNotified; bool mSleeping; + TimeStamp mLastTimerEventLoopRun; nsTArray mTimers; };