Backing out rev b567a93a5086 (
bug 558306) to fix test orange
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -45,30 +45,29 @@
#include "nsThreadUtils.h"
#include "pratom.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsIProxyObjectManager.h"
#include "mozilla/Services.h"
-#include <math.h>
-
NS_IMPL_THREADSAFE_ISUPPORTS2(TimerThread, nsIRunnable, nsIObserver)
TimerThread::TimerThread() :
mInitInProgress(0),
mInitialized(PR_FALSE),
mLock(nsnull),
mCondVar(nsnull),
mShutdown(PR_FALSE),
mWaiting(PR_FALSE),
mSleeping(PR_FALSE),
mDelayLineCounter(0),
- mMinTimerPeriod(0)
+ mMinTimerPeriod(0),
+ mTimeoutAdjustment(0)
{
}
TimerThread::~TimerThread()
{
if (mCondVar)
PR_DestroyCondVar(mCondVar);
if (mLock)
@@ -187,37 +186,36 @@ nsresult TimerThread::Shutdown()
PR_LOG(gTimerLog, PR_LOG_DEBUG, ("TimerThread::Shutdown end\n"));
return NS_OK;
}
// 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, TimeStamp aTimeout,
- TimeStamp aNow)
+void TimerThread::UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout,
+ PRIntervalTime aNow)
{
- TimeDuration slack = aTimeout - aNow;
+ PRInt32 slack = (PRInt32) (aTimeout - aNow);
double smoothSlack = 0;
PRUint32 i, filterLength;
- static TimeDuration kFilterFeedbackMaxTicks =
- TimeDuration::FromMilliseconds(FILTER_FEEDBACK_MAX);
- static TimeDuration kFilterFeedbackMinTicks =
- TimeDuration::FromMilliseconds(-FILTER_FEEDBACK_MAX);
+ static PRIntervalTime kFilterFeedbackMaxTicks =
+ PR_MillisecondsToInterval(FILTER_FEEDBACK_MAX);
- if (slack > kFilterFeedbackMaxTicks)
- slack = kFilterFeedbackMaxTicks;
- else if (slack < kFilterFeedbackMinTicks)
- slack = kFilterFeedbackMinTicks;
-
- mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] =
- slack.ToMilliseconds();
+ 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 (++mDelayLineCounter < DELAY_LINE_LENGTH) {
// Startup mode: accumulate a full delay line before filtering.
- PR_ASSERT(mTimeoutAdjustment.ToSeconds() == 0);
+ PR_ASSERT(mTimeoutAdjustment == 0);
filterLength = 0;
} else {
// Past startup: compute number of filter taps based on mMinTimerPeriod.
if (mMinTimerPeriod == 0) {
mMinTimerPeriod = (aDelay != 0) ? aDelay : 1;
} else if (aDelay != 0 && aDelay < mMinTimerPeriod) {
mMinTimerPeriod = aDelay;
}
@@ -228,47 +226,46 @@ void TimerThread::UpdateFilter(PRUint32
else if (filterLength < 4)
filterLength = 4;
for (i = 1; i <= filterLength; i++)
smoothSlack += mDelayLine[(mDelayLineCounter-i) & DELAY_LINE_LENGTH_MASK];
smoothSlack /= filterLength;
// XXXbe do we need amplification? hacking a fudge factor, need testing...
- mTimeoutAdjustment = TimeDuration::FromMilliseconds(smoothSlack * 1.5);
+ mTimeoutAdjustment = (PRInt32) (smoothSlack * 1.5);
}
#ifdef DEBUG_TIMERS
PR_LOG(gTimerLog, PR_LOG_DEBUG,
("UpdateFilter: smoothSlack = %g, filterLength = %u\n",
smoothSlack, filterLength));
#endif
}
/* void Run(); */
NS_IMETHODIMP TimerThread::Run()
{
nsAutoLock lock(mLock);
while (!mShutdown) {
- // Have to use PRIntervalTime here, since PR_WaitCondVar takes it
PRIntervalTime waitFor;
if (mSleeping) {
// Sleep for 0.1 seconds while not firing timers.
waitFor = PR_MillisecondsToInterval(100);
} else {
waitFor = PR_INTERVAL_NO_TIMEOUT;
- TimeStamp now = TimeStamp::Now();
+ PRIntervalTime now = PR_IntervalNow();
nsTimerImpl *timer = nsnull;
if (!mTimers.IsEmpty()) {
timer = mTimers[0];
- if (now >= timer->mTimeout + mTimeoutAdjustment) {
+ if (!TIMER_LESS_THAN(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
// from mTimers have gone away (the last non-mTimers[i]-ref's Release
// must be racing with us, blocked in gThread->RemoveTimer waiting
// for TimerThread::mLock, under nsTimerImpl::Release.
NS_ADDREF(timer);
@@ -276,17 +273,20 @@ NS_IMETHODIMP TimerThread::Run()
// We release mLock around the Fire call to avoid deadlock.
lock.unlock();
#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",
- PRInt32(fabs((now - timer->mTimeout).ToMilliseconds()))));
+ (now >= timer->mTimeout)
+ ? PR_IntervalToMilliseconds(now - timer->mTimeout)
+ : -(PRInt32)PR_IntervalToMilliseconds(timer->mTimeout-now))
+ );
}
#endif
// We are going to let the call to PostTimerEvent here handle the
// release of the timer so that we don't end up releasing the timer
// on the TimerThread instead of on the thread it targets.
if (NS_FAILED(timer->PostTimerEvent())) {
nsrefcnt rc;
@@ -308,30 +308,30 @@ NS_IMETHODIMP TimerThread::Run()
timer = nsnull;
lock.lock();
if (mShutdown)
break;
// Update now, as PostTimerEvent plus the locking may have taken a
// tick or two, and we may goto next below.
- now = TimeStamp::Now();
+ now = PR_IntervalNow();
}
}
if (!mTimers.IsEmpty()) {
timer = mTimers[0];
- TimeStamp timeout = timer->mTimeout + mTimeoutAdjustment;
+ PRIntervalTime 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 (now >= timeout)
+ if (!TIMER_LESS_THAN(now, timeout))
goto next;
- waitFor = PR_MillisecondsToInterval((timeout - now).ToMilliseconds());
+ waitFor = timeout - now;
}
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
if (waitFor == PR_INTERVAL_NO_TIMEOUT)
PR_LOG(gTimerLog, PR_LOG_DEBUG,
("waiting for PR_INTERVAL_NO_TIMEOUT\n"));
else
@@ -406,32 +406,33 @@ nsresult TimerThread::RemoveTimer(nsTime
}
// This function must be called from within a lock
PRInt32 TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
{
if (mShutdown)
return -1;
- TimeStamp now = TimeStamp::Now();
+ PRIntervalTime now = PR_IntervalNow();
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.
-
- // XXXbz why? Given our definition of overdue in terms of
- // mTimeoutAdjustment, aTimer might be overdue already! Why not
- // just fire timers in order?
+ // 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.
// XXX does this hold for TYPE_REPEATING_PRECISE? /be
- if (now < timer->mTimeout + mTimeoutAdjustment &&
- aTimer->mTimeout < timer->mTimeout) {
+ if (TIMER_LESS_THAN(now, timer->mTimeout) &&
+ TIMER_LESS_THAN(aTimer->mTimeout, timer->mTimeout)) {
break;
}
}
if (!mTimers.InsertElementAt(i, aTimer))
return -1;
aTimer->mArmed = PR_TRUE;
@@ -467,17 +468,17 @@ void TimerThread::DoAfterSleep()
nsTimerImpl *timer = mTimers[i];
// get and set the delay to cause its timeout to be recomputed
PRUint32 delay;
timer->GetDelay(&delay);
timer->SetDelay(delay);
}
// nuke the stored adjustments, so they get recalibrated
- mTimeoutAdjustment = TimeDuration(0);
+ mTimeoutAdjustment = 0;
mDelayLineCounter = 0;
mSleeping = PR_FALSE;
}
/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
NS_IMETHODIMP
TimerThread::Observe(nsISupports* /* aSubject */, const char *aTopic, const PRUnichar* /* aData */)
--- a/xpcom/threads/TimerThread.h
+++ b/xpcom/threads/TimerThread.h
@@ -45,26 +45,23 @@
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsTimerImpl.h"
#include "nsTArray.h"
#include "prcvar.h"
-#include "mozilla/TimeStamp.h"
+#include "prinrval.h"
#include "prlock.h"
class TimerThread : public nsIRunnable,
public nsIObserver
{
public:
- typedef mozilla::TimeStamp TimeStamp;
- typedef mozilla::TimeDuration TimeDuration;
-
TimerThread();
NS_HIDDEN_(nsresult) InitLocks();
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSIOBSERVER
NS_HIDDEN_(nsresult) Init();
@@ -72,18 +69,18 @@ public:
nsresult AddTimer(nsTimerImpl *aTimer);
nsresult TimerDelayChanged(nsTimerImpl *aTimer);
nsresult RemoveTimer(nsTimerImpl *aTimer);
#define FILTER_DURATION 1e3 /* one second */
#define FILTER_FEEDBACK_MAX 100 /* 1/10th of a second */
- void UpdateFilter(PRUint32 aDelay, TimeStamp aTimeout,
- TimeStamp aNow);
+ void UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout,
+ PRIntervalTime aNow);
void DoBeforeSleep();
void DoAfterSleep();
private:
~TimerThread();
PRInt32 mInitInProgress;
@@ -105,15 +102,15 @@ private:
PRPackedBool mSleeping;
nsTArray<nsTimerImpl*> mTimers;
#define DELAY_LINE_LENGTH_LOG2 5
#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]; // milliseconds
+ PRInt32 mDelayLine[DELAY_LINE_LENGTH];
PRUint32 mDelayLineCounter;
PRUint32 mMinTimerPeriod; // milliseconds
- TimeDuration mTimeoutAdjustment;
+ PRInt32 mTimeoutAdjustment;
};
#endif /* TimerThread_h___ */
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -41,19 +41,16 @@
#include "nsTimerImpl.h"
#include "TimerThread.h"
#include "nsAutoLock.h"
#include "nsAutoPtr.h"
#include "nsThreadManager.h"
#include "nsThreadUtils.h"
#include "prmem.h"
-using mozilla::TimeDuration;
-using mozilla::TimeStamp;
-
static PRInt32 gGenerator = 0;
static TimerThread* gThread = nsnull;
#ifdef DEBUG_TIMERS
#include <math.h>
double nsTimerImpl::sDeltaSumSquared = 0;
double nsTimerImpl::sDeltaSum = 0;
@@ -140,22 +137,28 @@ NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Re
nsTimerImpl::nsTimerImpl() :
mClosure(nsnull),
mCallbackType(CALLBACK_TYPE_UNKNOWN),
mFiring(PR_FALSE),
mArmed(PR_FALSE),
mCanceled(PR_FALSE),
mGeneration(0),
- mDelay(0)
+ mDelay(0),
+ mTimeout(0)
{
// XXXbsmedberg: shouldn't this be in Init()?
mEventTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread());
mCallback.c = nsnull;
+
+#ifdef DEBUG_TIMERS
+ mStart = 0;
+ mStart2 = 0;
+#endif
}
nsTimerImpl::~nsTimerImpl()
{
ReleaseCallback();
}
//static
@@ -293,18 +296,18 @@ NS_IMETHODIMP nsTimerImpl::SetDelay(PRUi
// by re-setting delay instead of reinitializing the timer.
NS_ERROR("nsITimer->SetDelay() called when the "
"one-shot timer is not set up.");
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();
+ if (mTimeout != 0 && mType == TYPE_REPEATING_PRECISE)
+ mTimeout = PR_IntervalNow();
SetDelayInternal(aDelay);
if (!mFiring && gThread)
gThread->TimerDelayChanged(this);
return NS_OK;
}
@@ -371,42 +374,41 @@ NS_IMETHODIMP nsTimerImpl::SetTarget(nsI
}
void nsTimerImpl::Fire()
{
if (mCanceled)
return;
- TimeStamp now = TimeStamp::Now();
+ PRIntervalTime now = PR_IntervalNow();
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
- 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
+ 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
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, PRInt32(a.ToMilliseconds())));
+ 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] (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 = TimeStamp::TimeStamp();
+ mStart2 = 0;
}
#endif
- TimeStamp timeout = mTimeout;
+ PRIntervalTime timeout = mTimeout;
if (mType == TYPE_REPEATING_PRECISE) {
// Precise repeating timers advance mTimeout by mDelay without fail before
// calling Fire().
- timeout -= TimeDuration::FromMilliseconds(mDelay);
+ timeout -= PR_MillisecondsToInterval(mDelay);
}
if (gThread)
gThread->UpdateFilter(mDelay, timeout, now);
if (mCallbackType == CALLBACK_TYPE_INTERFACE)
mTimerCallbackWhileFiring = mCallback.i;
mFiring = PR_TRUE;
@@ -451,17 +453,17 @@ void nsTimerImpl::Fire()
mFiring = PR_FALSE;
mTimerCallbackWhileFiring = nsnull;
#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, (TimeStamp::Now() - now).ToMilliseconds()));
+ this, PR_IntervalToMilliseconds(PR_IntervalNow() - now)));
}
#endif
// Reschedule REPEATING_SLACK timers, but make sure that we aren't armed
// already (which can happen if the callback reinitialized the timer).
if (mType == TYPE_REPEATING_SLACK && !mArmed) {
SetDelayInternal(mDelay); // force mTimeout to be recomputed.
if (gThread)
@@ -476,17 +478,17 @@ public:
nsTimerEvent(nsTimerImpl *timer, PRInt32 generation)
: mTimer(timer), mGeneration(generation) {
// timer is already addref'd for us
MOZ_COUNT_CTOR(nsTimerEvent);
}
#ifdef DEBUG_TIMERS
- TimeStamp mInitTime;
+ PRIntervalTime mInitTime;
#endif
private:
~nsTimerEvent() {
#ifdef DEBUG
if (mTimer)
NS_WARNING("leaking reference to nsTimerImpl");
#endif
@@ -502,20 +504,20 @@ NS_IMETHODIMP nsTimerEvent::Run()
nsRefPtr<nsTimerImpl> timer;
timer.swap(mTimer);
if (mGeneration != timer->GetGeneration())
return NS_OK;
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
- TimeStamp now = TimeStamp::Now();
+ PRIntervalTime now = PR_IntervalNow();
PR_LOG(gTimerLog, PR_LOG_DEBUG,
("[this=%p] time between PostTimerEvent() and Fire(): %dms\n",
- this, (now - mInitTime).ToMilliseconds()));
+ this, PR_IntervalToMilliseconds(now - mInitTime)));
}
#endif
timer->Fire();
return NS_OK;
}
@@ -529,17 +531,17 @@ nsresult nsTimerImpl::PostTimerEvent()
// re-initialized after being canceled.
nsRefPtr<nsTimerEvent> event = new nsTimerEvent(this, mGeneration);
if (!event)
return NS_ERROR_OUT_OF_MEMORY;
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
- event->mInitTime = TimeStamp::Now();
+ event->mInitTime = PR_IntervalNow();
}
#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.
if (mType == TYPE_REPEATING_PRECISE) {
SetDelayInternal(mDelay);
if (gThread) {
@@ -552,29 +554,33 @@ nsresult nsTimerImpl::PostTimerEvent()
nsresult rv = mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv) && gThread)
gThread->RemoveTimer(this);
return rv;
}
void nsTimerImpl::SetDelayInternal(PRUint32 aDelay)
{
- TimeDuration delayInterval = TimeDuration::FromMilliseconds(aDelay);
+ PRIntervalTime delayInterval = PR_MillisecondsToInterval(aDelay);
+ if (delayInterval > DELAY_INTERVAL_MAX) {
+ delayInterval = DELAY_INTERVAL_MAX;
+ aDelay = PR_IntervalToMilliseconds(delayInterval);
+ }
mDelay = aDelay;
- TimeStamp now = TimeStamp::Now();
- if (mTimeout.IsNull() || mType != TYPE_REPEATING_PRECISE)
+ PRIntervalTime now = PR_IntervalNow();
+ if (mTimeout == 0 || mType != TYPE_REPEATING_PRECISE)
mTimeout = now;
mTimeout += delayInterval;
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
- if (mStart.IsNull())
+ if (mStart == 0)
mStart = now;
else
mStart2 = now;
}
#endif
}
// NOT FOR PUBLIC CONSUMPTION!
--- a/xpcom/threads/nsTimerImpl.h
+++ b/xpcom/threads/nsTimerImpl.h
@@ -45,17 +45,16 @@
#include "nsITimer.h"
#include "nsIEventTarget.h"
#include "nsIObserver.h"
#include "nsCOMPtr.h"
#include "prlog.h"
-#include "mozilla/TimeStamp.h"
#if defined(PR_LOGGING)
static PRLogModuleInfo *gTimerLog = PR_NewLogModule("nsTimerImpl");
#define DEBUG_TIMERS 1
#else
#undef DEBUG_TIMERS
#endif
@@ -70,20 +69,28 @@ static PRLogModuleInfo *gTimerLog = PR_N
enum {
CALLBACK_TYPE_UNKNOWN = 0,
CALLBACK_TYPE_INTERFACE = 1,
CALLBACK_TYPE_FUNC = 2,
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();
static NS_HIDDEN_(nsresult) Startup();
static NS_HIDDEN_(void) Shutdown();
friend class TimerThread;
@@ -145,20 +152,20 @@ private:
PRBool mCanceled;
// The generation number of this timer, re-generated each time the timer is
// initialized so one-shot timers can be canceled and re-initialized by the
// arming thread without any bad race conditions.
PRInt32 mGeneration;
PRUint32 mDelay;
- TimeStamp mTimeout;
+ PRIntervalTime mTimeout;
#ifdef DEBUG_TIMERS
- TimeStamp mStart, mStart2;
+ PRIntervalTime mStart, mStart2;
static double sDeltaSum;
static double sDeltaSumSquared;
static double sDeltaNum;
#endif
};
#endif /* nsTimerImpl_h___ */