diff --git a/xpcom/threads/TimerThread.cpp b/xpcom/threads/TimerThread.cpp index 3e4365df77e..5f15394795a 100644 --- a/xpcom/threads/TimerThread.cpp +++ b/xpcom/threads/TimerThread.cpp @@ -50,6 +50,8 @@ #include "nsIProxyObjectManager.h" #include "mozilla/Services.h" +#include + NS_IMPL_THREADSAFE_ISUPPORTS2(TimerThread, nsIRunnable, nsIObserver) TimerThread::TimerThread() : @@ -61,8 +63,7 @@ TimerThread::TimerThread() : mWaiting(PR_FALSE), mSleeping(PR_FALSE), mDelayLineCounter(0), - mMinTimerPeriod(0), - mTimeoutAdjustment(0) + mMinTimerPeriod(0) { } @@ -191,26 +192,27 @@ nsresult TimerThread::Shutdown() // Keep track of how early (positive slack) or late (negative slack) timers // are running, and use the filtered slack number to adaptively estimate how // early timers should fire to be "on time". -void TimerThread::UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout, - PRIntervalTime aNow) +void TimerThread::UpdateFilter(PRUint32 aDelay, TimeStamp aTimeout, + TimeStamp aNow) { - PRInt32 slack = (PRInt32) (aTimeout - aNow); + TimeDuration slack = aTimeout - aNow; double smoothSlack = 0; PRUint32 i, filterLength; - static PRIntervalTime kFilterFeedbackMaxTicks = - PR_MillisecondsToInterval(FILTER_FEEDBACK_MAX); + static TimeDuration kFilterFeedbackMaxTicks = + TimeDuration::FromMilliseconds(FILTER_FEEDBACK_MAX); + static TimeDuration kFilterFeedbackMinTicks = + TimeDuration::FromMilliseconds(-FILTER_FEEDBACK_MAX); - if (slack > 0) { - if (slack > (PRInt32)kFilterFeedbackMaxTicks) - slack = kFilterFeedbackMaxTicks; - } else { - if (slack < -(PRInt32)kFilterFeedbackMaxTicks) - slack = -(PRInt32)kFilterFeedbackMaxTicks; - } - mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] = slack; + if (slack > kFilterFeedbackMaxTicks) + slack = kFilterFeedbackMaxTicks; + else if (slack < kFilterFeedbackMinTicks) + slack = kFilterFeedbackMinTicks; + + mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] = + slack.ToMilliseconds(); if (++mDelayLineCounter < DELAY_LINE_LENGTH) { // Startup mode: accumulate a full delay line before filtering. - PR_ASSERT(mTimeoutAdjustment == 0); + PR_ASSERT(mTimeoutAdjustment.ToSeconds() == 0); filterLength = 0; } else { // Past startup: compute number of filter taps based on mMinTimerPeriod. @@ -231,7 +233,7 @@ void TimerThread::UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout, smoothSlack /= filterLength; // XXXbe do we need amplification? hacking a fudge factor, need testing... - mTimeoutAdjustment = (PRInt32) (smoothSlack * 1.5); + mTimeoutAdjustment = TimeDuration::FromMilliseconds(smoothSlack * 1.5); } #ifdef DEBUG_TIMERS @@ -247,6 +249,7 @@ NS_IMETHODIMP TimerThread::Run() nsAutoLock lock(mLock); while (!mShutdown) { + // Have to use PRIntervalTime here, since PR_WaitCondVar takes it PRIntervalTime waitFor; if (mSleeping) { @@ -254,13 +257,13 @@ NS_IMETHODIMP TimerThread::Run() waitFor = PR_MillisecondsToInterval(100); } else { waitFor = PR_INTERVAL_NO_TIMEOUT; - PRIntervalTime now = PR_IntervalNow(); + TimeStamp now = TimeStamp::Now(); nsTimerImpl *timer = nsnull; if (!mTimers.IsEmpty()) { timer = mTimers[0]; - if (!TIMER_LESS_THAN(now, timer->mTimeout + mTimeoutAdjustment)) { + if (now >= timer->mTimeout + mTimeoutAdjustment) { next: // NB: AddRef before the Release under RemoveTimerInternal to avoid // mRefCnt passing through zero, in case all other refs than the one @@ -277,11 +280,8 @@ NS_IMETHODIMP TimerThread::Run() #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PR_LOG(gTimerLog, PR_LOG_DEBUG, - ("Timer thread woke up %dms from when it was supposed to\n", - (now >= timer->mTimeout) - ? PR_IntervalToMilliseconds(now - timer->mTimeout) - : -(PRInt32)PR_IntervalToMilliseconds(timer->mTimeout-now)) - ); + ("Timer thread woke up %fms from when it was supposed to\n", + fabs((now - timer->mTimeout).ToMilliseconds()))); } #endif @@ -313,20 +313,20 @@ NS_IMETHODIMP TimerThread::Run() // Update now, as PostTimerEvent plus the locking may have taken a // tick or two, and we may goto next below. - now = PR_IntervalNow(); + now = TimeStamp::Now(); } } if (!mTimers.IsEmpty()) { timer = mTimers[0]; - PRIntervalTime timeout = timer->mTimeout + mTimeoutAdjustment; + TimeStamp timeout = timer->mTimeout + mTimeoutAdjustment; // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer // is due now or overdue. - if (!TIMER_LESS_THAN(now, timeout)) + if (now >= timeout) goto next; - waitFor = timeout - now; + waitFor = PR_MillisecondsToInterval((timeout - now).ToMilliseconds()); } #ifdef DEBUG_TIMERS @@ -411,23 +411,22 @@ PRInt32 TimerThread::AddTimerInternal(nsTimerImpl *aTimer) if (mShutdown) return -1; - PRIntervalTime now = PR_IntervalNow(); + TimeStamp now = TimeStamp::Now(); PRUint32 count = mTimers.Length(); PRUint32 i = 0; for (; i < count; i++) { nsTimerImpl *timer = mTimers[i]; - // Don't break till we have skipped any overdue timers. Do not include - // mTimeoutAdjustment here, because we are really trying to avoid calling - // TIMER_LESS_THAN(t, u), where the t is now + DELAY_INTERVAL_MAX, u is - // now - overdue, and DELAY_INTERVAL_MAX + overdue > DELAY_INTERVAL_LIMIT. - // In other words, we want to use now-based time, now adjusted time, even - // though "overdue" ultimately depends on adjusted time. + // Don't break till we have skipped any overdue timers. + + // XXXbz why? Given our definition of overdue in terms of + // mTimeoutAdjustment, aTimer might be overdue already! Why not + // just fire timers in order? // XXX does this hold for TYPE_REPEATING_PRECISE? /be - if (TIMER_LESS_THAN(now, timer->mTimeout) && - TIMER_LESS_THAN(aTimer->mTimeout, timer->mTimeout)) { + if (now < timer->mTimeout + mTimeoutAdjustment && + aTimer->mTimeout < timer->mTimeout) { break; } } @@ -473,7 +472,7 @@ void TimerThread::DoAfterSleep() } // nuke the stored adjustments, so they get recalibrated - mTimeoutAdjustment = 0; + mTimeoutAdjustment = TimeDuration(0); mDelayLineCounter = 0; mSleeping = PR_FALSE; } diff --git a/xpcom/threads/TimerThread.h b/xpcom/threads/TimerThread.h index e3d48c9ca36..61945588e51 100644 --- a/xpcom/threads/TimerThread.h +++ b/xpcom/threads/TimerThread.h @@ -50,13 +50,16 @@ #include "nsTArray.h" #include "prcvar.h" -#include "prinrval.h" +#include "mozilla/TimeStamp.h" #include "prlock.h" class TimerThread : public nsIRunnable, public nsIObserver { public: + typedef mozilla::TimeStamp TimeStamp; + typedef mozilla::TimeDuration TimeDuration; + TimerThread(); NS_HIDDEN_(nsresult) InitLocks(); @@ -74,8 +77,8 @@ public: #define FILTER_DURATION 1e3 /* one second */ #define FILTER_FEEDBACK_MAX 100 /* 1/10th of a second */ - void UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout, - PRIntervalTime aNow); + void UpdateFilter(PRUint32 aDelay, TimeStamp aTimeout, + TimeStamp aNow); void DoBeforeSleep(); void DoAfterSleep(); @@ -107,10 +110,10 @@ private: #define DELAY_LINE_LENGTH_MASK PR_BITMASK(DELAY_LINE_LENGTH_LOG2) #define DELAY_LINE_LENGTH PR_BIT(DELAY_LINE_LENGTH_LOG2) - PRInt32 mDelayLine[DELAY_LINE_LENGTH]; + PRInt32 mDelayLine[DELAY_LINE_LENGTH]; // milliseconds PRUint32 mDelayLineCounter; PRUint32 mMinTimerPeriod; // milliseconds - PRInt32 mTimeoutAdjustment; + TimeDuration mTimeoutAdjustment; }; #endif /* TimerThread_h___ */ diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index f2dd88674c8..2fc231c8f3c 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -46,6 +46,9 @@ #include "nsThreadUtils.h" #include "prmem.h" +using mozilla::TimeDuration; +using mozilla::TimeStamp; + static PRInt32 gGenerator = 0; static TimerThread* gThread = nsnull; @@ -142,18 +145,12 @@ nsTimerImpl::nsTimerImpl() : mArmed(PR_FALSE), mCanceled(PR_FALSE), mGeneration(0), - mDelay(0), - mTimeout(0) + mDelay(0) { // XXXbsmedberg: shouldn't this be in Init()? mEventTarget = static_cast(NS_GetCurrentThread()); mCallback.c = nsnull; - -#ifdef DEBUG_TIMERS - mStart = 0; - mStart2 = 0; -#endif } nsTimerImpl::~nsTimerImpl() @@ -301,8 +298,8 @@ NS_IMETHODIMP nsTimerImpl::SetDelay(PRUint32 aDelay) // If we're already repeating precisely, update mTimeout now so that the // new delay takes effect in the future. - if (mTimeout != 0 && mType == TYPE_REPEATING_PRECISE) - mTimeout = PR_IntervalNow(); + if (!mTimeout.IsNull() && mType == TYPE_REPEATING_PRECISE) + mTimeout = TimeStamp::Now(); SetDelayInternal(aDelay); @@ -379,31 +376,32 @@ void nsTimerImpl::Fire() if (mCanceled) return; - PRIntervalTime now = PR_IntervalNow(); + TimeStamp now = TimeStamp::Now(); #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { - PRIntervalTime a = now - mStart; // actual delay in intervals - PRUint32 b = PR_MillisecondsToInterval(mDelay); // expected delay in intervals - PRUint32 d = PR_IntervalToMilliseconds((a > b) ? a - b : b - a); // delta in ms + TimeDuration a = now - mStart; // actual delay in intervals + TimeDuration b = TimeDuration::FromMilliseconds(mDelay); // expected delay in intervals + TimeDuration delta = (a > b) ? a - b : b - a; + PRUint32 d = delta.ToMilliseconds(); // delta in ms sDeltaSum += d; sDeltaSumSquared += double(d) * double(d); sDeltaNum++; - PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4dms\n", this, mDelay)); - PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %4dms\n", this, PR_IntervalToMilliseconds(a))); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4ums\n", this, mDelay)); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %fms\n", this, a.ToMilliseconds())); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType)); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (PRInt32)d : -(PRInt32)d)); mStart = mStart2; - mStart2 = 0; + mStart2 = TimeStamp::TimeStamp(); } #endif - PRIntervalTime timeout = mTimeout; + TimeStamp timeout = mTimeout; if (mType == TYPE_REPEATING_PRECISE) { // Precise repeating timers advance mTimeout by mDelay without fail before // calling Fire(). - timeout -= PR_MillisecondsToInterval(mDelay); + timeout -= TimeDuration::FromMilliseconds(mDelay); } if (gThread) gThread->UpdateFilter(mDelay, timeout, now); @@ -457,8 +455,8 @@ void nsTimerImpl::Fire() #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PR_LOG(gTimerLog, PR_LOG_DEBUG, - ("[this=%p] Took %dms to fire timer callback\n", - this, PR_IntervalToMilliseconds(PR_IntervalNow() - now))); + ("[this=%p] Took %fms to fire timer callback\n", + this, (TimeStamp::Now() - now).ToMilliseconds())); } #endif @@ -483,7 +481,7 @@ public: } #ifdef DEBUG_TIMERS - PRIntervalTime mInitTime; + TimeStamp mInitTime; #endif private: @@ -509,10 +507,10 @@ NS_IMETHODIMP nsTimerEvent::Run() #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { - PRIntervalTime now = PR_IntervalNow(); + TimeStamp now = TimeStamp::Now(); PR_LOG(gTimerLog, PR_LOG_DEBUG, - ("[this=%p] time between PostTimerEvent() and Fire(): %dms\n", - this, PR_IntervalToMilliseconds(now - mInitTime))); + ("[this=%p] time between PostTimerEvent() and Fire(): %fms\n", + this, (now - mInitTime).ToMilliseconds())); } #endif @@ -536,7 +534,7 @@ nsresult nsTimerImpl::PostTimerEvent() #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { - event->mInitTime = PR_IntervalNow(); + event->mInitTime = TimeStamp::Now(); } #endif @@ -559,23 +557,19 @@ nsresult nsTimerImpl::PostTimerEvent() void nsTimerImpl::SetDelayInternal(PRUint32 aDelay) { - PRIntervalTime delayInterval = PR_MillisecondsToInterval(aDelay); - if (delayInterval > DELAY_INTERVAL_MAX) { - delayInterval = DELAY_INTERVAL_MAX; - aDelay = PR_IntervalToMilliseconds(delayInterval); - } + TimeDuration delayInterval = TimeDuration::FromMilliseconds(aDelay); mDelay = aDelay; - PRIntervalTime now = PR_IntervalNow(); - if (mTimeout == 0 || mType != TYPE_REPEATING_PRECISE) + TimeStamp now = TimeStamp::Now(); + if (mTimeout.IsNull() || mType != TYPE_REPEATING_PRECISE) mTimeout = now; mTimeout += delayInterval; #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { - if (mStart == 0) + if (mStart.IsNull()) mStart = now; else mStart2 = now; diff --git a/xpcom/threads/nsTimerImpl.h b/xpcom/threads/nsTimerImpl.h index 602b9cc2f8b..1b1e3369e2b 100644 --- a/xpcom/threads/nsTimerImpl.h +++ b/xpcom/threads/nsTimerImpl.h @@ -50,6 +50,7 @@ #include "nsCOMPtr.h" #include "prlog.h" +#include "mozilla/TimeStamp.h" #if defined(PR_LOGGING) static PRLogModuleInfo *gTimerLog = PR_NewLogModule("nsTimerImpl"); @@ -74,18 +75,10 @@ enum { CALLBACK_TYPE_OBSERVER = 3 }; -// Two timer deadlines must differ by less than half the PRIntervalTime domain. -#define DELAY_INTERVAL_LIMIT PR_BIT(8 * sizeof(PRIntervalTime) - 1) - -// Maximum possible delay (XXX rework to use ms rather than interval ticks). -#define DELAY_INTERVAL_MAX (DELAY_INTERVAL_LIMIT - 1) - -// Is interval-time t less than u, even if t has wrapped PRIntervalTime? -#define TIMER_LESS_THAN(t, u) ((t) - (u) > DELAY_INTERVAL_LIMIT) - class nsTimerImpl : public nsITimer { public: + typedef mozilla::TimeStamp TimeStamp; nsTimerImpl(); @@ -157,10 +150,10 @@ private: PRInt32 mGeneration; PRUint32 mDelay; - PRIntervalTime mTimeout; + TimeStamp mTimeout; #ifdef DEBUG_TIMERS - PRIntervalTime mStart, mStart2; + TimeStamp mStart, mStart2; static double sDeltaSum; static double sDeltaSumSquared; static double sDeltaNum;