mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 558306 part 2. Switch XPCOM timers to TimeDuration/TimeStamp. r=cjones, sr=brendan
This commit is contained in:
parent
8a5a8c7f9e
commit
5e5e0fd66f
@ -50,6 +50,8 @@
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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___ */
|
||||
|
@ -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<nsIEventTarget*>(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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user