author | Eddy Bruël <ejpbruel@gmail.com> |
Mon, 27 Oct 2014 18:00:05 +0100 | |
changeset 212485 | d5fcb5f05f03386b67ee2745acd3d30ea477fa64 |
parent 212484 | 2add539cd09aeb853d4b2197fd67d6a3575c60d7 |
child 212486 | 06ec442314d4c251b64b9760170780a7eeed9d78 |
push id | 27716 |
push user | kwierso@gmail.com |
push date | Tue, 28 Oct 2014 00:27:17 +0000 |
treeherder | mozilla-central@2042c38f13ae [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | khuey |
bugs | 757133 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -230,16 +230,17 @@ @BINPATH@/components/dom_storage.xpt @BINPATH@/components/dom_stylesheets.xpt @BINPATH@/components/dom_telephony.xpt @BINPATH@/components/dom_traversal.xpt @BINPATH@/components/dom_voicemail.xpt #ifdef MOZ_WEBSPEECH @BINPATH@/components/dom_webspeechrecognition.xpt #endif +@BINPATH@/components/dom_workers.xpt @BINPATH@/components/dom_xbl.xpt @BINPATH@/components/dom_xpath.xpt @BINPATH@/components/dom_xul.xpt #ifdef MOZ_GAMEPAD @BINPATH@/components/dom_gamepad.xpt #endif @BINPATH@/components/dom_payment.xpt @BINPATH@/components/downloads.xpt
new file mode 100644 --- /dev/null +++ b/dom/workers/WorkerDebuggerManager.cpp @@ -0,0 +1,236 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* 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/. */ + +#include "WorkerDebuggerManager.h" + +#include "nsISimpleEnumerator.h" + +#include "WorkerPrivate.h" + +USING_WORKERS_NAMESPACE + +class RegisterDebuggerRunnable MOZ_FINAL : public nsRunnable +{ + nsRefPtr<WorkerDebuggerManager> mManager; + nsRefPtr<WorkerDebugger> mDebugger; + bool mHasListeners; + +public: + RegisterDebuggerRunnable(WorkerDebuggerManager* aManager, + WorkerDebugger* aDebugger, + bool aHasListeners) + : mManager(aManager), mDebugger(aDebugger), mHasListeners(aHasListeners) + { } + + NS_DECL_THREADSAFE_ISUPPORTS + +private: + ~RegisterDebuggerRunnable() + { } + + NS_IMETHOD + Run() MOZ_OVERRIDE + { + mManager->RegisterDebuggerOnMainThread(mDebugger, mHasListeners); + + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(RegisterDebuggerRunnable, nsIRunnable); + +BEGIN_WORKERS_NAMESPACE + +class WorkerDebuggerEnumerator MOZ_FINAL : public nsISimpleEnumerator +{ + nsTArray<nsCOMPtr<nsISupports>> mDebuggers; + uint32_t mIndex; + +public: + WorkerDebuggerEnumerator(const nsTArray<WorkerDebugger*>& aDebuggers) + : mIndex(0) + { + mDebuggers.AppendElements(aDebuggers); + } + + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + +private: + ~WorkerDebuggerEnumerator() {} +}; + +NS_IMPL_ISUPPORTS(WorkerDebuggerEnumerator, nsISimpleEnumerator); + +NS_IMETHODIMP +WorkerDebuggerEnumerator::HasMoreElements(bool* aResult) +{ + *aResult = mIndex < mDebuggers.Length(); + return NS_OK; +}; + +NS_IMETHODIMP +WorkerDebuggerEnumerator::GetNext(nsISupports** aResult) +{ + if (mIndex == mDebuggers.Length()) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsISupports> element = mDebuggers.ElementAt(mIndex++); + element.forget(aResult); + return NS_OK; +}; + +WorkerDebuggerManager::WorkerDebuggerManager() +: mMutex("WorkerDebuggerManager::mMutex") +{ + AssertIsOnMainThread(); +} + +WorkerDebuggerManager::~WorkerDebuggerManager() +{ + AssertIsOnMainThread(); +} + +NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIWorkerDebuggerManager); + +NS_IMETHODIMP +WorkerDebuggerManager::GetWorkerDebuggerEnumerator( + nsISimpleEnumerator** aResult) +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mMutex); + + nsRefPtr<WorkerDebuggerEnumerator> enumerator = + new WorkerDebuggerEnumerator(mDebuggers); + enumerator.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +WorkerDebuggerManager::AddListener(nsIWorkerDebuggerManagerListener* aListener) +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mMutex); + + if (mListeners.Contains(aListener)) { + return NS_ERROR_INVALID_ARG; + } + + mListeners.AppendElement(aListener); + return NS_OK; +} + +NS_IMETHODIMP +WorkerDebuggerManager::RemoveListener( + nsIWorkerDebuggerManagerListener* aListener) +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mMutex); + + if (!mListeners.Contains(aListener)) { + return NS_OK; + } + + mListeners.RemoveElement(aListener); + return NS_OK; +} + +void +WorkerDebuggerManager::RegisterDebugger(WorkerDebugger* aDebugger) +{ + // May be called on any thread! + + bool hasListeners = false; + + { + MutexAutoLock lock(mMutex); + + hasListeners = !mListeners.IsEmpty(); + } + + if (NS_IsMainThread()) { + RegisterDebuggerOnMainThread(aDebugger, hasListeners); + } else { + nsCOMPtr<nsIRunnable> runnable = + new RegisterDebuggerRunnable(this, aDebugger, hasListeners); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( + NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); + + if (hasListeners) { + aDebugger->WaitIsEnabled(true); + } + } +} + +void +WorkerDebuggerManager::UnregisterDebugger(WorkerDebugger* aDebugger) +{ + // May be called on any thread! + + if (NS_IsMainThread()) { + UnregisterDebuggerOnMainThread(aDebugger); + } else { + nsCOMPtr<nsIRunnable> runnable = + NS_NewRunnableMethodWithArg<nsRefPtr<WorkerDebugger>>(this, + &WorkerDebuggerManager::UnregisterDebuggerOnMainThread, aDebugger); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( + NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); + + aDebugger->WaitIsEnabled(false); + } +} + +void +WorkerDebuggerManager::RegisterDebuggerOnMainThread(WorkerDebugger* aDebugger, + bool aHasListeners) +{ + AssertIsOnMainThread(); + + MOZ_ASSERT(!mDebuggers.Contains(aDebugger)); + mDebuggers.AppendElement(aDebugger); + + nsTArray<nsCOMPtr<nsIWorkerDebuggerManagerListener>> listeners; + { + MutexAutoLock lock(mMutex); + + listeners.AppendElements(mListeners); + } + + if (aHasListeners) { + for (size_t index = 0; index < listeners.Length(); ++index) { + listeners[index]->OnRegister(aDebugger); + } + } + + aDebugger->Enable(); +} + +void +WorkerDebuggerManager::UnregisterDebuggerOnMainThread(WorkerDebugger* aDebugger) +{ + AssertIsOnMainThread(); + + MOZ_ASSERT(mDebuggers.Contains(aDebugger)); + mDebuggers.RemoveElement(aDebugger); + + nsTArray<nsCOMPtr<nsIWorkerDebuggerManagerListener>> listeners; + { + MutexAutoLock lock(mMutex); + + listeners.AppendElements(mListeners); + } + + for (size_t index = 0; index < listeners.Length(); ++index) { + listeners[index]->OnUnregister(aDebugger); + } + + aDebugger->Disable(); +} + +END_WORKERS_NAMESPACE
new file mode 100644 --- /dev/null +++ b/dom/workers/WorkerDebuggerManager.h @@ -0,0 +1,95 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* 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/. */ + +#ifndef mozilla_dom_workers_workerdebuggermanager_h +#define mozilla_dom_workers_workerdebuggermanager_h + +#include "Workers.h" + +#include "nsIWorkerDebuggerManager.h" + +#include "nsServiceManagerUtils.h" +#include "nsTArray.h" + +#define WORKERDEBUGGERMANAGER_CID \ + { 0x62ec8731, 0x55ad, 0x4246, \ + { 0xb2, 0xea, 0xf2, 0x6c, 0x1f, 0xe1, 0x9d, 0x2d } } +#define WORKERDEBUGGERMANAGER_CONTRACTID \ + "@mozilla.org/dom/workers/workerdebuggermanager;1" + +class RegisterDebuggerRunnable; + +BEGIN_WORKERS_NAMESPACE + +class WorkerDebugger; + +class WorkerDebuggerManager MOZ_FINAL : public nsIWorkerDebuggerManager +{ + friend class ::RegisterDebuggerRunnable; + + mozilla::Mutex mMutex; + + // Protected by mMutex. + nsTArray<nsCOMPtr<nsIWorkerDebuggerManagerListener>> mListeners; + + // Only touched on the main thread. + nsTArray<WorkerDebugger*> mDebuggers; + +public: + static WorkerDebuggerManager* + GetOrCreateService() + { + nsCOMPtr<nsIWorkerDebuggerManager> wdm = + do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID); + return static_cast<WorkerDebuggerManager*>(wdm.get()); + } + + WorkerDebuggerManager(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWORKERDEBUGGERMANAGER + + void RegisterDebugger(WorkerDebugger* aDebugger); + + void UnregisterDebugger(WorkerDebugger* aDebugger); + +private: + virtual ~WorkerDebuggerManager(); + + void RegisterDebuggerOnMainThread(WorkerDebugger* aDebugger, + bool aHasListeners); + + void UnregisterDebuggerOnMainThread(WorkerDebugger* aDebugger); +}; + +inline nsresult +RegisterWorkerDebugger(WorkerDebugger* aDebugger) +{ + nsRefPtr<WorkerDebuggerManager> manager = + WorkerDebuggerManager::GetOrCreateService(); + if (!manager) { + return NS_ERROR_FAILURE; + } + + manager->RegisterDebugger(aDebugger); + return NS_OK; +} + +inline nsresult +UnregisterWorkerDebugger(WorkerDebugger* aDebugger) +{ + nsRefPtr<WorkerDebuggerManager> manager = + WorkerDebuggerManager::GetOrCreateService(); + if (!manager) { + return NS_ERROR_FAILURE; + } + + manager->UnregisterDebugger(aDebugger); + return NS_OK; +} + +END_WORKERS_NAMESPACE + +#endif // mozilla_dom_workers_workerdebuggermanager_h
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -22,16 +22,17 @@ #include "nsIScriptSecurityManager.h" #include "nsPerformance.h" #include "nsPIDOMWindow.h" #include "nsITextToSubURI.h" #include "nsIThreadInternal.h" #include "nsITimer.h" #include "nsIURI.h" #include "nsIURL.h" +#include "nsIWorkerDebugger.h" #include "nsIXPConnect.h" #include <algorithm> #include "jsfriendapi.h" #include "js/MemoryMetrics.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/ContentEvents.h" @@ -75,16 +76,17 @@ #include "MessagePort.h" #include "Navigator.h" #include "Principal.h" #include "RuntimeService.h" #include "ScriptLoader.h" #include "ServiceWorkerManager.h" #include "SharedWorker.h" +#include "WorkerDebuggerManager.h" #include "WorkerFeature.h" #include "WorkerRunnable.h" #include "WorkerScope.h" // JS_MaybeGC will run once every second during normal execution. #define PERIODIC_GC_TIMER_DELAY_SEC 1 // A shrinking GC will run five seconds after the last event is processed. @@ -651,16 +653,18 @@ private: new MainThreadReleaseRunnable(doomed, hostObjectURIs); if (NS_FAILED(NS_DispatchToMainThread(runnable))) { NS_WARNING("Failed to dispatch, going to leak!"); } RuntimeService* runtime = RuntimeService::GetService(); NS_ASSERTION(runtime, "This should never be null!"); + mFinishedWorker->DisableDebugger(); + runtime->UnregisterWorker(aCx, mFinishedWorker); mFinishedWorker->ClearSelfRef(); return true; } }; class TopLevelWorkerFinishedRunnable MOZ_FINAL : public nsRunnable @@ -685,16 +689,18 @@ private: AssertIsOnMainThread(); RuntimeService* runtime = RuntimeService::GetService(); MOZ_ASSERT(runtime); AutoSafeJSContext cx; JSAutoRequest ar(cx); + mFinishedWorker->DisableDebugger(); + runtime->UnregisterWorker(cx, mFinishedWorker); nsTArray<nsCOMPtr<nsISupports> > doomed; mFinishedWorker->ForgetMainThreadObjects(doomed); nsTArray<nsCString> hostObjectURIs; mFinishedWorker->StealHostObjectURIs(hostObjectURIs); @@ -2138,16 +2144,52 @@ WorkerPrivateParent<Derived>::DispatchPr mCondVar.Notify(); } return NS_OK; } template <class Derived> +void +WorkerPrivateParent<Derived>::EnableDebugger() +{ + AssertIsOnParentThread(); + + WorkerPrivate* self = ParentAsWorkerPrivate(); + + MOZ_ASSERT(!self->mDebugger); + self->mDebugger = new WorkerDebugger(self); + + if (NS_FAILED(RegisterWorkerDebugger(self->mDebugger))) { + NS_WARNING("Failed to register worker debugger!"); + self->mDebugger = nullptr; + } +} + +template <class Derived> +void +WorkerPrivateParent<Derived>::DisableDebugger() +{ + AssertIsOnParentThread(); + + WorkerPrivate* self = ParentAsWorkerPrivate(); + + if (!self->mDebugger) { + return; + } + + if (NS_FAILED(UnregisterWorkerDebugger(self->mDebugger))) { + NS_WARNING("Failed to unregister worker debugger!"); + } + + self->mDebugger = nullptr; +} + +template <class Derived> nsresult WorkerPrivateParent<Derived>::DispatchControlRunnable( WorkerControlRunnable* aWorkerControlRunnable) { // May be called on any thread! MOZ_ASSERT(aWorkerControlRunnable); @@ -3443,16 +3485,104 @@ WorkerPrivateParent<Derived>::AssertInne AssertIsOnMainThread(); nsPIDOMWindow* outer = mLoadInfo.mWindow->GetOuterWindow(); NS_ASSERTION(outer && outer->GetCurrentInnerWindow() == mLoadInfo.mWindow, "Inner window no longer correct!"); } #endif + +WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate) +: mMutex("WorkerDebugger::mMutex"), + mCondVar(mMutex, "WorkerDebugger::mCondVar"), + mWorkerPrivate(aWorkerPrivate), + mIsEnabled(false) +{ + mWorkerPrivate->AssertIsOnParentThread(); +} + +WorkerDebugger::~WorkerDebugger() +{ + MOZ_ASSERT(!mWorkerPrivate); +} + +NS_IMPL_ISUPPORTS(WorkerDebugger, nsIWorkerDebugger) + +NS_IMETHODIMP +WorkerDebugger::GetIsClosed(bool* aResult) +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mMutex); + + *aResult = !mWorkerPrivate; + return NS_OK; +} + +NS_IMETHODIMP +WorkerDebugger::GetUrl(nsAString& aResult) +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + return NS_ERROR_UNEXPECTED; + } + + aResult = mWorkerPrivate->ScriptURL(); + return NS_OK; +} + +void +WorkerDebugger::WaitIsEnabled(bool aIsEnabled) +{ + MutexAutoLock lock(mMutex); + + while (mIsEnabled != aIsEnabled) { + mCondVar.Wait(); + } +} + +void +WorkerDebugger::NotifyIsEnabled(bool aIsEnabled) +{ + mMutex.AssertCurrentThreadOwns(); + + MOZ_ASSERT(mIsEnabled != aIsEnabled); + mIsEnabled = aIsEnabled; + mCondVar.Notify(); +} + +void +WorkerDebugger::Enable() +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mWorkerPrivate); + + NotifyIsEnabled(true); +} + +void +WorkerDebugger::Disable() +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate = nullptr; + + NotifyIsEnabled(false); +} + WorkerPrivate::WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, WorkerType aWorkerType, const nsACString& aSharedWorkerName, LoadInfo& aLoadInfo) : WorkerPrivateParent<WorkerPrivate>(aCx, aParent, aScriptURL, aIsChromeWorker, aWorkerType, @@ -3616,16 +3746,18 @@ WorkerPrivate::Constructor(JSContext* aC new WorkerPrivate(aCx, parent, aScriptURL, aIsChromeWorker, aWorkerType, aSharedWorkerName, *aLoadInfo); if (!runtimeService->RegisterWorker(aCx, worker)) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } + worker->EnableDebugger(); + nsRefPtr<CompileScriptRunnable> compiler = new CompileScriptRunnable(worker); if (!compiler->Dispatch(aCx)) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } worker->mSelfRef = worker;
--- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -4,16 +4,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_workers_workerprivate_h__ #define mozilla_dom_workers_workerprivate_h__ #include "Workers.h" #include "nsIContentSecurityPolicy.h" +#include "nsIWorkerDebugger.h" #include "nsPIDOMWindow.h" #include "mozilla/CondVar.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/BindingDeclarations.h" #include "nsCycleCollectionParticipant.h" #include "nsDataHashtable.h" @@ -56,16 +57,17 @@ BEGIN_WORKERS_NAMESPACE class AutoSyncLoopHolder; class MessagePort; class SharedWorker; class WorkerControlRunnable; class WorkerGlobalScope; class WorkerPrivate; class WorkerRunnable; +class WorkerDebugger; enum WorkerType { WorkerTypeDedicated, WorkerTypeShared, WorkerTypeService }; @@ -290,16 +292,22 @@ public: virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent, DOMEventTargetHelper) void + EnableDebugger(); + + void + DisableDebugger(); + + void ClearSelfRef() { AssertIsOnParentThread(); MOZ_ASSERT(mSelfRef); mSelfRef = nullptr; } nsresult @@ -716,16 +724,44 @@ public: { } void AssertInnerWindowIsCorrect() const { } #endif }; +class WorkerDebugger : public nsIWorkerDebugger { + mozilla::Mutex mMutex; + mozilla::CondVar mCondVar; + + // Protected by mMutex + WorkerPrivate* mWorkerPrivate; + bool mIsEnabled; + +public: + WorkerDebugger(WorkerPrivate* aWorkerPrivate); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIWORKERDEBUGGER + + void AssertIsOnParentThread(); + + void WaitIsEnabled(bool aIsEnabled); + + void Enable(); + + void Disable(); + +private: + virtual ~WorkerDebugger(); + + void NotifyIsEnabled(bool aIsEnabled); +}; + class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate> { friend class WorkerPrivateParent<WorkerPrivate>; typedef WorkerPrivateParent<WorkerPrivate> ParentType; friend class AutoSyncLoopHolder; struct TimeoutInfo; @@ -734,16 +770,18 @@ class WorkerPrivate : public WorkerPriva enum GCTimerMode { PeriodicTimer = 0, IdleTimer, NoTimer }; + nsRefPtr<WorkerDebugger> mDebugger; + Queue<WorkerControlRunnable*, 4> mControlQueue; // Touched on multiple threads, protected with mMutex. JSContext* mJSContext; nsRefPtr<WorkerCrossThreadDispatcher> mCrossThreadDispatcher; nsTArray<nsCOMPtr<nsIRunnable>> mUndispatchedRunnablesForSyncLoop; nsCOMPtr<nsIThread> mThread;
--- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -11,16 +11,17 @@ EXPORTS.mozilla.dom += [ 'ServiceWorkerRegistration.h', 'WorkerPrivate.h', 'WorkerRunnable.h', 'WorkerScope.h', ] EXPORTS.mozilla.dom.workers += [ 'ServiceWorkerManager.h', + 'WorkerDebuggerManager.h', 'Workers.h', ] # Stuff needed for the bindings, not really public though. EXPORTS.mozilla.dom.workers.bindings += [ 'DataStore.h', 'DataStoreCursor.h', 'FileReaderSync.h', @@ -31,16 +32,23 @@ EXPORTS.mozilla.dom.workers.bindings += 'ServiceWorker.h', 'SharedWorker.h', 'URL.h', 'WorkerFeature.h', 'XMLHttpRequest.h', 'XMLHttpRequestUpload.h', ] +XPIDL_MODULE = 'dom_workers' + +XPIDL_SOURCES += [ + 'nsIWorkerDebugger.idl', + 'nsIWorkerDebuggerManager.idl', +] + UNIFIED_SOURCES += [ 'ChromeWorkerScope.cpp', 'DataStore.cpp', 'DataStoreCursor.cpp', 'FileReaderSync.cpp', 'Location.cpp', 'MessagePort.cpp', 'Navigator.cpp', @@ -51,16 +59,17 @@ UNIFIED_SOURCES += [ 'ScriptLoader.cpp', 'ServiceWorker.cpp', 'ServiceWorkerContainer.cpp', 'ServiceWorkerEvents.cpp', 'ServiceWorkerManager.cpp', 'ServiceWorkerRegistration.cpp', 'SharedWorker.cpp', 'URL.cpp', + 'WorkerDebuggerManager.cpp', 'WorkerPrivate.cpp', 'WorkerRunnable.cpp', 'WorkerScope.cpp', 'XMLHttpRequest.cpp', 'XMLHttpRequestUpload.cpp', ] FAIL_ON_WARNINGS = True
new file mode 100644 --- /dev/null +++ b/dom/workers/nsIWorkerDebugger.idl @@ -0,0 +1,9 @@ +#include "nsISupports.idl" + +[scriptable, builtinclass, uuid(0833b363-bffe-4cdb-ad50-1c4563e0C8ff)] +interface nsIWorkerDebugger : nsISupports +{ + readonly attribute bool isClosed; + + readonly attribute DOMString url; +};
new file mode 100644 --- /dev/null +++ b/dom/workers/nsIWorkerDebuggerManager.idl @@ -0,0 +1,22 @@ +#include "nsISupports.idl" + +interface nsISimpleEnumerator; +interface nsIWorkerDebugger; + +[scriptable, uuid(d2aa74ee-6b98-4d5d-8173-4e23422daf1e)] +interface nsIWorkerDebuggerManagerListener : nsISupports +{ + void onRegister(in nsIWorkerDebugger debugger); + + void onUnregister(in nsIWorkerDebugger debugger); +}; + +[scriptable, builtinclass, uuid(056d7918-dc86-452a-b4e6-86da3405f015)] +interface nsIWorkerDebuggerManager : nsISupports +{ + nsISimpleEnumerator getWorkerDebuggerEnumerator(); + + void addListener(in nsIWorkerDebuggerManagerListener listener); + + void removeListener(in nsIWorkerDebuggerManagerListener listener); +};
new file mode 100644 --- /dev/null +++ b/dom/workers/test/WorkerDebuggerManager_childWorker.js @@ -0,0 +1,3 @@ +"use strict"; + +onmessage = function () {};
new file mode 100644 --- /dev/null +++ b/dom/workers/test/WorkerDebuggerManager_parentWorker.js @@ -0,0 +1,3 @@ +"use strict"; + +var worker = new Worker("WorkerDebuggerManager_childWorker.js");
--- a/dom/workers/test/chrome.ini +++ b/dom/workers/test/chrome.ini @@ -1,30 +1,35 @@ [DEFAULT] support-files = + WorkerDebuggerManager_childWorker.js + WorkerDebuggerManager_parentWorker.js WorkerTest.jsm WorkerTest_subworker.js WorkerTest_worker.js chromeWorker_subworker.js chromeWorker_worker.js dom_worker_helper.js + file_url.jsm + file_worker.js fileBlobSubWorker_worker.js fileBlob_worker.js filePosting_worker.js fileReadSlice_worker.js fileReaderSyncErrors_worker.js fileReaderSync_worker.js fileSlice_worker.js fileSubWorker_worker.js file_worker.js jsm_url_worker.js workersDisabled_worker.js file_url.jsm bug1062920_worker.js +[test_WorkerDebuggerManager.xul] [test_bug883784.jsm] [test_bug883784.xul] [test_chromeWorker.xul] [test_chromeWorkerJSM.xul] [test_extension.xul] [test_extensionBootstrap.xul] [test_file.xul] [test_fileBlobPosting.xul]
--- a/dom/workers/test/dom_worker_helper.js +++ b/dom/workers/test/dom_worker_helper.js @@ -1,21 +1,102 @@ /** * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"]. + getService(Ci.nsIWorkerDebuggerManager); + var gRemainingTests = 0; function waitForWorkerFinish() { if (gRemainingTests == 0) { SimpleTest.waitForExplicitFinish(); } ++gRemainingTests; } function finish() { --gRemainingTests; if (gRemainingTests == 0) { SimpleTest.finish(); } } +function assertThrows(fun, message) { + let throws = false; + try { + fun(); + } catch (e) { + throws = true; + } + ok(throws, message); +} + +function* generateDebuggers() { + let e = wdm.getWorkerDebuggerEnumerator(); + while (e.hasMoreElements()) { + let dbg = e.getNext().QueryInterface(Ci.nsIWorkerDebugger); + yield dbg; + } +} + +function findDebugger(predicate) { + for (let dbg of generateDebuggers()) { + if (predicate(dbg)) { + return dbg; + } + } + return null; +} + +function waitForRegister(predicate = () => true) { + return new Promise(function (resolve) { + wdm.addListener({ + onRegister: function (dbg) { + if (!predicate(dbg)) { + return; + } + wdm.removeListener(this); + resolve(dbg); + } + }); + }); +} + +function waitForUnregister(predicate = () => true) { + return new Promise(function (resolve) { + wdm.addListener({ + onUnregister: function (dbg) { + if (!predicate(dbg)) { + return; + } + wdm.removeListener(this); + resolve(dbg); + } + }); + }); +} + +function waitForMultiple(promises) { + return new Promise(function (resolve) { + let results = []; + for (let i = 0; i < promises.length; ++i) { + let promise = promises[i]; + let index = i; + promise.then(function (result) { + is(results.length, index, "events should occur in the specified order"); + results.push(result); + if (results.length === promises.length) { + resolve(results); + } + }); + } + }); +};
new file mode 100644 --- /dev/null +++ b/dom/workers/test/test_WorkerDebuggerManager.xul @@ -0,0 +1,92 @@ +<?xml version="1.0"?> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<window title="Test for WorkerDebuggerManager" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="test();"> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> + <script type="application/javascript" src="dom_worker_helper.js"/> + + <script type="application/javascript"> + <![CDATA[ + + const PARENT_WORKER_URL = "WorkerDebuggerManager_parentWorker.js"; + const CHILD_WORKER_URL = "WorkerDebuggerManager_childWorker.js"; + + function test() { + Task.spawn(function* () { + SimpleTest.waitForExplicitFinish(); + + ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL), + "debugger for parent worker should not be enumerated before it is " + + "registered"); + ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL), + "debugger for child worker should not be enumerated before it is " + + "registered"); + + let promise = waitForMultiple([ + waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL), + waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL), + ]); + let worker = new Worker(PARENT_WORKER_URL); + let dbgs = yield promise; + is(dbgs[0].isClosed, false, + "debugger for parent worker should not be closed after it is " + + "registered"); + is(dbgs[1].isClosed, false, + "debugger for child worker should not be closed after it is " + + "registered"); + + ok(findDebugger((dbg) => dbg.url === PARENT_WORKER_URL), + "debugger for parent worker should be enumerated after it is " + + "registered"); + ok(findDebugger((dbg) => dbg.url === CHILD_WORKER_URL), + "debugger for child worker should be enumerated after it is " + + "registered"); + + promise = waitForMultiple([ + waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL), + waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL), + ]); + worker.terminate(); + dbgs = yield promise; + is(dbgs[0].isClosed, true, + "debugger for parent worker should be closed after it is " + + "unregistered"); + is(dbgs[1].isClosed, true, + "debugger for child worker should be closed after it is " + + "unregistered"); + assertThrows(() => dbgs[0].url, + "accessing debugger for parent worker should throw " + + "after it is closed"); + assertThrows(() => dbgs[0].url, + "accessing debugger for child worker should throw after " + + "it is closed"); + + ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL), + "debugger for parent worker should not be enumerated after it is " + + "unregistered"); + ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL), + "debugger for child worker should not be enumerated after it is " + + "unregistered"); + + SimpleTest.finish(); + }); + } + + ]]> + </script> + + <body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display:none;"></div> + <pre id="test"></pre> + </body> + <label id="test-result"/> +</window>
--- a/dom/workers/test/test_extension.xul +++ b/dom/workers/test/test_extension.xul @@ -11,23 +11,16 @@ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> <script type="application/javascript" src="dom_worker_helper.js"/> <script type="application/javascript"> <![CDATA[ - const Cc = Components.classes; - const Ci = Components.interfaces; - const Cu = Components.utils; - - Cu.import("resource://gre/modules/Services.jsm"); - Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - function test() { const message = "woohoo"; var workertest = Cc["@mozilla.org/test/workertest;1"].createInstance(Ci.nsIWorkerTest); workertest.callback = { onmessage: function(data) {
--- a/dom/workers/test/test_extensionBootstrap.xul +++ b/dom/workers/test/test_extensionBootstrap.xul @@ -11,24 +11,16 @@ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> <script type="application/javascript" src="dom_worker_helper.js"/> <script type="application/javascript"> <![CDATA[ - const Cc = Components.classes; - const Ci = Components.interfaces; - const Cu = Components.utils; - - Cu.import("resource://gre/modules/AddonManager.jsm"); - Cu.import("resource://gre/modules/Services.jsm"); - Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - function test() { const message = "woohoo"; var observer = { observe: function(subject, topic, data) { is(topic, "message", "Correct type of event"); is(data, message, "Correct message");
--- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -85,16 +85,17 @@ #include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMRequest.h" #include "mozilla/dom/network/TCPSocketChild.h" #include "mozilla/dom/network/TCPSocketParent.h" #include "mozilla/dom/network/TCPServerSocketChild.h" #include "mozilla/dom/network/UDPSocketChild.h" #include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/dom/workers/ServiceWorkerManager.h" +#include "mozilla/dom/workers/WorkerDebuggerManager.h" #include "mozilla/OSFileConstants.h" #include "mozilla/Services.h" #ifdef MOZ_WEBSPEECH #include "mozilla/dom/FakeSpeechRecognitionService.h" #include "mozilla/dom/nsSynthVoiceRegistry.h" #endif @@ -243,16 +244,17 @@ static void Shutdown(); #include "GMPService.h" using namespace mozilla; using namespace mozilla::dom; using mozilla::dom::alarm::AlarmHalService; using mozilla::dom::power::PowerManagerService; using mozilla::dom::quota::QuotaManager; using mozilla::dom::workers::ServiceWorkerManager; +using mozilla::dom::workers::WorkerDebuggerManager; using mozilla::dom::TCPSocketChild; using mozilla::dom::TCPSocketParent; using mozilla::dom::TCPServerSocketChild; using mozilla::dom::UDPSocketChild; using mozilla::dom::time::TimeService; using mozilla::net::StreamingProtocolControllerService; using mozilla::gmp::GeckoMediaPluginService; @@ -282,16 +284,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(Exception NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager) NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService, DOMRequestService::FactoryCreate) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManager, QuotaManager::FactoryCreate) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ServiceWorkerManager, ServiceWorkerManager::FactoryCreate) +NS_GENERIC_FACTORY_CONSTRUCTOR(WorkerDebuggerManager) + #ifdef MOZ_WIDGET_GONK NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemWorkerManager, SystemWorkerManager::FactoryCreate) #endif #ifdef MOZ_B2G_BT NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(BluetoothService, BluetoothService::FactoryCreate) #endif @@ -710,16 +714,17 @@ NS_DEFINE_NAMED_CID(NS_XMLHTTPREQUEST_CI NS_DEFINE_NAMED_CID(NS_DOMPARSER_CID); NS_DEFINE_NAMED_CID(NS_DOMSESSIONSTORAGEMANAGER_CID); NS_DEFINE_NAMED_CID(NS_DOMLOCALSTORAGEMANAGER_CID); NS_DEFINE_NAMED_CID(NS_DOMJSON_CID); NS_DEFINE_NAMED_CID(NS_TEXTEDITOR_CID); NS_DEFINE_NAMED_CID(DOMREQUEST_SERVICE_CID); NS_DEFINE_NAMED_CID(QUOTA_MANAGER_CID); NS_DEFINE_NAMED_CID(SERVICEWORKERMANAGER_CID); +NS_DEFINE_NAMED_CID(WORKERDEBUGGERMANAGER_CID); #ifdef MOZ_WIDGET_GONK NS_DEFINE_NAMED_CID(SYSTEMWORKERMANAGER_CID); #endif #ifdef MOZ_B2G_BT NS_DEFINE_NAMED_CID(BLUETOOTHSERVICE_CID); #endif #ifdef MOZ_WIDGET_GONK NS_DEFINE_NAMED_CID(NS_AUDIOMANAGER_CID); @@ -1000,16 +1005,17 @@ static const mozilla::Module::CIDEntry k { &kNS_XPCEXCEPTION_CID, false, nullptr, ExceptionConstructor }, { &kNS_DOMSESSIONSTORAGEMANAGER_CID, false, nullptr, DOMSessionStorageManagerConstructor }, { &kNS_DOMLOCALSTORAGEMANAGER_CID, false, nullptr, DOMLocalStorageManagerConstructor }, { &kNS_DOMJSON_CID, false, nullptr, NS_NewJSON }, { &kNS_TEXTEDITOR_CID, false, nullptr, nsPlaintextEditorConstructor }, { &kDOMREQUEST_SERVICE_CID, false, nullptr, DOMRequestServiceConstructor }, { &kQUOTA_MANAGER_CID, false, nullptr, QuotaManagerConstructor }, { &kSERVICEWORKERMANAGER_CID, false, nullptr, ServiceWorkerManagerConstructor }, + { &kWORKERDEBUGGERMANAGER_CID, true, nullptr, WorkerDebuggerManagerConstructor }, #ifdef MOZ_WIDGET_GONK { &kSYSTEMWORKERMANAGER_CID, true, nullptr, SystemWorkerManagerConstructor }, #endif #ifdef MOZ_B2G_BT { &kBLUETOOTHSERVICE_CID, true, nullptr, BluetoothServiceConstructor }, #endif #ifdef MOZ_WIDGET_GONK { &kNS_AUDIOMANAGER_CID, true, nullptr, AudioManagerConstructor }, @@ -1157,16 +1163,17 @@ static const mozilla::Module::ContractID // Keeping the old ContractID for backward compatibility { "@mozilla.org/dom/storagemanager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID }, { "@mozilla.org/dom/sessionStorage-manager;1", &kNS_DOMSESSIONSTORAGEMANAGER_CID }, { "@mozilla.org/dom/json;1", &kNS_DOMJSON_CID }, { "@mozilla.org/editor/texteditor;1", &kNS_TEXTEDITOR_CID }, { DOMREQUEST_SERVICE_CONTRACTID, &kDOMREQUEST_SERVICE_CID }, { QUOTA_MANAGER_CONTRACTID, &kQUOTA_MANAGER_CID }, { SERVICEWORKERMANAGER_CONTRACTID, &kSERVICEWORKERMANAGER_CID }, + { WORKERDEBUGGERMANAGER_CONTRACTID, &kWORKERDEBUGGERMANAGER_CID }, #ifdef MOZ_WIDGET_GONK { SYSTEMWORKERMANAGER_CONTRACTID, &kSYSTEMWORKERMANAGER_CID }, #endif #ifdef MOZ_B2G_BT { BLUETOOTHSERVICE_CONTRACTID, &kBLUETOOTHSERVICE_CID }, #endif #ifdef MOZ_WIDGET_GONK { NS_AUDIOMANAGER_CONTRACTID, &kNS_AUDIOMANAGER_CID },