mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-26 02:02:33 +00:00
Bug 955888. Part 8: In chaos mode, vary timer duration (while respecting order of firing). r=bz
We also ensure that the mean timer duration is unchanged. --HG-- extra : rebase_source : 21a43c2c6a0f677263464b8a23c5f605e36b9d06
This commit is contained in:
parent
62a65cf9a2
commit
53ef4cd684
@ -12,6 +12,8 @@
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/ChaosMode.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@ -25,6 +27,7 @@ TimerThread::TimerThread() :
|
||||
mMonitor("TimerThread.mMonitor"),
|
||||
mShutdown(false),
|
||||
mWaiting(false),
|
||||
mNotified(false),
|
||||
mSleeping(false)
|
||||
{
|
||||
}
|
||||
@ -133,8 +136,10 @@ nsresult TimerThread::Shutdown()
|
||||
mShutdown = true;
|
||||
|
||||
// notify the cond var so that Run() can return
|
||||
if (mWaiting)
|
||||
if (mWaiting) {
|
||||
mNotified = true;
|
||||
mMonitor.Notify();
|
||||
}
|
||||
|
||||
// Need to copy content of mTimers array to a local array
|
||||
// because call to timers' ReleaseCallback() (and release its self)
|
||||
@ -199,14 +204,21 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
// Half of the amount of microseconds needed to get positive PRIntervalTime.
|
||||
// We use this to decide how to round our wait times later
|
||||
int32_t halfMicrosecondsIntervalResolution = high >> 1;
|
||||
bool forceRunNextTimer = false;
|
||||
|
||||
while (!mShutdown) {
|
||||
// Have to use PRIntervalTime here, since PR_WaitCondVar takes it
|
||||
PRIntervalTime waitFor;
|
||||
bool forceRunThisTimer = forceRunNextTimer;
|
||||
forceRunNextTimer = false;
|
||||
|
||||
if (mSleeping) {
|
||||
// Sleep for 0.1 seconds while not firing timers.
|
||||
waitFor = PR_MillisecondsToInterval(100);
|
||||
uint32_t milliseconds = 100;
|
||||
if (ChaosMode::isActive()) {
|
||||
milliseconds = ChaosMode::randomUint32LessThan(200);
|
||||
}
|
||||
waitFor = PR_MillisecondsToInterval(milliseconds);
|
||||
} else {
|
||||
waitFor = PR_INTERVAL_NO_TIMEOUT;
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
@ -215,7 +227,7 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
if (!mTimers.IsEmpty()) {
|
||||
timer = mTimers[0];
|
||||
|
||||
if (now >= timer->mTimeout) {
|
||||
if (now >= timer->mTimeout || forceRunThisTimer) {
|
||||
next:
|
||||
// NB: AddRef before the Release under RemoveTimerInternal to avoid
|
||||
// mRefCnt passing through zero, in case all other refs than the one
|
||||
@ -283,8 +295,22 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
// before, to do the optimal rounding (i.e., of how to decide what
|
||||
// interval is so small we should not wait at all).
|
||||
double microseconds = (timeout - now).ToMilliseconds()*1000;
|
||||
if (microseconds < halfMicrosecondsIntervalResolution)
|
||||
|
||||
if (ChaosMode::isActive()) {
|
||||
// The mean value of sFractions must be 1 to ensure that
|
||||
// the average of a long sequence of timeouts converges to the
|
||||
// actual sum of their times.
|
||||
static const float sFractions[] = {
|
||||
0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.75f, 2.75f
|
||||
};
|
||||
microseconds *= sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
|
||||
forceRunNextTimer = true;
|
||||
}
|
||||
|
||||
if (microseconds < halfMicrosecondsIntervalResolution) {
|
||||
forceRunNextTimer = false;
|
||||
goto next; // round down; execute event now
|
||||
}
|
||||
waitFor = PR_MicrosecondsToInterval(static_cast<uint32_t>(microseconds)); // Floor is accurate enough.
|
||||
if (waitFor == 0)
|
||||
waitFor = 1; // round up, wait the minimum time we can wait
|
||||
@ -303,7 +329,11 @@ NS_IMETHODIMP TimerThread::Run()
|
||||
}
|
||||
|
||||
mWaiting = true;
|
||||
mNotified = false;
|
||||
mMonitor.Wait(waitFor);
|
||||
if (mNotified) {
|
||||
forceRunNextTimer = false;
|
||||
}
|
||||
mWaiting = false;
|
||||
}
|
||||
|
||||
@ -320,8 +350,10 @@ nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Awaken the timer thread.
|
||||
if (mWaiting && i == 0)
|
||||
if (mWaiting && i == 0) {
|
||||
mNotified = true;
|
||||
mMonitor.Notify();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -339,8 +371,10 @@ nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Awaken the timer thread.
|
||||
if (mWaiting && i == 0)
|
||||
if (mWaiting && i == 0) {
|
||||
mNotified = true;
|
||||
mMonitor.Notify();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -360,8 +394,10 @@ nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// Awaken the timer thread.
|
||||
if (mWaiting)
|
||||
if (mWaiting) {
|
||||
mNotified = true;
|
||||
mMonitor.Notify();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ private:
|
||||
|
||||
bool mShutdown;
|
||||
bool mWaiting;
|
||||
bool mNotified;
|
||||
bool mSleeping;
|
||||
|
||||
nsTArray<nsTimerImpl*> mTimers;
|
||||
|
Loading…
Reference in New Issue
Block a user