mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset 295b75fac0c8 (bug 940408) for test failures in B2g Desktop Linux & B2G ICS Emulator Opt
This commit is contained in:
parent
ed69377fa1
commit
325e1c28d4
@ -2549,7 +2549,7 @@ OverflowableToolbar.prototype = {
|
||||
this._lazyResizeHandler = new DeferredTask(this._onLazyResize.bind(this),
|
||||
LAZY_RESIZE_INTERVAL_MS);
|
||||
}
|
||||
this._lazyResizeHandler.arm();
|
||||
this._lazyResizeHandler.start();
|
||||
},
|
||||
|
||||
_moveItemsBackToTheirOrigin: function(shouldMoveAllItems) {
|
||||
@ -2608,7 +2608,7 @@ OverflowableToolbar.prototype = {
|
||||
this._enabled = false;
|
||||
this._moveItemsBackToTheirOrigin(true);
|
||||
if (this._lazyResizeHandler) {
|
||||
this._lazyResizeHandler.disarm();
|
||||
this._lazyResizeHandler.cancel();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -25,8 +25,6 @@ const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||
"resource://gre/modules/Downloads.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
|
||||
@ -1100,7 +1098,6 @@ this.DownloadAutoSaveView = function (aList, aStore)
|
||||
this._list = aList;
|
||||
this._store = aStore;
|
||||
this._downloadsMap = new Map();
|
||||
this._writer = new DeferredTask(() => this._store.save(), kSaveDelayMs);
|
||||
}
|
||||
|
||||
this.DownloadAutoSaveView.prototype = {
|
||||
@ -1141,9 +1138,45 @@ this.DownloadAutoSaveView.prototype = {
|
||||
_downloadsMap: null,
|
||||
|
||||
/**
|
||||
* DeferredTask for the save operation.
|
||||
* This is set to true when the save operation should be triggered. This is
|
||||
* required so that a new operation can be scheduled while the current one is
|
||||
* in progress, without re-entering the save method.
|
||||
*/
|
||||
_writer: null,
|
||||
_shouldSave: false,
|
||||
|
||||
/**
|
||||
* nsITimer used for triggering the save operation after a delay, or null if
|
||||
* saving has finished and there is no operation scheduled for execution.
|
||||
*
|
||||
* The logic here is different from the DeferredTask module in that multiple
|
||||
* requests will never delay the operation for longer than the expected time
|
||||
* (no grace delay), and the operation is never re-entered during execution.
|
||||
*/
|
||||
_timer: null,
|
||||
|
||||
/**
|
||||
* Timer callback used to serialize the list of downloads.
|
||||
*/
|
||||
_save: function ()
|
||||
{
|
||||
Task.spawn(function () {
|
||||
// Any save request received during execution will be handled later.
|
||||
this._shouldSave = false;
|
||||
|
||||
// Execute the asynchronous save operation.
|
||||
try {
|
||||
yield this._store.save();
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
||||
// Handle requests received during the operation.
|
||||
this._timer = null;
|
||||
if (this._shouldSave) {
|
||||
this.saveSoon();
|
||||
}
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the list of downloads changed, this triggers the asynchronous
|
||||
@ -1151,7 +1184,11 @@ this.DownloadAutoSaveView.prototype = {
|
||||
*/
|
||||
saveSoon: function ()
|
||||
{
|
||||
this._writer.arm();
|
||||
this._shouldSave = true;
|
||||
if (!this._timer) {
|
||||
this._timer = new Timer(this._save.bind(this), kSaveDelayMs,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -11,8 +11,6 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
|
||||
"resource://gre/modules/AsyncShutdown.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
@ -2657,7 +2655,7 @@ Engine.prototype = {
|
||||
url.addParam(aName, aValue);
|
||||
|
||||
// Serialize the changes to file lazily
|
||||
this.lazySerializeTask.arm();
|
||||
this.lazySerializeTask.start();
|
||||
},
|
||||
|
||||
#ifdef ANDROID
|
||||
@ -3873,8 +3871,7 @@ SearchService.prototype = {
|
||||
engine._initFromMetadata(aName, aIconURL, aAlias, aDescription,
|
||||
aMethod, aTemplate);
|
||||
this._addEngineToStore(engine);
|
||||
this.batchTask.disarm();
|
||||
this.batchTask.arm();
|
||||
this.batchTask.start();
|
||||
},
|
||||
|
||||
addEngine: function SRCH_SVC_addEngine(aEngineURL, aDataType, aIconURL,
|
||||
@ -3937,10 +3934,9 @@ SearchService.prototype = {
|
||||
engineToRemove.hidden = true;
|
||||
engineToRemove.alias = null;
|
||||
} else {
|
||||
// Cancel the serialized task if it's pending. Since the task is a
|
||||
// synchronous function, we don't need to wait on the "finalize" method.
|
||||
// Cancel the serialized task if it's running
|
||||
if (engineToRemove._lazySerializeTask) {
|
||||
engineToRemove._lazySerializeTask.disarm();
|
||||
engineToRemove._lazySerializeTask.cancel();
|
||||
engineToRemove._lazySerializeTask = null;
|
||||
}
|
||||
|
||||
@ -4139,19 +4135,22 @@ SearchService.prototype = {
|
||||
LOG("nsSearchService::observe: setting current");
|
||||
this.currentEngine = aEngine;
|
||||
}
|
||||
this.batchTask.disarm();
|
||||
this.batchTask.arm();
|
||||
this.batchTask.start();
|
||||
break;
|
||||
case SEARCH_ENGINE_CHANGED:
|
||||
case SEARCH_ENGINE_REMOVED:
|
||||
this.batchTask.disarm();
|
||||
this.batchTask.arm();
|
||||
this.batchTask.start();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIT_APPLICATION_TOPIC:
|
||||
this._removeObservers();
|
||||
if (this._batchTask) {
|
||||
// Flush to disk immediately
|
||||
this._batchTask.flush();
|
||||
}
|
||||
engineMetadataService.flush();
|
||||
break;
|
||||
|
||||
case "nsPref:changed":
|
||||
@ -4210,16 +4209,6 @@ SearchService.prototype = {
|
||||
Services.obs.addObserver(this, QUIT_APPLICATION_TOPIC, false);
|
||||
Services.prefs.addObserver(BROWSER_SEARCH_PREF + "defaultenginename", this, false);
|
||||
Services.prefs.addObserver(BROWSER_SEARCH_PREF + "selectedEngine", this, false);
|
||||
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"Search service: shutting down",
|
||||
() => Task.spawn(function () {
|
||||
if (this._batchTask) {
|
||||
yield this._batchTask.finalize().then(null, Cu.reportError);
|
||||
}
|
||||
yield engineMetadataService.finalize();
|
||||
}.bind(this))
|
||||
);
|
||||
},
|
||||
|
||||
_removeObservers: function SRCH_SVC_removeObservers() {
|
||||
@ -4439,8 +4428,11 @@ var engineMetadataService = {
|
||||
/**
|
||||
* Flush any waiting write.
|
||||
*/
|
||||
finalize: function () this._lazyWriter ? this._lazyWriter.finalize()
|
||||
: Promise.resolve(),
|
||||
flush: function epsFlush() {
|
||||
if (this._lazyWriter) {
|
||||
this._lazyWriter.flush();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Commit changes to disk, asynchronously.
|
||||
@ -4477,14 +4469,12 @@ var engineMetadataService = {
|
||||
LOG("metadata writeCommit: done");
|
||||
}
|
||||
);
|
||||
// Use our error logging instead of the default one.
|
||||
return TaskUtils.captureErrors(promise).then(null, () => {});
|
||||
TaskUtils.captureErrors(promise);
|
||||
}
|
||||
this._lazyWriter = new DeferredTask(writeCommit, LAZY_SERIALIZE_DELAY);
|
||||
}
|
||||
LOG("metadata _commit: (re)setting timer");
|
||||
this._lazyWriter.disarm();
|
||||
this._lazyWriter.arm();
|
||||
this._lazyWriter.start();
|
||||
},
|
||||
_lazyWriter: null
|
||||
};
|
||||
|
@ -187,17 +187,16 @@ let ActiveProviders = {
|
||||
|
||||
add: function (origin) {
|
||||
this._providers[origin] = 1;
|
||||
this._deferredTask.arm();
|
||||
this._deferredTask.start();
|
||||
},
|
||||
|
||||
delete: function (origin) {
|
||||
delete this._providers[origin];
|
||||
this._deferredTask.arm();
|
||||
this._deferredTask.start();
|
||||
},
|
||||
|
||||
flush: function () {
|
||||
this._deferredTask.disarm();
|
||||
this._persist();
|
||||
this._deferredTask.flush();
|
||||
},
|
||||
|
||||
get _deferredTask() {
|
||||
|
@ -1,299 +1,85 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
this.EXPORTED_SYMBOLS = ["DeferredTask"];
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"DeferredTask",
|
||||
];
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
/**
|
||||
* Sets up a function or an asynchronous task whose execution can be triggered
|
||||
* after a defined delay. Multiple attempts to run the task before the delay
|
||||
* has passed are coalesced. The task cannot be re-entered while running, but
|
||||
* can be executed again after a previous run finished.
|
||||
* A task that will run after a delay. Multiple attempts to run the same task
|
||||
* before the delay will be coalesced
|
||||
*
|
||||
* A common use case occurs when a data structure should be saved into a file
|
||||
* every time the data changes, using asynchronous calls, and multiple changes
|
||||
* to the data may happen within a short time:
|
||||
* Use this for instance if you write data to a file and you expect that you
|
||||
* may have to rewrite data very soon afterwards. With |DeferredTask|, the
|
||||
* task is delayed by a few milliseconds and, should a new change to the data
|
||||
* occur during this period,
|
||||
* 1/ only the final version of the data is actually written;
|
||||
* 2/ a further grace delay is added to take into account other changes.
|
||||
*
|
||||
* let saveDeferredTask = new DeferredTask(function* () {
|
||||
* yield OS.File.writeAtomic(...);
|
||||
* // Any uncaught exception will be reported.
|
||||
* }, 2000);
|
||||
*
|
||||
* // The task is ready, but will not be executed until requested.
|
||||
*
|
||||
* The "arm" method can be used to start the internal timer that will result in
|
||||
* the eventual execution of the task. Multiple attempts to arm the timer don't
|
||||
* introduce further delays:
|
||||
*
|
||||
* saveDeferredTask.arm();
|
||||
*
|
||||
* // The task will be executed in 2 seconds from now.
|
||||
*
|
||||
* yield waitOneSecond();
|
||||
* saveDeferredTask.arm();
|
||||
*
|
||||
* // The task will be executed in 1 second from now.
|
||||
*
|
||||
* The timer can be disarmed to reset the delay, or just to cancel execution:
|
||||
*
|
||||
* saveDeferredTask.disarm();
|
||||
* saveDeferredTask.arm();
|
||||
*
|
||||
* // The task will be executed in 2 seconds from now.
|
||||
*
|
||||
* When the internal timer fires and the execution of the task starts, the task
|
||||
* cannot be canceled anymore. It is however possible to arm the timer again
|
||||
* during the execution of the task, in which case the task will need to finish
|
||||
* before the timer is started again, thus guaranteeing a time of inactivity
|
||||
* between executions that is at least equal to the provided delay.
|
||||
*
|
||||
* The "finalize" method can be used to ensure that the task terminates
|
||||
* properly. The promise it returns is resolved only after the last execution
|
||||
* of the task is finished. To guarantee that the task is executed for the
|
||||
* last time, the method prevents any attempt to arm the timer again.
|
||||
*
|
||||
* If the timer is already armed when the "finalize" method is called, then the
|
||||
* task is executed immediately. If the task was already running at this point,
|
||||
* then one last execution from start to finish will happen again, immediately
|
||||
* after the current execution terminates. If the timer is not armed, the
|
||||
* "finalize" method only ensures that any running task terminates.
|
||||
*
|
||||
* For example, during shutdown, you may want to ensure that any pending write
|
||||
* is processed, using the latest version of the data if the timer is armed:
|
||||
*
|
||||
* AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
* "Example service: shutting down",
|
||||
* () => saveDeferredTask.finalize()
|
||||
* );
|
||||
*
|
||||
* Instead, if you are going to delete the saved data from disk anyways, you
|
||||
* might as well prevent any pending write from starting, while still ensuring
|
||||
* that any write that is currently in progress terminates, so that the file is
|
||||
* not in use anymore:
|
||||
*
|
||||
* saveDeferredTask.disarm();
|
||||
* saveDeferredTask.finalize().then(() => OS.File.remove(...))
|
||||
* .then(null, Components.utils.reportError);
|
||||
* Constructor
|
||||
* @param aDelay The delay time in milliseconds.
|
||||
* @param aCallback The code to execute after the delay.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
const Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer",
|
||||
"initWithCallback");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DeferredTask
|
||||
|
||||
/**
|
||||
* Sets up a task whose execution can be triggered after a delay.
|
||||
*
|
||||
* @param aTaskFn
|
||||
* Function or generator function to execute. This argument is passed to
|
||||
* the "Task.spawn" method every time the task should be executed. This
|
||||
* task is never re-entered while running.
|
||||
* @param aDelayMs
|
||||
* Time between executions, in milliseconds. Multiple attempts to run
|
||||
* the task before the delay has passed are coalesced. This time of
|
||||
* inactivity is guaranteed to pass between multiple executions of the
|
||||
* task, except on finalization, when the task may restart immediately
|
||||
* after the previous execution finished.
|
||||
*/
|
||||
this.DeferredTask = function (aTaskFn, aDelayMs) {
|
||||
this._taskFn = aTaskFn;
|
||||
this._delayMs = aDelayMs;
|
||||
this.DeferredTask = function DeferredTask(aCallback, aDelay) {
|
||||
this._callback = function onCallback() {
|
||||
this._timer = null;
|
||||
try {
|
||||
aCallback();
|
||||
} catch(e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}.bind(this);
|
||||
this._delay = aDelay;
|
||||
}
|
||||
|
||||
this.DeferredTask.prototype = {
|
||||
/**
|
||||
* Function or generator function to execute.
|
||||
*/
|
||||
_taskFn: null,
|
||||
|
||||
/**
|
||||
* Time between executions, in milliseconds.
|
||||
*/
|
||||
_delayMs: null,
|
||||
|
||||
/**
|
||||
* Indicates whether the task is currently requested to start again later,
|
||||
* regardless of whether it is currently running.
|
||||
*/
|
||||
get isArmed() this._armed,
|
||||
_armed: false,
|
||||
|
||||
/**
|
||||
* Indicates whether the task is currently running. This is always true when
|
||||
* read from code inside the task function, but can also be true when read
|
||||
* from external code, in case the task is an asynchronous generator function.
|
||||
*/
|
||||
get isRunning() !!this._runningPromise,
|
||||
|
||||
/**
|
||||
* Promise resolved when the current execution of the task terminates, or null
|
||||
* if the task is not currently running.
|
||||
*/
|
||||
_runningPromise: null,
|
||||
|
||||
/**
|
||||
* nsITimer used for triggering the task after a delay, or null in case the
|
||||
* task is running or there is no task scheduled for execution.
|
||||
*/
|
||||
DeferredTask.prototype = {
|
||||
/* Callback */
|
||||
_callback: null,
|
||||
/* Delay */
|
||||
_delay: null,
|
||||
/* Timer */
|
||||
_timer: null,
|
||||
|
||||
/**
|
||||
* Actually starts the timer with the delay specified on construction.
|
||||
* Check the current task state.
|
||||
* @returns true if pending, false otherwise.
|
||||
*/
|
||||
_startTimer: function ()
|
||||
{
|
||||
this._timer = new Timer(this._timerCallback.bind(this), this._delayMs,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
get isPending() {
|
||||
return (this._timer != null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Requests the execution of the task after the delay specified on
|
||||
* construction. Multiple calls don't introduce further delays. If the task
|
||||
* is running, the delay will start when the current execution finishes.
|
||||
*
|
||||
* The task will always be executed on a different tick of the event loop,
|
||||
* even if the delay specified on construction is zero. Multiple "arm" calls
|
||||
* within the same tick of the event loop are guaranteed to result in a single
|
||||
* execution of the task.
|
||||
*
|
||||
* @note By design, this method doesn't provide a way for the caller to detect
|
||||
* when the next execution terminates, or collect a result. In fact,
|
||||
* doing that would often result in duplicate processing or logging. If
|
||||
* a special operation or error logging is needed on completion, it can
|
||||
* be better handled from within the task itself, for example using a
|
||||
* try/catch/finally clause in the task. The "finalize" method can be
|
||||
* used in the common case of waiting for completion on shutdown.
|
||||
* Start (or postpone) task.
|
||||
*/
|
||||
arm: function ()
|
||||
{
|
||||
if (this._finalized) {
|
||||
throw new Error("Unable to arm timer, the object has been finalized.");
|
||||
}
|
||||
|
||||
this._armed = true;
|
||||
|
||||
// In case the timer callback is running, do not create the timer now,
|
||||
// because this will be handled by the timer callback itself. Also, the
|
||||
// timer is not restarted in case it is already running.
|
||||
if (!this._runningPromise && !this._timer) {
|
||||
this._startTimer();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancels any request for a delayed the execution of the task, though the
|
||||
* task itself cannot be canceled in case it is already running.
|
||||
*
|
||||
* This method stops any currently running timer, thus the delay will restart
|
||||
* from its original value in case the "arm" method is called again.
|
||||
*/
|
||||
disarm: function () {
|
||||
this._armed = false;
|
||||
start: function DeferredTask_start() {
|
||||
if (this._timer) {
|
||||
this._timer.cancel();
|
||||
}
|
||||
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._timer.initWithCallback(
|
||||
this._callback, this._delay, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform any postponed task immediately.
|
||||
*/
|
||||
flush: function DeferredTask_flush() {
|
||||
if (this._timer) {
|
||||
this.cancel();
|
||||
this._callback();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel any pending task.
|
||||
*/
|
||||
cancel: function DeferredTask_cancel() {
|
||||
if (this._timer) {
|
||||
// Calling the "cancel" method and discarding the timer reference makes
|
||||
// sure that the timer callback will not be called later, even if the
|
||||
// timer thread has already posted the timer event on the main thread.
|
||||
this._timer.cancel();
|
||||
this._timer = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures that any pending task is executed from start to finish, while
|
||||
* preventing any attempt to arm the timer again.
|
||||
*
|
||||
* - If the task is running and the timer is armed, then one last execution
|
||||
* from start to finish will happen again, immediately after the current
|
||||
* execution terminates, then the returned promise will be resolved.
|
||||
* - If the task is running and the timer is not armed, the returned promise
|
||||
* will be resolved when the current execution terminates.
|
||||
* - If the task is not running and the timer is armed, then the task is
|
||||
* started immediately, and the returned promise resolves when the new
|
||||
* execution terminates.
|
||||
* - If the task is not running and the timer is not armed, the method returns
|
||||
* a resolved promise.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves After the last execution of the task is finished.
|
||||
* @rejects Never.
|
||||
*/
|
||||
finalize: function () {
|
||||
if (this._finalized) {
|
||||
throw new Error("The object has been already finalized.");
|
||||
}
|
||||
this._finalized = true;
|
||||
|
||||
// If the timer is armed, it means that the task is not running but it is
|
||||
// scheduled for execution. Cancel the timer and run the task immediately.
|
||||
if (this._timer) {
|
||||
this.disarm();
|
||||
this._timerCallback();
|
||||
}
|
||||
|
||||
// Wait for the operation to be completed, or resolve immediately.
|
||||
if (this._runningPromise) {
|
||||
return this._runningPromise;
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
_finalized: false,
|
||||
|
||||
/**
|
||||
* Timer callback used to run the delayed task.
|
||||
*/
|
||||
_timerCallback: function ()
|
||||
{
|
||||
let runningDeferred = Promise.defer();
|
||||
|
||||
// All these state changes must occur at the same time directly inside the
|
||||
// timer callback, to prevent race conditions and to ensure that all the
|
||||
// methods behave consistently even if called from inside the task. This
|
||||
// means that the assignment of "this._runningPromise" must complete before
|
||||
// the task gets a chance to start.
|
||||
this._timer = null;
|
||||
this._armed = false;
|
||||
this._runningPromise = runningDeferred.promise;
|
||||
|
||||
runningDeferred.resolve(Task.spawn(function () {
|
||||
// Execute the provided function asynchronously.
|
||||
yield Task.spawn(this._taskFn).then(null, Cu.reportError);
|
||||
|
||||
// Now that the task has finished, we check the state of the object to
|
||||
// determine if we should restart the task again.
|
||||
if (this._armed) {
|
||||
if (!this._finalized) {
|
||||
this._startTimer();
|
||||
} else {
|
||||
// Execute the task again immediately, for the last time. The isArmed
|
||||
// property should return false while the task is running, and should
|
||||
// remain false after the last execution terminates.
|
||||
this._armed = false;
|
||||
yield Task.spawn(this._taskFn).then(null, Cu.reportError);
|
||||
}
|
||||
}
|
||||
|
||||
// Indicate that the execution of the task has finished. This happens
|
||||
// synchronously with the previous state changes in the function.
|
||||
this._runningPromise = null;
|
||||
}.bind(this)).then(null, Cu.reportError));
|
||||
},
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
[DEFAULT]
|
||||
|
||||
[browser_DeferredTask.js]
|
||||
[browser_Deprecated.js]
|
||||
[browser_Finder.js]
|
||||
[browser_Geometry.js]
|
||||
|
166
toolkit/modules/tests/browser/browser_DeferredTask.js
Normal file
166
toolkit/modules/tests/browser/browser_DeferredTask.js
Normal file
@ -0,0 +1,166 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
let DeferredTask =
|
||||
Components.utils.import("resource://gre/modules/DeferredTask.jsm", {}).DeferredTask;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function nextTest() {
|
||||
let test = tests.shift();
|
||||
if (test) {
|
||||
info("Starting " + test.name);
|
||||
executeSoon(test.bind(null, nextTest));
|
||||
} else {
|
||||
executeSoon(finish);
|
||||
}
|
||||
}
|
||||
|
||||
let tests = [
|
||||
function checkRanOnce(next) {
|
||||
// Test that a deferred task runs only once.
|
||||
let deferredTaskCounter = 0;
|
||||
let deferredTask = new DeferredTask(function checkDeferred() {
|
||||
is(++deferredTaskCounter, 1, "Deferred task ran once");
|
||||
if (deferredTaskCounter > 1)
|
||||
return; // shouldn't happen!
|
||||
next();
|
||||
}, 100);
|
||||
|
||||
deferredTask.start();
|
||||
deferredTask.start();
|
||||
deferredTask.start();
|
||||
},
|
||||
|
||||
function testOrdering(next) {
|
||||
// Test the deferred task running order.
|
||||
let ARan, BRan;
|
||||
let deferredTaskA = new DeferredTask(function () {
|
||||
info("Deferred task A running");
|
||||
ARan = true;
|
||||
ok(!BRan, "Deferred task B shouldn't have run yet");
|
||||
}, 10);
|
||||
let deferredTaskB = new DeferredTask(function () {
|
||||
info("Deferred task B running");
|
||||
BRan = true;
|
||||
ok(ARan, "Deferred task A should have run already");
|
||||
executeSoon(next);
|
||||
}, 100);
|
||||
|
||||
deferredTaskA.start();
|
||||
deferredTaskB.start();
|
||||
},
|
||||
|
||||
function testFlush(next) {
|
||||
// Test the flush method.
|
||||
let deferedTaskCounter = 0;
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
is(++deferedTaskCounter, 1, "Deferred task should only run once");
|
||||
}, 10);
|
||||
|
||||
is(deferedTaskCounter, 0, "Deferred task shouldn't run right away");
|
||||
deferredTask.flush();
|
||||
is(deferedTaskCounter, 0, "Deferred task shouldn't run after flush() if it wasn't started");
|
||||
deferredTask.start();
|
||||
is(deferedTaskCounter, 0, "Deferred task shouldn't run immediately after start");
|
||||
deferredTask.flush();
|
||||
is(deferedTaskCounter, 1, "Deferred task should run after flush() after being started");
|
||||
next();
|
||||
},
|
||||
|
||||
function testCancel(next) {
|
||||
// Test the cancel method.
|
||||
let deferredTask1, deferredTask2, deferredTask3;
|
||||
let deferredTask2Ran = false;
|
||||
deferredTask1 = new DeferredTask(function () {
|
||||
info("Deferred task 1 running");
|
||||
deferredTask2.cancel();
|
||||
info("Deferred task 2 canceled");
|
||||
}, 10);
|
||||
deferredTask2 = new DeferredTask(function () {
|
||||
info("Deferred task 2 running");
|
||||
deferredTask2Ran = true;
|
||||
}, 100);
|
||||
deferredTask3 = new DeferredTask(function () {
|
||||
info("Deferred task 3 running");
|
||||
is(deferredTask2Ran, false, "Deferred task 2 shouldn't run");
|
||||
next();
|
||||
}, 200);
|
||||
|
||||
deferredTask1.start();
|
||||
deferredTask2.start();
|
||||
deferredTask3.start();
|
||||
},
|
||||
|
||||
function testIsPending(next) {
|
||||
// Test the pending property.
|
||||
let deferredTask1, deferredTask2;
|
||||
let deferredTask1 = new DeferredTask(function () {
|
||||
info("Deferred task 1 running");
|
||||
is(deferredTask1.isPending, false, "Deferred task 1 shouldn't be pending");
|
||||
is(deferredTask2.isPending, true, "Deferred task 2 should be pending");
|
||||
}, 100);
|
||||
let deferredTask2 = new DeferredTask(function () {
|
||||
info("Deferred task 2 running");
|
||||
is(deferredTask1.isPending, false, "Deferred task 1 shouldn't be pending");
|
||||
is(deferredTask2.isPending, false, "Deferred task 2 shouldn't be pending");
|
||||
next();
|
||||
}, 200);
|
||||
|
||||
is(deferredTask1.isPending, false, "Deferred task 1 shouldn't be pending");
|
||||
is(deferredTask2.isPending, false, "Deferred task 2 shouldn't be pending");
|
||||
deferredTask1.start();
|
||||
deferredTask2.start();
|
||||
is(deferredTask1.isPending, true, "Deferred task 1 should be pending");
|
||||
is(deferredTask2.isPending, true, "Deferred task 2 should be pending");
|
||||
},
|
||||
|
||||
function testRestartingTask(next) {
|
||||
// Test restarting a task from other task.
|
||||
let deferredTask1, deferredTask2, deferredTask3;
|
||||
let deferredTask1 = new DeferredTask(function () {
|
||||
info("Deferred task 1 running");
|
||||
is(deferredTask1.isPending, false, "Deferred task 1 shouldn't be pending");
|
||||
is(deferredTask2.isPending, false, "Deferred task 2 shouldn't be pending");
|
||||
is(deferredTask3.isPending, false, "Deferred task 3 shouldn't be pending");
|
||||
next();
|
||||
}, 100);
|
||||
let deferredTask2 = new DeferredTask(function () {
|
||||
info("Deferred task 2 running");
|
||||
deferredTask1.start();
|
||||
deferredTask3.start();
|
||||
}, 50);
|
||||
let deferredTask3 = new DeferredTask(function () {
|
||||
info("Deferred task 3 running");
|
||||
is(deferredTask1.isPending, true, "Deferred task 1 should be pending");
|
||||
}, 75);
|
||||
|
||||
deferredTask1.start();
|
||||
deferredTask2.start();
|
||||
},
|
||||
|
||||
function testRestartItselfTask(next) {
|
||||
// Test restarting a task from the same task callback.
|
||||
let deferredTask;
|
||||
let taskReRun = false;
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
info("Deferred task running");
|
||||
is(deferredTask.isPending, false, "Deferred task shouldn't be pending");
|
||||
if (!taskReRun) {
|
||||
taskReRun = true;
|
||||
info("Deferred task restart");
|
||||
deferredTask.start();
|
||||
is(deferredTask.isPending, true, "Deferred task should be pending");
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
deferredTask.start();
|
||||
}
|
||||
];
|
@ -1,392 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* This file tests the DeferredTask.jsm module.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Globals
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
/**
|
||||
* Due to the nature of this module, most of the tests are time-dependent. All
|
||||
* the timeouts are designed to occur at multiples of this granularity value,
|
||||
* in milliseconds, that should be high enough to prevent intermittent failures,
|
||||
* but low enough to prevent an excessive overall test execution time.
|
||||
*/
|
||||
const T = 100;
|
||||
|
||||
/**
|
||||
* Waits for the specified timeout before resolving the returned promise.
|
||||
*/
|
||||
function promiseTimeout(aTimeoutMs)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
do_timeout(aTimeoutMs, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Tests
|
||||
|
||||
/**
|
||||
* Creates a simple DeferredTask and executes it once.
|
||||
*/
|
||||
add_test(function test_arm_simple()
|
||||
{
|
||||
new DeferredTask(run_next_test, 10).arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the delay set for the task is respected.
|
||||
*/
|
||||
add_test(function test_arm_delay_respected()
|
||||
{
|
||||
let executed1 = false;
|
||||
let executed2 = false;
|
||||
|
||||
new DeferredTask(function () {
|
||||
executed1 = true;
|
||||
do_check_false(executed2);
|
||||
}, 1*T).arm();
|
||||
|
||||
new DeferredTask(function () {
|
||||
executed2 = true;
|
||||
do_check_true(executed1);
|
||||
run_next_test();
|
||||
}, 2*T).arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "arm" again does not introduce further delay.
|
||||
*/
|
||||
add_test(function test_arm_delay_notrestarted()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
// Create a task that will run later.
|
||||
let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
|
||||
deferredTask.arm();
|
||||
|
||||
// Before the task starts, call "arm" again.
|
||||
do_timeout(2*T, () => deferredTask.arm());
|
||||
|
||||
// The "arm" call should not have introduced further delays.
|
||||
do_timeout(5*T, function () {
|
||||
do_check_true(executed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that a task runs only once when armed multiple times synchronously.
|
||||
*/
|
||||
add_test(function test_arm_coalesced()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_false(executed);
|
||||
executed = true;
|
||||
run_next_test();
|
||||
}, 50);
|
||||
|
||||
deferredTask.arm();
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that a task runs only once when armed multiple times synchronously,
|
||||
* even when it has been created with a delay of zero milliseconds.
|
||||
*/
|
||||
add_test(function test_arm_coalesced_nodelay()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_false(executed);
|
||||
executed = true;
|
||||
run_next_test();
|
||||
}, 0);
|
||||
|
||||
deferredTask.arm();
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that a task can be armed again while running.
|
||||
*/
|
||||
add_test(function test_arm_recursive()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
if (!executed) {
|
||||
executed = true;
|
||||
deferredTask.arm();
|
||||
} else {
|
||||
run_next_test();
|
||||
}
|
||||
}, 50);
|
||||
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "arm" while an asynchronous task is running waits until
|
||||
* the task is finished before restarting the delay.
|
||||
*/
|
||||
add_test(function test_arm_async()
|
||||
{
|
||||
let finishedExecution = false;
|
||||
let finishedExecutionAgain = false;
|
||||
|
||||
// Create a task that will run later.
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
yield promiseTimeout(4*T);
|
||||
if (!finishedExecution) {
|
||||
finishedExecution = true;
|
||||
} else if (!finishedExecutionAgain) {
|
||||
finishedExecutionAgain = true;
|
||||
}
|
||||
}, 2*T);
|
||||
deferredTask.arm();
|
||||
|
||||
// While the task is running, call "arm" again. This will result in a wait
|
||||
// of 2*T until the task finishes, then another 2*T for the normal task delay
|
||||
// specified on construction.
|
||||
do_timeout(4*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(finishedExecution);
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
// This will fail in case the task was started without waiting 2*T after it
|
||||
// has finished.
|
||||
do_timeout(7*T, function () {
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_true(finishedExecution);
|
||||
});
|
||||
|
||||
// This is in the middle of the second execution.
|
||||
do_timeout(10*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(finishedExecutionAgain);
|
||||
});
|
||||
|
||||
// Wait enough time to verify that the task was executed as expected.
|
||||
do_timeout(13*T, function () {
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_true(finishedExecutionAgain);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that an armed task can be disarmed.
|
||||
*/
|
||||
add_test(function test_disarm()
|
||||
{
|
||||
// Create a task that will run later.
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_throw("This task should not run.");
|
||||
}, 2*T);
|
||||
deferredTask.arm();
|
||||
|
||||
// Disable execution later, but before the task starts.
|
||||
do_timeout(1*T, () => deferredTask.disarm());
|
||||
|
||||
// Wait enough time to verify that the task did not run.
|
||||
do_timeout(3*T, run_next_test);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "disarm" allows the delay to be restarted.
|
||||
*/
|
||||
add_test(function test_disarm_delay_restarted()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(2*T, function () {
|
||||
deferredTask.disarm();
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
do_timeout(5*T, function () {
|
||||
do_check_false(executed);
|
||||
});
|
||||
|
||||
do_timeout(7*T, function () {
|
||||
do_check_true(executed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "disarm" while an asynchronous task is running does not
|
||||
* prevent the task to finish.
|
||||
*/
|
||||
add_test(function test_disarm_async()
|
||||
{
|
||||
let finishedExecution = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
deferredTask.arm();
|
||||
yield promiseTimeout(2*T);
|
||||
finishedExecution = true;
|
||||
}, 1*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(2*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_true(deferredTask.isArmed);
|
||||
do_check_false(finishedExecution);
|
||||
deferredTask.disarm();
|
||||
});
|
||||
|
||||
do_timeout(4*T, function () {
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
do_check_true(finishedExecution);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "arm" immediately followed by "disarm" while an
|
||||
* asynchronous task is running does not cause it to run again.
|
||||
*/
|
||||
add_test(function test_disarm_immediate_async()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_false(executed);
|
||||
executed = true;
|
||||
yield promiseTimeout(2*T);
|
||||
}, 1*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(2*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
deferredTask.arm();
|
||||
deferredTask.disarm();
|
||||
});
|
||||
|
||||
do_timeout(4*T, function () {
|
||||
do_check_true(executed);
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks the isArmed and isRunning properties with a synchronous task.
|
||||
*/
|
||||
add_test(function test_isArmed_isRunning()
|
||||
{
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
deferredTask.arm();
|
||||
do_check_true(deferredTask.isArmed);
|
||||
deferredTask.disarm();
|
||||
do_check_false(deferredTask.isArmed);
|
||||
run_next_test();
|
||||
}, 50);
|
||||
|
||||
do_check_false(deferredTask.isArmed);
|
||||
deferredTask.arm();
|
||||
do_check_true(deferredTask.isArmed);
|
||||
do_check_false(deferredTask.isRunning);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the "finalize" method executes a synchronous task.
|
||||
*/
|
||||
add_test(function test_finalize()
|
||||
{
|
||||
let executed = false;
|
||||
let timePassed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_false(timePassed);
|
||||
executed = true;
|
||||
}, 2*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(1*T, () => { timePassed = true; });
|
||||
|
||||
// This should trigger the immediate execution of the task.
|
||||
deferredTask.finalize().then(function () {
|
||||
do_check_true(executed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the "finalize" method executes the task again from start to
|
||||
* finish in case it is already running.
|
||||
*/
|
||||
add_test(function test_finalize_executes_entirely()
|
||||
{
|
||||
let executed = false;
|
||||
let executedAgain = false;
|
||||
let timePassed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
// The first time, we arm the timer again and set up the finalization.
|
||||
if (!executed) {
|
||||
deferredTask.arm();
|
||||
do_check_true(deferredTask.isArmed);
|
||||
do_check_true(deferredTask.isRunning);
|
||||
|
||||
deferredTask.finalize().then(function () {
|
||||
// When we reach this point, the task must be finished.
|
||||
do_check_true(executedAgain);
|
||||
do_check_false(timePassed);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
do_check_false(deferredTask.isRunning);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// The second execution triggered by the finalization waits 1*T for the
|
||||
// current task to finish (see the timeout below), but then it must not
|
||||
// wait for the 2*T specified on construction as normal task delay. The
|
||||
// second execution will finish after the timeout below has passed again,
|
||||
// for a total of 2*T of wait time.
|
||||
do_timeout(3*T, () => { timePassed = true; });
|
||||
}
|
||||
|
||||
yield promiseTimeout(1*T);
|
||||
|
||||
// Just before finishing, indicate if we completed the second execution.
|
||||
if (executed) {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
executedAgain = true;
|
||||
} else {
|
||||
executed = true;
|
||||
}
|
||||
}, 2*T);
|
||||
|
||||
deferredTask.arm();
|
||||
});
|
@ -118,18 +118,6 @@ add_test(function test_spawn_function()
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_spawn_function_returning_promise()
|
||||
{
|
||||
Task.spawn(function () {
|
||||
return promiseResolvedLater("Resolution value.");
|
||||
}).then(function (result) {
|
||||
do_check_eq("Resolution value.", result);
|
||||
run_next_test();
|
||||
}, function (ex) {
|
||||
do_throw("Unexpected error: " + ex);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_spawn_function_exceptions()
|
||||
{
|
||||
Task.spawn(function () {
|
||||
|
@ -7,7 +7,6 @@ support-files =
|
||||
chromeappsstore.sqlite
|
||||
|
||||
[test_AsyncShutdown.js]
|
||||
[test_DeferredTask.js]
|
||||
[test_dict.js]
|
||||
[test_FileUtils.js]
|
||||
[test_Http.js]
|
||||
|
Loading…
Reference in New Issue
Block a user