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:
Robert O'Callahan 2014-03-03 18:12:51 +13:00
parent 62a65cf9a2
commit 53ef4cd684
2 changed files with 44 additions and 7 deletions

View File

@ -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;
}

View File

@ -71,6 +71,7 @@ private:
bool mShutdown;
bool mWaiting;
bool mNotified;
bool mSleeping;
nsTArray<nsTimerImpl*> mTimers;