зеркало из https://github.com/mozilla/gecko-dev.git
Back out changeset b83d3c8ac166 (bug 460811) to try to fix bustage ... re-adding removed files
This commit is contained in:
Родитель
263fe2964e
Коммит
bf9b4fe931
|
@ -0,0 +1,149 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* ***** 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 worker threads.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
* Ben Turner <bent.mozilla@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIScriptError;
|
||||
|
||||
[scriptable, function, uuid(e50ca05d-1381-4abb-a021-02eb720cfc38)]
|
||||
interface nsIDOMWorkerMessageListener : nsISupports
|
||||
{
|
||||
/**
|
||||
* An nsIDOMWorkerThread receives the onMessage callback when another
|
||||
* worker posts a message to it.
|
||||
*
|
||||
* @param aMessage (in DOMString)
|
||||
* The message sent from another worker.
|
||||
* @param aSource (in nsISupports)
|
||||
* The worker that sent the message. Useful for a quick response.
|
||||
*/
|
||||
void onMessage(in DOMString aMessage,
|
||||
in nsISupports aSource);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(9df8422e-25dd-43f4-b9b9-709f9e074647)]
|
||||
interface nsIDOMWorkerErrorListener : nsISupports
|
||||
{
|
||||
/**
|
||||
* An nsIDOMWorkerPool receives the onError callback when one of its child
|
||||
* workers has a parse error or an unhandled exception.
|
||||
*
|
||||
* @param aMessage (in nsIScriptError)
|
||||
* Details about the error that occurred. See nsIScriptError.
|
||||
* @param aSource (in nsISupports)
|
||||
* The worker that sent the message. Depending on the specific error in
|
||||
* question it may not be possible to use this object (in the case of a
|
||||
* parse error, for instance, aSource will be unusable).
|
||||
*/
|
||||
void onError(in nsIScriptError aError,
|
||||
in nsISupports aSource);
|
||||
};
|
||||
|
||||
[scriptable, uuid(6f19f3ff-2aaa-4504-9b71-dca3c191efed)]
|
||||
interface nsIDOMWorkerThread : nsISupports
|
||||
{
|
||||
/**
|
||||
* Sends a message to the worker.
|
||||
*
|
||||
* @param aMessage (in DOMString)
|
||||
* The message to send.
|
||||
*/
|
||||
void postMessage(in DOMString aMessage);
|
||||
};
|
||||
|
||||
[scriptable, uuid(45312e93-8a3e-4493-9bd9-272a6c23a16c)]
|
||||
interface nsIDOMWorkerPool : nsISupports
|
||||
{
|
||||
/**
|
||||
* Sends a message to the pool.
|
||||
*
|
||||
* @param aMessage (in DOMString)
|
||||
* The message to send..
|
||||
*/
|
||||
void postMessage(in DOMString aMessage);
|
||||
|
||||
/**
|
||||
* The nsIDOMWorkerMessageListener which handles messages for this worker.
|
||||
*
|
||||
* Developers should set this attribute to a proper object before another
|
||||
* worker begins sending messages to ensure that all messages are received.
|
||||
*/
|
||||
attribute nsIDOMWorkerMessageListener messageListener;
|
||||
|
||||
/**
|
||||
* The nsIDOMWorkerErrorListener which handles errors in child threads.
|
||||
*
|
||||
* Developers should set this attribute to a proper object before calling
|
||||
* createWorker in order to catch parse errors as well as runtime exceptions.
|
||||
*/
|
||||
attribute nsIDOMWorkerErrorListener errorListener;
|
||||
|
||||
/**
|
||||
* Create a new worker object by evaluating the given script.
|
||||
*
|
||||
* @param aSourceScript (in DOMString)
|
||||
* The script to compile. See below for details on the scope in which
|
||||
* the script will run.
|
||||
*/
|
||||
nsIDOMWorkerThread createWorker(in DOMString aSourceScript);
|
||||
|
||||
/**
|
||||
* Create a new worker object by evaluating the given script.
|
||||
*
|
||||
* @param aSourceURL (in AString)
|
||||
* The script url to load and compile. See below for details on the
|
||||
* scope in which the script will run.
|
||||
*/
|
||||
nsIDOMWorkerThread createWorkerFromURL(in AString aSourceURL);
|
||||
};
|
||||
|
||||
[scriptable, uuid(0f2a52ea-afc9-49e6-86dd-2d0cb65b5dd5)]
|
||||
interface nsIDOMThreadService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Creates a new DOM worker pool.
|
||||
*/
|
||||
nsIDOMWorkerPool createPool();
|
||||
};
|
||||
|
||||
[scriptable, uuid(fcf387be-a7e3-4283-8bc5-06bfe13c5e8c)]
|
||||
interface nsIDOMWorkerThreadContext : nsISupports
|
||||
{
|
||||
readonly attribute nsIDOMWorkerThread thisThread;
|
||||
};
|
|
@ -0,0 +1,984 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* ***** 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 worker threads.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
* Ben Turner <bent.mozilla@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nsDOMWorkerThread.h"
|
||||
|
||||
// Interfaces
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIJSRuntimeService.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
||||
// Other includes
|
||||
#ifdef MOZ_SHARK
|
||||
#include "jsdbgapi.h"
|
||||
#endif
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
// DOMWorker includes
|
||||
#include "nsDOMWorkerPool.h"
|
||||
#include "nsDOMWorkerScriptLoader.h"
|
||||
#include "nsDOMWorkerSecurityManager.h"
|
||||
#include "nsDOMThreadService.h"
|
||||
#include "nsDOMWorkerTimeout.h"
|
||||
#include "nsDOMWorkerXHR.h"
|
||||
|
||||
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
|
||||
|
||||
// XXX Could make these functions of nsDOMWorkerThread instead.
|
||||
class nsDOMWorkerFunctions
|
||||
{
|
||||
public:
|
||||
// Same as window.dump().
|
||||
static JSBool Dump(JSContext* aCx, JSObject* aObj, uintN aArgc, jsval* aArgv,
|
||||
jsval* aRval);
|
||||
|
||||
// Debug-only version of window.dump(), like the JS component loader has.
|
||||
static JSBool DebugDump(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval);
|
||||
|
||||
// Same as nsIDOMWorkerThread::PostMessage
|
||||
static JSBool PostMessage(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval);
|
||||
|
||||
// Same as window.setTimeout().
|
||||
static JSBool SetTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval) {
|
||||
return MakeTimeout(aCx, aObj, aArgc, aArgv, aRval, PR_FALSE);
|
||||
}
|
||||
|
||||
// Same as window.setInterval().
|
||||
static JSBool SetInterval(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval) {
|
||||
return MakeTimeout(aCx, aObj, aArgc, aArgv, aRval, PR_TRUE);
|
||||
}
|
||||
|
||||
// Used for both clearTimeout() and clearInterval().
|
||||
static JSBool KillTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval);
|
||||
|
||||
static JSBool LoadScripts(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval);
|
||||
|
||||
static JSBool NewXMLHttpRequest(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval);
|
||||
|
||||
private:
|
||||
// Internal helper for SetTimeout and SetInterval.
|
||||
static JSBool MakeTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
|
||||
jsval* aArgv, jsval* aRval, PRBool aIsInterval);
|
||||
};
|
||||
|
||||
JSBool
|
||||
nsDOMWorkerFunctions::Dump(JSContext* aCx,
|
||||
JSObject* /* aObj */,
|
||||
uintN aArgc,
|
||||
jsval* aArgv,
|
||||
jsval* /* aRval */)
|
||||
{
|
||||
// XXX Expose this to the JS console? Only if that DOM pref is set?
|
||||
|
||||
JSString* str;
|
||||
if (aArgc && (str = JS_ValueToString(aCx, aArgv[0])) && str) {
|
||||
nsDependentJSString string(str);
|
||||
fputs(NS_ConvertUTF16toUTF8(nsDependentJSString(str)).get(), stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
nsDOMWorkerFunctions::DebugDump(JSContext* aCx,
|
||||
JSObject* aObj,
|
||||
uintN aArgc,
|
||||
jsval* aArgv,
|
||||
jsval* aRval)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
return nsDOMWorkerFunctions::Dump(aCx, aObj, aArgc, aArgv, aRval);
|
||||
#else
|
||||
return JS_TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JSBool
|
||||
nsDOMWorkerFunctions::PostMessage(JSContext* aCx,
|
||||
JSObject* /* aObj */,
|
||||
uintN aArgc,
|
||||
jsval* aArgv,
|
||||
jsval* /* aRval */)
|
||||
{
|
||||
nsDOMWorkerThread* worker =
|
||||
static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
|
||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||
|
||||
if (worker->IsCanceled()) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMWorkerPool> pool = worker->Pool();
|
||||
NS_ASSERTION(pool, "Shouldn't ever be null!");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
JSString* str;
|
||||
if (aArgc && (str = JS_ValueToString(aCx, aArgv[0])) && str) {
|
||||
rv = pool->PostMessageInternal(nsDependentJSString(str), worker);
|
||||
}
|
||||
else {
|
||||
rv = pool->PostMessageInternal(EmptyString(), worker);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to post message!");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx,
|
||||
JSObject* /* aObj */,
|
||||
uintN aArgc,
|
||||
jsval* aArgv,
|
||||
jsval* aRval,
|
||||
PRBool aIsInterval)
|
||||
{
|
||||
nsDOMWorkerThread* worker =
|
||||
static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
|
||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||
|
||||
if (worker->IsCanceled()) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 id = ++worker->mNextTimeoutId;
|
||||
|
||||
nsAutoPtr<nsDOMWorkerTimeout>
|
||||
timeout(new nsDOMWorkerTimeout(worker, id));
|
||||
if (!timeout) {
|
||||
JS_ReportOutOfMemory(aCx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsresult rv = timeout->Init(aCx, aArgc, aArgv, aIsInterval);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to initialize timeout!");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
timeout.forget();
|
||||
|
||||
*aRval = INT_TO_JSVAL(id);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
nsDOMWorkerFunctions::KillTimeout(JSContext* aCx,
|
||||
JSObject* /* aObj */,
|
||||
uintN aArgc,
|
||||
jsval* aArgv,
|
||||
jsval* /* aRval */)
|
||||
{
|
||||
nsDOMWorkerThread* worker =
|
||||
static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
|
||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||
|
||||
// A canceled worker should have already killed all timeouts.
|
||||
if (worker->IsCanceled()) {
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (!aArgc) {
|
||||
JS_ReportError(aCx, "Function requires at least 1 parameter");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
uint32 id;
|
||||
if (!JS_ValueToECMAUint32(aCx, aArgv[0], &id)) {
|
||||
JS_ReportError(aCx, "First argument must be a timeout id");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
worker->CancelTimeout(PRUint32(id));
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
|
||||
JSObject* /* aObj */,
|
||||
uintN aArgc,
|
||||
jsval* aArgv,
|
||||
jsval* /* aRval */)
|
||||
{
|
||||
nsDOMWorkerThread* worker =
|
||||
static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
|
||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||
|
||||
if (worker->IsCanceled()) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (!aArgc) {
|
||||
JS_ReportError(aCx, "Function must have at least one argument!");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsAutoTArray<nsString, 5> urls;
|
||||
|
||||
if (!urls.SetCapacity((PRUint32)aArgc)) {
|
||||
JS_ReportOutOfMemory(aCx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
for (uintN index = 0; index < aArgc; index++) {
|
||||
jsval val = aArgv[index];
|
||||
|
||||
if (!JSVAL_IS_STRING(val)) {
|
||||
JS_ReportError(aCx, "Argument %d must be a string", index);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSString* str = JS_ValueToString(aCx, val);
|
||||
if (!str) {
|
||||
JS_ReportError(aCx, "Couldn't convert argument %d to a string", index);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsString* newURL = urls.AppendElement();
|
||||
NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!");
|
||||
|
||||
newURL->Assign(nsDependentJSString(str));
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMWorkerScriptLoader> loader = new nsDOMWorkerScriptLoader();
|
||||
if (!loader) {
|
||||
JS_ReportOutOfMemory(aCx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsresult rv = loader->LoadScripts(worker, aCx, urls);
|
||||
if (NS_FAILED(rv)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
nsDOMWorkerFunctions::NewXMLHttpRequest(JSContext* aCx,
|
||||
JSObject* aObj,
|
||||
uintN aArgc,
|
||||
jsval* /* aArgv */,
|
||||
jsval* aRval)
|
||||
{
|
||||
nsDOMWorkerThread* worker =
|
||||
static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
|
||||
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
|
||||
|
||||
if (worker->IsCanceled()) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (aArgc) {
|
||||
JS_ReportError(aCx, "Constructor takes no arguments!");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMWorkerXHR> xhr = new nsDOMWorkerXHR(worker);
|
||||
if (!xhr) {
|
||||
JS_ReportOutOfMemory(aCx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsresult rv = xhr->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to construct XHR!");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> xhrSupports;
|
||||
xhr->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(xhrSupports));
|
||||
NS_ASSERTION(xhrSupports, "Impossible!");
|
||||
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> xhrWrapped;
|
||||
rv = xpc->WrapNative(aCx, aObj, xhrSupports, NS_GET_IID(nsIXMLHttpRequest),
|
||||
getter_AddRefs(xhrWrapped));
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to wrap XHR!");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSObject* xhrJSObj;
|
||||
rv = xhrWrapped->GetJSObject(&xhrJSObj);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to get JSObject!");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*aRval = OBJECT_TO_JSVAL(xhrJSObj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSFunctionSpec gDOMWorkerFunctions[] = {
|
||||
{ "dump", nsDOMWorkerFunctions::Dump, 1, 0, 0 },
|
||||
{ "debug", nsDOMWorkerFunctions::DebugDump, 1, 0, 0 },
|
||||
{ "postMessageToPool", nsDOMWorkerFunctions::PostMessage, 1, 0, 0 },
|
||||
{ "setTimeout", nsDOMWorkerFunctions::SetTimeout, 1, 0, 0 },
|
||||
{ "clearTimeout", nsDOMWorkerFunctions::KillTimeout, 1, 0, 0 },
|
||||
{ "setInterval", nsDOMWorkerFunctions::SetInterval, 1, 0, 0 },
|
||||
{ "clearInterval", nsDOMWorkerFunctions::KillTimeout, 1, 0, 0 },
|
||||
{ "loadScripts", nsDOMWorkerFunctions::LoadScripts, 1, 0, 0 },
|
||||
{ "XMLHttpRequest", nsDOMWorkerFunctions::NewXMLHttpRequest, 0, 0, 0 },
|
||||
#ifdef MOZ_SHARK
|
||||
{ "startShark", js_StartShark, 0, 0, 0 },
|
||||
{ "stopShark", js_StopShark, 0, 0, 0 },
|
||||
{ "connectShark", js_ConnectShark, 0, 0, 0 },
|
||||
{ "disconnectShark", js_DisconnectShark, 0, 0, 0 },
|
||||
#endif
|
||||
{ nsnull, nsnull, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* An nsISupports that holds a weak ref to the worker. The worker owns the
|
||||
* thread context so we don't have to worry about nulling this out ever.
|
||||
*/
|
||||
class nsDOMWorkerThreadWeakRef : public nsIDOMWorkerThread,
|
||||
public nsIClassInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_FORWARD_NSIDOMWORKERTHREAD(mWorker->)
|
||||
NS_FORWARD_NSICLASSINFO(mWorker->)
|
||||
|
||||
nsDOMWorkerThreadWeakRef(nsDOMWorkerThread* aWorker)
|
||||
: mWorker(aWorker) { }
|
||||
|
||||
protected:
|
||||
nsDOMWorkerThread* mWorker;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerThreadWeakRef, nsIDOMWorkerThread,
|
||||
nsIClassInfo)
|
||||
|
||||
/**
|
||||
* The 'threadContext' object for a worker's JS global object.
|
||||
*/
|
||||
class nsDOMWorkerThreadContext : public nsIDOMWorkerThreadContext,
|
||||
public nsIClassInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMWORKERTHREADCONTEXT
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
||||
nsDOMWorkerThreadContext(nsDOMWorkerThread* aWorker)
|
||||
: mWorker(aWorker) { }
|
||||
|
||||
protected:
|
||||
nsDOMWorkerThread* mWorker;
|
||||
nsCOMPtr<nsIDOMWorkerThread> mWeakRef;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerThreadContext,
|
||||
nsIDOMWorkerThreadContext,
|
||||
nsIClassInfo)
|
||||
|
||||
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerThreadContext,
|
||||
nsIDOMWorkerThreadContext)
|
||||
|
||||
NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerThreadContext)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWorkerThreadContext::GetThisThread(nsIDOMWorkerThread** aThisThread)
|
||||
{
|
||||
if (!mWeakRef) {
|
||||
mWeakRef = new nsDOMWorkerThreadWeakRef(mWorker);
|
||||
NS_ENSURE_TRUE(mWeakRef, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
NS_ADDREF(*aThisThread = mWeakRef);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDOMWorkerThread::nsDOMWorkerThread(nsDOMWorkerPool* aPool,
|
||||
const nsAString& aSource,
|
||||
PRBool aSourceIsURL)
|
||||
: mPool(aPool),
|
||||
mCompiled(PR_FALSE),
|
||||
mCallbackCount(0),
|
||||
mNextTimeoutId(0),
|
||||
mLock(nsnull)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (aSourceIsURL) {
|
||||
mSourceURL.Assign(aSource);
|
||||
NS_ASSERTION(!mSourceURL.IsEmpty(), "Empty source url!");
|
||||
}
|
||||
else {
|
||||
mSource.Assign(aSource);
|
||||
NS_ASSERTION(!mSource.IsEmpty(), "Empty source string!");
|
||||
}
|
||||
|
||||
PR_INIT_CLIST(&mTimeouts);
|
||||
}
|
||||
|
||||
nsDOMWorkerThread::~nsDOMWorkerThread()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!IsCanceled()) {
|
||||
nsRefPtr<nsDOMWorkerPool> pool = Pool();
|
||||
pool->NoteDyingWorker(this);
|
||||
}
|
||||
|
||||
ClearTimeouts();
|
||||
|
||||
if (mLock) {
|
||||
nsAutoLock::DestroyLock(mLock);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerThread, nsIDOMWorkerThread,
|
||||
nsIClassInfo)
|
||||
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerThread, nsIDOMWorkerThread)
|
||||
|
||||
NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerThread)
|
||||
|
||||
nsresult
|
||||
nsDOMWorkerThread::Init()
|
||||
{
|
||||
mLock = nsAutoLock::NewLock("nsDOMWorkerThread::mLock");
|
||||
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
NS_ASSERTION(!mGlobal, "Already got a global?!");
|
||||
|
||||
JSRuntime* rt;
|
||||
nsresult rv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool success = mGlobal.Hold(rt);
|
||||
NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
|
||||
|
||||
// This is pretty cool - all we have to do to get our script executed is to
|
||||
// pass a no-op runnable to the thread service and it will make sure we have
|
||||
// a context and global object.
|
||||
nsCOMPtr<nsIRunnable> runnable(new nsRunnable());
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = nsDOMThreadService::get()->Dispatch(this, runnable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// From nsDOMWorkerBase
|
||||
nsresult
|
||||
nsDOMWorkerThread::HandleMessage(const nsAString& aMessage,
|
||||
nsDOMWorkerBase* aSource)
|
||||
{
|
||||
nsCOMPtr<nsIDOMWorkerMessageListener> messageListener = GetMessageListener();
|
||||
if (!messageListener) {
|
||||
LOG(("Message received on a worker with no listener!"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We have to call this manually because XPConnect will replace our error
|
||||
// reporter with its own and we won't properly notify the pool of any
|
||||
// unhandled exceptions...
|
||||
|
||||
JSContext* cx;
|
||||
nsresult rv =
|
||||
nsDOMThreadService::ThreadJSContextStack()->GetSafeJSContext(&cx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
if (JS_IsExceptionPending(cx)) {
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
|
||||
// Get a JS string for the message.
|
||||
JSString* message = JS_NewUCStringCopyN(cx, (jschar*)aMessage.BeginReading(),
|
||||
aMessage.Length());
|
||||
NS_ENSURE_TRUE(message, NS_ERROR_FAILURE);
|
||||
|
||||
// Root it
|
||||
jsval messageVal = STRING_TO_JSVAL(message);
|
||||
nsAutoGCRoot rootedMessage(&messageVal, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
|
||||
nsCOMPtr<nsISupports> source;
|
||||
aSource->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(source));
|
||||
NS_ASSERTION(source, "Impossible!");
|
||||
|
||||
// Wrap the source thread.
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrappedThread;
|
||||
rv = xpc->WrapNative(cx, mGlobal, source, NS_GET_IID(nsISupports),
|
||||
getter_AddRefs(wrappedThread));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSObject* sourceThread;
|
||||
rv = wrappedThread->GetJSObject(&sourceThread);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set up our arguments.
|
||||
jsval argv[2] = {
|
||||
STRING_TO_JSVAL(message),
|
||||
OBJECT_TO_JSVAL(sourceThread)
|
||||
};
|
||||
|
||||
// Get the listener object out of our wrapped listener.
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrappedListener =
|
||||
do_QueryInterface(messageListener);
|
||||
NS_ENSURE_TRUE(wrappedListener, NS_ERROR_NO_INTERFACE);
|
||||
|
||||
JSObject* listener;
|
||||
rv = wrappedListener->GetJSObject(&listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// And call it.
|
||||
jsval rval;
|
||||
PRBool success = JS_CallFunctionValue(cx, mGlobal, OBJECT_TO_JSVAL(listener),
|
||||
2, argv, &rval);
|
||||
if (!success && JS_IsExceptionPending(cx)) {
|
||||
// Make sure any pending exceptions are converted to errors for the pool.
|
||||
JS_ReportPendingException(cx);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// From nsDOMWorkerBase
|
||||
nsresult
|
||||
nsDOMWorkerThread::DispatchMessage(nsIRunnable* aRunnable)
|
||||
{
|
||||
nsresult rv = nsDOMThreadService::get()->Dispatch(this, aRunnable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::Cancel()
|
||||
{
|
||||
nsDOMWorkerBase::Cancel();
|
||||
|
||||
// Do this before waiting on the thread service below!
|
||||
CancelScriptLoaders();
|
||||
CancelXHRs();
|
||||
|
||||
// If we're suspended there's a good chance that we're already paused waiting
|
||||
// on the pool's monitor. Waiting on the thread service's lock will deadlock.
|
||||
if (!IsSuspended()) {
|
||||
nsDOMThreadService::get()->WaitForCanceledWorker(this);
|
||||
}
|
||||
|
||||
ClearTimeouts();
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::Suspend()
|
||||
{
|
||||
nsDOMWorkerBase::Suspend();
|
||||
SuspendTimeouts();
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::Resume()
|
||||
{
|
||||
nsDOMWorkerBase::Resume();
|
||||
ResumeTimeouts();
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDOMWorkerThread::SetGlobalForContext(JSContext* aCx)
|
||||
{
|
||||
PRBool success = CompileGlobalObject(aCx);
|
||||
if (!success) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
JS_SetGlobalObject(aCx, mGlobal);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDOMWorkerThread::CompileGlobalObject(JSContext* aCx)
|
||||
{
|
||||
if (mGlobal) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (mCompiled) {
|
||||
// Don't try to recompile a bad script.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
mCompiled = PR_TRUE;
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
JSObject* global = JS_NewObject(aCx, nsnull, nsnull, nsnull);
|
||||
NS_ENSURE_TRUE(global, PR_FALSE);
|
||||
|
||||
NS_ASSERTION(!JS_GetGlobalObject(aCx), "Global object should be unset!");
|
||||
|
||||
// This call will root global.
|
||||
PRBool success = JS_InitStandardClasses(aCx, global);
|
||||
NS_ENSURE_TRUE(success, PR_FALSE);
|
||||
|
||||
// Set up worker thread functions
|
||||
success = JS_DefineFunctions(aCx, global, gDOMWorkerFunctions);
|
||||
NS_ENSURE_TRUE(success, PR_FALSE);
|
||||
|
||||
nsRefPtr<nsDOMWorkerThreadContext>
|
||||
context(new nsDOMWorkerThreadContext(this));
|
||||
NS_ENSURE_TRUE(context, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
nsresult rv = xpc->InitClasses(aCx, global);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
// XXX Fix this!
|
||||
success = JS_DeleteProperty(aCx, global, "Components");
|
||||
NS_ENSURE_TRUE(success, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> contextWrapper;
|
||||
rv = xpc->WrapNative(aCx, global,
|
||||
NS_ISUPPORTS_CAST(nsIDOMWorkerThreadContext*, context),
|
||||
NS_GET_IID(nsIDOMWorkerThreadContext),
|
||||
getter_AddRefs(contextWrapper));
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
JSObject* contextObj;
|
||||
rv = contextWrapper->GetJSObject(&contextObj);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
// Set up a name for our worker object
|
||||
success = JS_DefineProperty(aCx, global, "threadContext",
|
||||
OBJECT_TO_JSVAL(contextObj), nsnull, nsnull,
|
||||
JSPROP_ENUMERATE);
|
||||
NS_ENSURE_TRUE(success, PR_FALSE);
|
||||
|
||||
jsval val;
|
||||
|
||||
// From here on out we have to remember to null mGlobal if something fails!
|
||||
mGlobal = global;
|
||||
|
||||
if (mSource.IsEmpty()) {
|
||||
NS_ASSERTION(!mSourceURL.IsEmpty(), "Must have a url here!");
|
||||
|
||||
nsRefPtr<nsDOMWorkerScriptLoader> loader = new nsDOMWorkerScriptLoader();
|
||||
NS_ASSERTION(loader, "Out of memory!");
|
||||
if (!loader) {
|
||||
mGlobal = NULL;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv = loader->LoadScript(this, aCx, mSourceURL);
|
||||
JS_ReportPendingException(aCx);
|
||||
if (NS_FAILED(rv)) {
|
||||
mGlobal = NULL;
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(!mSource.IsEmpty(), "No source text!");
|
||||
|
||||
JSPrincipals* principal = nsDOMWorkerSecurityManager::WorkerPrincipal();
|
||||
|
||||
// Evaluate and execute the script
|
||||
success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
|
||||
reinterpret_cast<const jschar*>
|
||||
(mSource.get()),
|
||||
mSource.Length(),
|
||||
"DOMWorker inline script", 1,
|
||||
&val);
|
||||
if (!success) {
|
||||
mGlobal = NULL;
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// See if the message listener function was defined.
|
||||
nsCOMPtr<nsIDOMWorkerMessageListener> listener;
|
||||
if (JS_LookupProperty(aCx, global, "messageListener", &val) &&
|
||||
JSVAL_IS_OBJECT(val) &&
|
||||
NS_SUCCEEDED(xpc->WrapJS(aCx, JSVAL_TO_OBJECT(val),
|
||||
NS_GET_IID(nsIDOMWorkerMessageListener),
|
||||
getter_AddRefs(listener)))) {
|
||||
SetMessageListener(listener);
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsDOMWorkerTimeout*
|
||||
nsDOMWorkerThread::FirstTimeout()
|
||||
{
|
||||
// Only called within the lock!
|
||||
PRCList* first = PR_LIST_HEAD(&mTimeouts);
|
||||
return first == &mTimeouts ?
|
||||
nsnull :
|
||||
static_cast<nsDOMWorkerTimeout*>(first);
|
||||
}
|
||||
|
||||
nsDOMWorkerTimeout*
|
||||
nsDOMWorkerThread::NextTimeout(nsDOMWorkerTimeout* aTimeout)
|
||||
{
|
||||
// Only called within the lock!
|
||||
nsDOMWorkerTimeout* next =
|
||||
static_cast<nsDOMWorkerTimeout*>(PR_NEXT_LINK(aTimeout));
|
||||
return next == &mTimeouts ? nsnull : next;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDOMWorkerThread::AddTimeout(nsDOMWorkerTimeout* aTimeout)
|
||||
{
|
||||
// This should only ever be called on the worker thread... but there's no way
|
||||
// to really assert that since we're using a thread pool.
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aTimeout, "Null pointer!");
|
||||
|
||||
PRIntervalTime newInterval = aTimeout->GetInterval();
|
||||
|
||||
if (IsSuspended()) {
|
||||
aTimeout->Suspend(PR_Now());
|
||||
}
|
||||
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
if (IsCanceled()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// XXX Currently stored in the order that they should execute (like the window
|
||||
// timeouts are) but we don't flush all expired timeouts the same way that
|
||||
// the window does... Either we should or this is unnecessary.
|
||||
for (nsDOMWorkerTimeout* timeout = FirstTimeout();
|
||||
timeout;
|
||||
timeout = NextTimeout(timeout)) {
|
||||
if (timeout->GetInterval() > newInterval) {
|
||||
PR_INSERT_BEFORE(aTimeout, timeout);
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
PR_APPEND_LINK(aTimeout, &mTimeouts);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::RemoveTimeout(nsDOMWorkerTimeout* aTimeout)
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
PR_REMOVE_LINK(aTimeout);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::ClearTimeouts()
|
||||
{
|
||||
nsAutoTArray<nsRefPtr<nsDOMWorkerTimeout>, 20> timeouts;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
for (nsDOMWorkerTimeout* timeout = FirstTimeout();
|
||||
timeout;
|
||||
timeout = NextTimeout(timeout)) {
|
||||
timeouts.AppendElement(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 count = timeouts.Length();
|
||||
for (PRUint32 i = 0; i < count; i++) {
|
||||
timeouts[i]->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::CancelTimeout(PRUint32 aId)
|
||||
{
|
||||
nsRefPtr<nsDOMWorkerTimeout> foundTimeout;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
for (nsDOMWorkerTimeout* timeout = FirstTimeout();
|
||||
timeout;
|
||||
timeout = NextTimeout(timeout)) {
|
||||
if (timeout->GetId() == aId) {
|
||||
foundTimeout = timeout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundTimeout) {
|
||||
foundTimeout->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::SuspendTimeouts()
|
||||
{
|
||||
nsAutoTArray<nsRefPtr<nsDOMWorkerTimeout>, 20> timeouts;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
for (nsDOMWorkerTimeout* timeout = FirstTimeout();
|
||||
timeout;
|
||||
timeout = NextTimeout(timeout)) {
|
||||
timeouts.AppendElement(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
PRTime now = PR_Now();
|
||||
|
||||
PRUint32 count = timeouts.Length();
|
||||
for (PRUint32 i = 0; i < count; i++) {
|
||||
timeouts[i]->Suspend(now);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::ResumeTimeouts()
|
||||
{
|
||||
nsAutoTArray<nsRefPtr<nsDOMWorkerTimeout>, 20> timeouts;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
for (nsDOMWorkerTimeout* timeout = FirstTimeout();
|
||||
timeout;
|
||||
timeout = NextTimeout(timeout)) {
|
||||
NS_ASSERTION(timeout->IsSuspended(), "Should be suspended!");
|
||||
timeouts.AppendElement(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
PRTime now = PR_Now();
|
||||
|
||||
PRUint32 count = timeouts.Length();
|
||||
for (PRUint32 i = 0; i < count; i++) {
|
||||
timeouts[i]->Resume(now);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::CancelScriptLoaders()
|
||||
{
|
||||
nsAutoTArray<nsDOMWorkerScriptLoader*, 20> loaders;
|
||||
|
||||
// Must call cancel on the loaders outside the lock!
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
loaders.AppendElements(mScriptLoaders);
|
||||
|
||||
// Don't clear mScriptLoaders, they'll remove themselves as they get
|
||||
// destroyed.
|
||||
}
|
||||
|
||||
PRUint32 loaderCount = loaders.Length();
|
||||
for (PRUint32 index = 0; index < loaderCount; index++) {
|
||||
loaders[index]->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDOMWorkerThread::AddXHR(nsDOMWorkerXHR* aXHR)
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
if (IsCanceled()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool contains = mXHRs.Contains(aXHR);
|
||||
NS_ASSERTION(!contains, "Adding an XHR twice!");
|
||||
#endif
|
||||
|
||||
nsDOMWorkerXHR** newElement = mXHRs.AppendElement(aXHR);
|
||||
NS_ENSURE_TRUE(newElement, PR_FALSE);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::RemoveXHR(nsDOMWorkerXHR* aXHR)
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
#ifdef DEBUG
|
||||
PRBool removed =
|
||||
#endif
|
||||
mXHRs.RemoveElement(aXHR);
|
||||
NS_WARN_IF_FALSE(removed, "Removed an XHR that was never added?!");
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMWorkerThread::CancelXHRs()
|
||||
{
|
||||
nsAutoTArray<nsDOMWorkerXHR*, 20> xhrs;
|
||||
|
||||
// Must call Cancel outside the lock!
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
xhrs.AppendElements(mXHRs);
|
||||
}
|
||||
|
||||
PRUint32 xhrCount = xhrs.Length();
|
||||
for (PRUint32 index = 0; index < xhrCount; index++) {
|
||||
xhrs[index]->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWorkerThread::PostMessage(const nsAString& aMessage)
|
||||
{
|
||||
nsresult rv = PostMessageInternal(aMessage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* ***** 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 worker threads.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
|
||||
* Ben Turner <bent.mozilla@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef __NSDOMWORKERTHREAD_H__
|
||||
#define __NSDOMWORKERTHREAD_H__
|
||||
|
||||
// Bases
|
||||
#include "nsDOMWorkerBase.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIDOMThreads.h"
|
||||
|
||||
// Other includes
|
||||
#include "jsapi.h"
|
||||
#include "nsAutoJSObjectHolder.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prclist.h"
|
||||
#include "prlock.h"
|
||||
|
||||
// DOMWorker includes
|
||||
#include "nsDOMThreadService.h"
|
||||
|
||||
// Macro to generate nsIClassInfo methods for these threadsafe DOM classes
|
||||
#define NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \
|
||||
NS_IMETHODIMP \
|
||||
_class::GetInterfaces(PRUint32* _count, nsIID*** _array) \
|
||||
{ \
|
||||
return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \
|
||||
} \
|
||||
|
||||
#define NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class) \
|
||||
NS_IMETHODIMP \
|
||||
_class::GetHelperForLanguage(PRUint32 _language, nsISupports** _retval) \
|
||||
{ \
|
||||
*_retval = nsnull; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
_class::GetContractID(char** _contractID) \
|
||||
{ \
|
||||
*_contractID = nsnull; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
_class::GetClassDescription(char** _classDescription) \
|
||||
{ \
|
||||
*_classDescription = nsnull; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
_class::GetClassID(nsCID** _classID) \
|
||||
{ \
|
||||
*_classID = nsnull; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
_class::GetImplementationLanguage(PRUint32* _language) \
|
||||
{ \
|
||||
*_language = nsIProgrammingLanguage::CPLUSPLUS; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
_class::GetFlags(PRUint32* _flags) \
|
||||
{ \
|
||||
*_flags = nsIClassInfo::THREADSAFE | nsIClassInfo::DOM_OBJECT; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
_class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
|
||||
{ \
|
||||
return NS_ERROR_NOT_AVAILABLE; \
|
||||
}
|
||||
|
||||
#define NS_IMPL_THREADSAFE_DOM_CI(_class) \
|
||||
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \
|
||||
NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class)
|
||||
|
||||
class nsDOMWorkerPool;
|
||||
class nsDOMWorkerScriptLoader;
|
||||
class nsDOMWorkerTimeout;
|
||||
class nsDOMWorkerXHR;
|
||||
|
||||
class nsDOMWorkerThread : public nsDOMWorkerBase,
|
||||
public nsIDOMWorkerThread,
|
||||
public nsIClassInfo
|
||||
{
|
||||
friend class nsDOMCreateJSContextRunnable;
|
||||
friend class nsDOMWorkerFunctions;
|
||||
friend class nsDOMWorkerPool;
|
||||
friend class nsDOMWorkerRunnable;
|
||||
friend class nsDOMWorkerScriptLoader;
|
||||
friend class nsDOMWorkerTimeout;
|
||||
friend class nsDOMWorkerXHR;
|
||||
|
||||
friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMWORKERTHREAD
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
||||
nsDOMWorkerThread(nsDOMWorkerPool* aPool,
|
||||
const nsAString& aSource,
|
||||
PRBool aSourceIsURL);
|
||||
|
||||
virtual nsDOMWorkerPool* Pool() {
|
||||
NS_ASSERTION(!IsCanceled(), "Don't touch Pool after we've been canceled!");
|
||||
return mPool;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~nsDOMWorkerThread();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
// For nsDOMWorkerBase
|
||||
virtual nsresult HandleMessage(const nsAString& aMessage,
|
||||
nsDOMWorkerBase* aSourceThread);
|
||||
|
||||
// For nsDOMWorkerBase
|
||||
virtual nsresult DispatchMessage(nsIRunnable* aRunnable);
|
||||
|
||||
virtual void Cancel();
|
||||
virtual void Suspend();
|
||||
virtual void Resume();
|
||||
|
||||
PRBool SetGlobalForContext(JSContext* aCx);
|
||||
PRBool CompileGlobalObject(JSContext* aCx);
|
||||
|
||||
inline nsDOMWorkerTimeout* FirstTimeout();
|
||||
inline nsDOMWorkerTimeout* NextTimeout(nsDOMWorkerTimeout* aTimeout);
|
||||
|
||||
PRBool AddTimeout(nsDOMWorkerTimeout* aTimeout);
|
||||
void RemoveTimeout(nsDOMWorkerTimeout* aTimeout);
|
||||
void ClearTimeouts();
|
||||
void CancelTimeout(PRUint32 aId);
|
||||
void SuspendTimeouts();
|
||||
void ResumeTimeouts();
|
||||
|
||||
void CancelScriptLoaders();
|
||||
|
||||
PRBool AddXHR(nsDOMWorkerXHR* aXHR);
|
||||
void RemoveXHR(nsDOMWorkerXHR* aXHR);
|
||||
void CancelXHRs();
|
||||
|
||||
PRLock* Lock() {
|
||||
return mLock;
|
||||
}
|
||||
|
||||
nsDOMWorkerPool* mPool;
|
||||
nsString mSource;
|
||||
nsString mSourceURL;
|
||||
|
||||
nsAutoJSObjectHolder mGlobal;
|
||||
PRBool mCompiled;
|
||||
|
||||
PRUint32 mCallbackCount;
|
||||
|
||||
PRUint32 mNextTimeoutId;
|
||||
|
||||
PRLock* mLock;
|
||||
PRCList mTimeouts;
|
||||
|
||||
nsTArray<nsDOMWorkerScriptLoader*> mScriptLoaders;
|
||||
nsTArray<nsDOMWorkerXHR*> mXHRs;
|
||||
};
|
||||
|
||||
#endif /* __NSDOMWORKERTHREAD_H__ */
|
Загрузка…
Ссылка в новой задаче