Files
Mozilla/mozilla/zap/base/AsyncUtils.js
alex%croczilla.com 961053a4be Fix ui <--> media thread race conditions by moving from bidirectional sync communication model to a sync/async model.
git-svn-id: svn://10.0.0.236/branches/ZAP_20050610_BRANCH@209696 18797224-902f-48f8-a5cc-f745e15eee43
2006-09-11 10:20:49 +00:00

165 lines
6.7 KiB
JavaScript

/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 moz-jssh-buffer-globalobj: "Components.utils.importModule('gre:AsyncUtils.js', null)" -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SIP client project.
*
* The Initial Developer of the Original Code is 8x8 Inc.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Fritze <alex@croczilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
Components.utils.importModule("gre:FunctionUtils.js");
EXPORTED_SYMBOLS = [ "getMainThread",
"getSyncProxyOnMainThread",
"getAsyncProxyOnMainThread",
"makeOneShotTimer",
"resetOneShotTimer",
"schedule",
"schedulePeriodic",
"callAsync"];
////////////////////////////////////////////////////////////////////////
// Threads
var getThreadManager = makeServiceGetter("@mozilla.org/thread-manager;1",
Components.interfaces.nsIThreadManager);
var IProxyManager = Components.interfaces.nsIProxyObjectManager;
var getProxyManager = makeServiceGetter("@mozilla.org/xpcomproxy;1",
IProxyManager);
defun(
function getMainThread() {
return getThreadManager().mainThread;
});
defun(
function getSyncProxyOnMainThread(obj, itf) {
return getProxyManager().getProxyForObject(getMainThread(),
itf, obj,
IProxyManager.INVOKE_SYNC |
IProxyManager.FORCE_PROXY_CREATION);
});
defun(
function getAsyncProxyOnMainThread(obj, itf) {
return getProxyManager().getProxyForObject(getMainThread(),
itf, obj,
IProxyManager.INVOKE_ASYNC |
IProxyManager.FORCE_PROXY_CREATION);
});
////////////////////////////////////////////////////////////////////////
// Timer utilities:
var CLASS_TIMER = "@mozilla.org/timer;1";
defun(
"Create a new one-shot timer\n"+
" 'callback' must implement nsITimerCallback\n"+
" 'duration' is the time in ms after which the timer fires\n"+
"The timer can be cancelled with timer.cancel() and reset with a "+
"different duration using resetOneShotTimer(.).",
function makeOneShotTimer(callback, duration) {
// We need to use 'this.Components' to ensure that xpconnect wraps
// the timer for the caller's global object (assuming that the
// callback has the same global object). See also the comments in
// ClassUtils.js, function makeClass().
var timer = this.Components.classes[CLASS_TIMER].createInstance(this.Components.interfaces.nsITimer);
timer.initWithCallback(callback, duration, this.Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return timer;
});
defun(
function resetOneShotTimer(timer, duration) {
timer.initWithCallback(timer.callback, duration, this.Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return timer;
});
defun(
"Asynchronously call 'fct' after 'interval' ms. ",
function schedule(fct, interval) {
// We'll hold onto the timer object in the closure to prevent it
// from being garbarge collected.
var timer = makeOneShotTimer(
{
notify : function(t) {
fct();
// Now make sure that the timer can be garbage collected:
timer = null;
}
},
interval);
});
// helper for schedulePeriodic:
function callback(fct) {
this.fct = fct;
}
callback.prototype.notify = function(t) { this.fct(); };
defun(
"Periodically make an asynchronous call to 'fct' every 'period' "+
"ms. Return timer object. Calling 'cancel()' on the return value "+
"will cancel the schedule.\n"+
"The caller must hold onto the timer object for as long as the timer is "+
"supposed to run (otherwise it might be garbage collected).",
function schedulePeriodic(fct, period) {
var timer = this.Components.classes[CLASS_TIMER].createInstance(this.Components.interfaces.nsITimer);
// to prevent a reference cycle it is important here that the
// callback object is not created with the 'schedulePeriodic'
// closure (because this closure will keep the timer alive through
// the 'timer' variable).
timer.initWithCallback(new callback(fct),
period,
this.Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
return timer;
});
defun(
"Call 'fct' asynchronously.",
function callAsync(fct) {
schedule(fct, 0);
// // XXX we *really* want a new method on nsIEventTarget for posting
// // from JS here. setTimeout is not a good idea, since, among other
// // things, it sets up a 10ms timer even if the timeout value is 0ms.
// // This means that there is the potential for race conditions - the
// // call is not guaranteed to be the next one in the queue.
// var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
// .getService(Components.interfaces.nsIWindowMediator);
// var enumerator = wm.getEnumerator(null);
// var retval = [];
// if (!enumerator.hasMoreElements()) return; // can't post
// enumerator.getNext().setTimeout(fct, 0);
});