Bug 586692 - xpcshell: do_timeout does not guarantee desired timeout interval. r=jduell

This commit is contained in:
Dan Witte 2010-08-13 13:28:14 -07:00
Родитель 60763c3536
Коммит 6f2a31c22a
2 изменённых файлов: 55 добавлений и 69 удалений

Просмотреть файл

@ -41,8 +41,6 @@ do_load_httpd_js();
// if these tests fail, we'll want the debug output
DEBUG = true;
const Timer = CC("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
/**
* Constructs a new nsHttpServer instance. This function is intended to
@ -210,20 +208,6 @@ function isException(e, code)
do_throw("unexpected error: " + e);
}
/**
* Pending timers used by callLater, which must store them to avoid the timer
* being canceled and destroyed. Stupid API...
*/
var __pendingTimers = [];
/**
* Date.now() is not necessarily monotonically increasing (insert sob story
* about times not being the right tool to use for measuring intervals of time,
* robarnold can tell all), so be wary of error by erring by at least
* __timerFuzz ms.
*/
const __timerFuzz = 15;
/**
* Calls the given function at least the specified number of milliseconds later.
* The callback will not undershoot the given time, but it might overshoot --
@ -236,48 +220,7 @@ const __timerFuzz = 15;
*/
function callLater(msecs, callback)
{
do_check_true(msecs >= 0);
var start = Date.now();
function checkTime()
{
var index = __pendingTimers.indexOf(timer);
do_check_true(index >= 0); // sanity
__pendingTimers.splice(index, 1);
do_check_eq(__pendingTimers.indexOf(timer), -1);
// The current nsITimer implementation can undershoot, but even if it
// couldn't, paranoia is probably a virtue here given the potential for
// random orange on tinderboxen.
var end = Date.now();
var elapsed = end - start;
if (elapsed >= msecs)
{
dumpn("*** TIMER FIRE " + elapsed + "ms (" + msecs + "ms requested)");
try
{
callback();
}
catch (e)
{
do_throw("exception thrown from callLater callback: " + e);
}
return;
}
// Timer undershot, retry with a little overshoot to try to avoid more
// undershoots.
var newDelay = msecs - elapsed;
dumpn("*** TIMER UNDERSHOOT " + newDelay + "ms " +
"(" + msecs + "ms requested, delaying)");
callLater(newDelay, callback);
}
var timer =
new Timer(checkTime, msecs + __timerFuzz, Ci.nsITimer.TYPE_ONE_SHOT);
__pendingTimers.push(timer);
do_timeout(msecs, callback);
}

Просмотреть файл

@ -49,7 +49,7 @@ var _passed = true;
var _tests_pending = 0;
var _passedChecks = 0, _falsePassedChecks = 0;
var _cleanupFunctions = [];
var _pendingCallbacks = [];
var _pendingTimers = [];
function _dump(str) {
if (typeof _XPCSHELL_PROCESS == "undefined") {
@ -89,16 +89,34 @@ try { // nsIXULRuntime is not available in some configurations.
}
catch (e) { }
/**
* Date.now() is not necessarily monotonically increasing (insert sob story
* about times not being the right tool to use for measuring intervals of time,
* robarnold can tell all), so be wary of error by erring by at least
* _timerFuzz ms.
*/
const _timerFuzz = 15;
function _Timer(func, delay) {
delay = Number(delay);
if (delay < 0)
do_throw("do_timeout() delay must be nonnegative");
function _TimerCallback(func, timer) {
if (typeof func !== "function")
throw new Error("string callbacks no longer accepted; use a function!");
do_throw("string callbacks no longer accepted; use a function!");
this._func = func;
this._start = Date.now();
this._delay = delay;
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(this, delay + _timerFuzz, timer.TYPE_ONE_SHOT);
// Keep timer alive until it fires
_pendingCallbacks.push(timer);
_pendingTimers.push(timer);
}
_TimerCallback.prototype = {
_Timer.prototype = {
QueryInterface: function(iid) {
if (iid.Equals(Components.interfaces.nsITimerCallback) ||
iid.Equals(Components.interfaces.nsISupports))
@ -108,8 +126,26 @@ _TimerCallback.prototype = {
},
notify: function(timer) {
_pendingCallbacks.splice(_pendingCallbacks.indexOf(timer), 1);
this._func.call(null);
_pendingTimers.splice(_pendingTimers.indexOf(timer), 1);
// The current nsITimer implementation can undershoot, but even if it
// couldn't, paranoia is probably a virtue here given the potential for
// random orange on tinderboxen.
var end = Date.now();
var elapsed = end - this._start;
if (elapsed >= this._delay) {
try {
this._func.call(null);
} catch (e) {
do_throw("exception thrown from callLater callback: " + e);
}
return;
}
// Timer undershot, retry with a little overshoot to try to avoid more
// undershoots.
var newDelay = this._delay - elapsed;
do_timeout(newDelay, this._func);
}
};
@ -223,11 +259,18 @@ function _load_files(aFiles) {
/************** Functions to be used from the tests **************/
/**
* Calls the given function at least the specified number of milliseconds later.
* The callback will not undershoot the given time, but it might overshoot --
* don't expect precision!
*
* @param delay : uint
* the number of milliseconds to delay
* @param callback : function() : void
* the function to call
*/
function do_timeout(delay, func) {
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(new _TimerCallback(func, timer), delay, timer.TYPE_ONE_SHOT);
new _Timer(func, Number(delay));
}
function do_execute_soon(callback) {