summaryrefslogtreecommitdiffstats
path: root/dom/workers
diff options
context:
space:
mode:
Diffstat (limited to 'dom/workers')
-rw-r--r--dom/workers/EventWithOptionsRunnable.cpp16
-rw-r--r--dom/workers/MessageEventRunnable.cpp112
-rw-r--r--dom/workers/MessageEventRunnable.h16
-rw-r--r--dom/workers/RuntimeService.cpp47
-rw-r--r--dom/workers/ScriptLoader.cpp6
-rw-r--r--dom/workers/Worker.cpp6
-rw-r--r--dom/workers/WorkerCSPEventListener.cpp5
-rw-r--r--dom/workers/WorkerDebugger.cpp8
-rw-r--r--dom/workers/WorkerDocumentListener.cpp7
-rw-r--r--dom/workers/WorkerError.cpp12
-rw-r--r--dom/workers/WorkerEventTarget.cpp7
-rw-r--r--dom/workers/WorkerNavigator.cpp2
-rw-r--r--dom/workers/WorkerPrivate.cpp267
-rw-r--r--dom/workers/WorkerPrivate.h55
-rw-r--r--dom/workers/WorkerRef.cpp5
-rw-r--r--dom/workers/WorkerRef.h2
-rw-r--r--dom/workers/WorkerRunnable.cpp563
-rw-r--r--dom/workers/WorkerRunnable.h304
-rw-r--r--dom/workers/WorkerScope.cpp22
-rw-r--r--dom/workers/WorkerThread.cpp87
-rw-r--r--dom/workers/WorkerThread.h11
-rw-r--r--dom/workers/remoteworkers/RemoteWorkerChild.cpp6
-rw-r--r--dom/workers/test/test_worker_interfaces.js1
23 files changed, 950 insertions, 617 deletions
diff --git a/dom/workers/EventWithOptionsRunnable.cpp b/dom/workers/EventWithOptionsRunnable.cpp
index 2ddc56d946..5c4988c9a7 100644
--- a/dom/workers/EventWithOptionsRunnable.cpp
+++ b/dom/workers/EventWithOptionsRunnable.cpp
@@ -33,8 +33,7 @@
namespace mozilla::dom {
EventWithOptionsRunnable::EventWithOptionsRunnable(Worker& aWorker,
const char* aName)
- : WorkerDebuggeeRunnable(aWorker.mWorkerPrivate, aName,
- WorkerRunnable::WorkerThread),
+ : WorkerDebuggeeRunnable(aName),
StructuredCloneHolder(CloningSupported, TransferringSupported,
StructuredCloneScope::SameProcess) {}
@@ -132,19 +131,6 @@ bool EventWithOptionsRunnable::BuildAndFireEvent(
bool EventWithOptionsRunnable::WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) {
- if (mTarget == ParentThread) {
- // Don't fire this event if the JS object has been disconnected from the
- // private object.
- if (!aWorkerPrivate->IsAcceptingEvents()) {
- return true;
- }
-
- aWorkerPrivate->AssertInnerWindowIsCorrect();
-
- return BuildAndFireEvent(aCx, aWorkerPrivate,
- aWorkerPrivate->ParentEventTargetRef());
- }
-
MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
MOZ_ASSERT(aWorkerPrivate->GlobalScope());
diff --git a/dom/workers/MessageEventRunnable.cpp b/dom/workers/MessageEventRunnable.cpp
index 8edc7037cd..33efc966b4 100644
--- a/dom/workers/MessageEventRunnable.cpp
+++ b/dom/workers/MessageEventRunnable.cpp
@@ -14,9 +14,8 @@
namespace mozilla::dom {
-MessageEventRunnable::MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
- Target aTarget)
- : WorkerDebuggeeRunnable(aWorkerPrivate, "MessageEventRunnable", aTarget),
+MessageEventRunnable::MessageEventRunnable(WorkerPrivate* aWorkerPrivate)
+ : WorkerDebuggeeRunnable("MessageEventRunnable"),
StructuredCloneHolder(CloningSupported, TransferringSupported,
StructuredCloneScope::SameProcess) {}
@@ -84,20 +83,6 @@ bool MessageEventRunnable::DispatchDOMEvent(JSContext* aCx,
bool MessageEventRunnable::WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) {
- if (mTarget == ParentThread) {
- // Don't fire this event if the JS object has been disconnected from the
- // private object.
- if (!aWorkerPrivate->IsAcceptingEvents()) {
- return true;
- }
-
- aWorkerPrivate->AssertInnerWindowIsCorrect();
-
- return DispatchDOMEvent(aCx, aWorkerPrivate,
- aWorkerPrivate->ParentEventTargetRef(),
- !aWorkerPrivate->GetParent());
- }
-
MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
MOZ_ASSERT(aWorkerPrivate->GlobalScope());
@@ -124,4 +109,97 @@ void MessageEventRunnable::DispatchError(JSContext* aCx,
aTarget->DispatchEvent(*event);
}
+MessageEventToParentRunnable::MessageEventToParentRunnable(
+ WorkerPrivate* aWorkerPrivate)
+ : WorkerParentDebuggeeRunnable("MessageEventToParentRunnable"),
+ StructuredCloneHolder(CloningSupported, TransferringSupported,
+ StructuredCloneScope::SameProcess) {}
+
+bool MessageEventToParentRunnable::DispatchDOMEvent(
+ JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+ DOMEventTargetHelper* aTarget, bool aIsMainThread) {
+ nsCOMPtr<nsIGlobalObject> parent = aTarget->GetParentObject();
+
+ // For some workers without window, parent is null and we try to find it
+ // from the JS Context.
+ if (!parent) {
+ JS::Rooted<JSObject*> globalObject(aCx, JS::CurrentGlobalOrNull(aCx));
+ if (NS_WARN_IF(!globalObject)) {
+ return false;
+ }
+
+ parent = xpc::NativeGlobal(globalObject);
+ if (NS_WARN_IF(!parent)) {
+ return false;
+ }
+ }
+
+ MOZ_ASSERT(parent);
+
+ JS::Rooted<JS::Value> messageData(aCx);
+ IgnoredErrorResult rv;
+
+ JS::CloneDataPolicy cloneDataPolicy;
+ if (parent->GetClientInfo().isSome() &&
+ parent->GetClientInfo()->AgentClusterId().isSome() &&
+ parent->GetClientInfo()->AgentClusterId()->Equals(
+ aWorkerPrivate->AgentClusterId())) {
+ cloneDataPolicy.allowIntraClusterClonableSharedObjects();
+ }
+
+ if (aWorkerPrivate->IsSharedMemoryAllowed()) {
+ cloneDataPolicy.allowSharedMemoryObjects();
+ }
+
+ Read(parent, aCx, &messageData, cloneDataPolicy, rv);
+
+ if (NS_WARN_IF(rv.Failed())) {
+ DispatchError(aCx, aTarget);
+ return false;
+ }
+
+ Sequence<OwningNonNull<MessagePort>> ports;
+ if (!TakeTransferredPortsAsSequence(ports)) {
+ DispatchError(aCx, aTarget);
+ return false;
+ }
+
+ RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
+ event->InitMessageEvent(nullptr, u"message"_ns, CanBubble::eNo,
+ Cancelable::eNo, messageData, u""_ns, u""_ns, nullptr,
+ ports);
+
+ event->SetTrusted(true);
+
+ aTarget->DispatchEvent(*event);
+
+ return true;
+}
+
+bool MessageEventToParentRunnable::WorkerRun(JSContext* aCx,
+ WorkerPrivate* aWorkerPrivate) {
+ if (!aWorkerPrivate->IsAcceptingEvents()) {
+ return true;
+ }
+
+ aWorkerPrivate->AssertInnerWindowIsCorrect();
+
+ return DispatchDOMEvent(aCx, aWorkerPrivate,
+ aWorkerPrivate->ParentEventTargetRef(),
+ !aWorkerPrivate->GetParent());
+}
+
+void MessageEventToParentRunnable::DispatchError(
+ JSContext* aCx, DOMEventTargetHelper* aTarget) {
+ RootedDictionary<MessageEventInit> init(aCx);
+ init.mBubbles = false;
+ init.mCancelable = false;
+
+ RefPtr<Event> event =
+ MessageEvent::Constructor(aTarget, u"messageerror"_ns, init);
+ event->SetTrusted(true);
+
+ aTarget->DispatchEvent(*event);
+}
+
} // namespace mozilla::dom
diff --git a/dom/workers/MessageEventRunnable.h b/dom/workers/MessageEventRunnable.h
index c20efb4c55..45bce9949f 100644
--- a/dom/workers/MessageEventRunnable.h
+++ b/dom/workers/MessageEventRunnable.h
@@ -20,7 +20,21 @@ namespace dom {
class MessageEventRunnable final : public WorkerDebuggeeRunnable,
public StructuredCloneHolder {
public:
- MessageEventRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget);
+ explicit MessageEventRunnable(WorkerPrivate* aWorkerPrivate);
+
+ bool DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+ DOMEventTargetHelper* aTarget, bool aIsMainThread);
+
+ private:
+ bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
+
+ void DispatchError(JSContext* aCx, DOMEventTargetHelper* aTarget);
+};
+
+class MessageEventToParentRunnable final : public WorkerParentDebuggeeRunnable,
+ public StructuredCloneHolder {
+ public:
+ explicit MessageEventToParentRunnable(WorkerPrivate* aWorkerPrivate);
bool DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
DOMEventTargetHelper* aTarget, bool aIsMainThread);
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index 321895e700..047384b420 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -343,7 +343,7 @@ void LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */) {
#define PREF(suffix_, key_) \
{ \
- nsLiteralCString(PREF_MEM_OPTIONS_PREFIX suffix_), \
+ nsLiteralCString(suffix_), \
PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX suffix_, key_ \
}
constexpr WorkerGCPref kWorkerPrefs[] = {
@@ -372,6 +372,7 @@ void LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */) {
PREF("gc_parallel_marking", JSGC_PARALLEL_MARKING_ENABLED),
PREF("gc_parallel_marking_threshold_mb",
JSGC_PARALLEL_MARKING_THRESHOLD_MB),
+ PREF("gc_max_parallel_marking_threads", JSGC_MAX_MARKING_THREADS),
#ifdef NIGHTLY_BUILD
PREF("gc_experimental_semispace_nursery", JSGC_SEMISPACE_NURSERY_ENABLED),
#endif
@@ -454,6 +455,7 @@ void LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */) {
case JSGC_MAX_EMPTY_CHUNK_COUNT:
case JSGC_HEAP_GROWTH_FACTOR:
case JSGC_PARALLEL_MARKING_THRESHOLD_MB:
+ case JSGC_MAX_MARKING_THREADS:
UpdateCommonJSGCMemoryOption(rts, pref->fullName, pref->key);
break;
default:
@@ -596,7 +598,7 @@ void CTypesActivityCallback(JSContext* aCx, JS::CTypesActivityType aType) {
// do. Moreover, JS_DestroyContext() does *not* block on JS::Dispatchable::run
// being called, DispatchToEventLoopCallback failure is expected to happen
// during shutdown.
-class JSDispatchableRunnable final : public WorkerRunnable {
+class JSDispatchableRunnable final : public WorkerThreadRunnable {
JS::Dispatchable* mDispatchable;
~JSDispatchableRunnable() { MOZ_ASSERT(!mDispatchable); }
@@ -617,21 +619,19 @@ class JSDispatchableRunnable final : public WorkerRunnable {
public:
JSDispatchableRunnable(WorkerPrivate* aWorkerPrivate,
JS::Dispatchable* aDispatchable)
- : WorkerRunnable(aWorkerPrivate, "JSDispatchableRunnable",
- WorkerRunnable::WorkerThread),
+ : WorkerThreadRunnable("JSDispatchableRunnable"),
mDispatchable(aDispatchable) {
MOZ_ASSERT(mDispatchable);
}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
- MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate);
- MOZ_ASSERT(aCx == mWorkerPrivate->GetJSContext());
+ MOZ_ASSERT(aCx == aWorkerPrivate->GetJSContext());
MOZ_ASSERT(mDispatchable);
AutoJSAPI jsapi;
jsapi.Init();
- mDispatchable->run(mWorkerPrivate->GetJSContext(),
+ mDispatchable->run(aWorkerPrivate->GetJSContext(),
JS::Dispatchable::NotShuttingDown);
mDispatchable = nullptr; // mDispatchable may delete itself
@@ -644,7 +644,7 @@ class JSDispatchableRunnable final : public WorkerRunnable {
AutoJSAPI jsapi;
jsapi.Init();
- mDispatchable->run(mWorkerPrivate->GetJSContext(),
+ mDispatchable->run(GetCurrentThreadWorkerPrivate()->GetJSContext(),
JS::Dispatchable::ShuttingDown);
mDispatchable = nullptr; // mDispatchable may delete itself
@@ -665,7 +665,7 @@ static bool DispatchToEventLoop(void* aClosure,
// the JSDispatchableRunnable comment above.
RefPtr<JSDispatchableRunnable> r =
new JSDispatchableRunnable(workerPrivate, aDispatchable);
- return r->Dispatch();
+ return r->Dispatch(workerPrivate);
}
static bool ConsumeStream(JSContext* aCx, JS::Handle<JSObject*> aObj,
@@ -1482,9 +1482,9 @@ namespace {
class DumpCrashInfoRunnable final : public WorkerControlRunnable {
public:
explicit DumpCrashInfoRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerControlRunnable(aWorkerPrivate, "DumpCrashInfoRunnable",
- WorkerThread),
- mMonitor("DumpCrashInfoRunnable::mMonitor") {}
+ : WorkerControlRunnable("DumpCrashInfoRunnable"),
+ mMonitor("DumpCrashInfoRunnable::mMonitor"),
+ mWorkerPrivate(aWorkerPrivate) {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
MonitorAutoLock lock(mMonitor);
@@ -1510,7 +1510,7 @@ class DumpCrashInfoRunnable final : public WorkerControlRunnable {
bool DispatchAndWait() {
MonitorAutoLock lock(mMonitor);
- if (!Dispatch()) {
+ if (!Dispatch(mWorkerPrivate)) {
// The worker is already dead but the main thread still didn't remove it
// from RuntimeService's registry.
return false;
@@ -1537,6 +1537,7 @@ class DumpCrashInfoRunnable final : public WorkerControlRunnable {
Monitor mMonitor MOZ_UNANNOTATED;
nsCString mMsg;
FlippedOnce<false> mHasMsg;
+ WorkerPrivate* mWorkerPrivate;
};
struct ActiveWorkerStats {
@@ -2066,21 +2067,24 @@ WorkerThreadPrimaryRunnable::Run() {
url.get());
using mozilla::ipc::BackgroundChild;
-
{
+ bool runLoopRan = false;
auto failureCleanup = MakeScopeExit([&]() {
- // The creation of threadHelper above is the point at which a worker is
- // considered to have run, because the `mPreStartRunnables` are all
- // re-dispatched after `mThread` is set. We need to let the WorkerPrivate
- // know so it can clean up the various event loops and delete the worker.
- mWorkerPrivate->RunLoopNeverRan();
+ // If Worker initialization fails, call WorkerPrivate::ScheduleDeletion()
+ // to release the WorkerPrivate in the parent thread.
+ mWorkerPrivate->ScheduleDeletion(WorkerPrivate::WorkerRan);
});
mWorkerPrivate->SetWorkerPrivateInWorkerThread(mThread.unsafeGetRawPtr());
const auto threadCleanup = MakeScopeExit([&] {
- // This must be called before ScheduleDeletion, which is either called
- // from failureCleanup leaving scope, or from the outer scope.
+ // If Worker initialization fails, such as creating a BackgroundChild or
+ // the worker's JSContext initialization failing, call
+ // WorkerPrivate::RunLoopNeverRan() to set the Worker to the correct
+ // status, which means "Dead," to forbid WorkerThreadRunnable dispatching.
+ if (!runLoopRan) {
+ mWorkerPrivate->RunLoopNeverRan();
+ }
mWorkerPrivate->ResetWorkerPrivateInWorkerThread();
});
@@ -2117,6 +2121,7 @@ WorkerThreadPrimaryRunnable::Run() {
}
failureCleanup.release();
+ runLoopRan = true;
{
PROFILER_SET_JS_CONTEXT(cx);
diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp
index 9dcb1d0c9a..b841a6e357 100644
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1641,7 +1641,8 @@ void ScriptLoaderRunnable::DispatchProcessPendingRequests() {
Span<RefPtr<ThreadSafeRequestHandle>>{maybeRangeToExecute->first,
maybeRangeToExecute->second});
- if (!runnable->Dispatch() && mScriptLoader->mSyncLoopTarget) {
+ if (!runnable->Dispatch(mWorkerRef->Private()) &&
+ mScriptLoader->mSyncLoopTarget) {
MOZ_ASSERT(false, "This should never fail!");
}
}
@@ -1651,8 +1652,7 @@ ScriptExecutorRunnable::ScriptExecutorRunnable(
WorkerScriptLoader* aScriptLoader, WorkerPrivate* aWorkerPrivate,
nsISerialEventTarget* aSyncLoopTarget,
Span<RefPtr<ThreadSafeRequestHandle>> aLoadedRequests)
- : MainThreadWorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget,
- "ScriptExecutorRunnable"),
+ : MainThreadWorkerSyncRunnable(aSyncLoopTarget, "ScriptExecutorRunnable"),
mScriptLoader(aScriptLoader),
mLoadedRequests(aLoadedRequests) {}
diff --git a/dom/workers/Worker.cpp b/dom/workers/Worker.cpp
index 88df53b877..6d85948d96 100644
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -126,7 +126,7 @@ void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
JS::ProfilingCategoryPair::DOM, flags);
RefPtr<MessageEventRunnable> runnable =
- new MessageEventRunnable(mWorkerPrivate, WorkerRunnable::WorkerThread);
+ new MessageEventRunnable(mWorkerPrivate);
JS::CloneDataPolicy clonePolicy;
// DedicatedWorkers are always part of the same agent cluster.
@@ -157,7 +157,7 @@ void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
// The worker could have closed between the time we entered this function and
// checked ParentStatusProtected and now, which could cause the dispatch to
// fail.
- Unused << NS_WARN_IF(!runnable->Dispatch());
+ Unused << NS_WARN_IF(!runnable->Dispatch(mWorkerPrivate));
}
void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
@@ -191,7 +191,7 @@ void Worker::PostEventWithOptions(JSContext* aCx,
return;
}
- Unused << NS_WARN_IF(!aRunnable->Dispatch());
+ Unused << NS_WARN_IF(!aRunnable->Dispatch(mWorkerPrivate));
}
void Worker::Terminate() {
diff --git a/dom/workers/WorkerCSPEventListener.cpp b/dom/workers/WorkerCSPEventListener.cpp
index c693928486..fa17ba0dcb 100644
--- a/dom/workers/WorkerCSPEventListener.cpp
+++ b/dom/workers/WorkerCSPEventListener.cpp
@@ -19,8 +19,7 @@ namespace {
class WorkerCSPEventRunnable final : public MainThreadWorkerRunnable {
public:
WorkerCSPEventRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aJSON)
- : MainThreadWorkerRunnable(aWorkerPrivate, "WorkerCSPEventRunnable"),
- mJSON(aJSON) {}
+ : MainThreadWorkerRunnable("WorkerCSPEventRunnable"), mJSON(aJSON) {}
private:
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
@@ -83,7 +82,7 @@ WorkerCSPEventListener::OnCSPViolationEvent(const nsAString& aJSON) {
if (NS_IsMainThread()) {
RefPtr<WorkerCSPEventRunnable> runnable =
new WorkerCSPEventRunnable(workerPrivate, aJSON);
- runnable->Dispatch();
+ runnable->Dispatch(workerPrivate);
return NS_OK;
}
diff --git a/dom/workers/WorkerDebugger.cpp b/dom/workers/WorkerDebugger.cpp
index a3e0af7a38..43cccf1102 100644
--- a/dom/workers/WorkerDebugger.cpp
+++ b/dom/workers/WorkerDebugger.cpp
@@ -37,7 +37,7 @@ class DebuggerMessageEventRunnable final : public WorkerDebuggerRunnable {
public:
DebuggerMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
const nsAString& aMessage)
- : WorkerDebuggerRunnable(aWorkerPrivate, "DebuggerMessageEventRunnable"),
+ : WorkerDebuggerRunnable("DebuggerMessageEventRunnable"),
mMessage(aMessage) {}
private:
@@ -74,7 +74,7 @@ class CompileDebuggerScriptRunnable final : public WorkerDebuggerRunnable {
CompileDebuggerScriptRunnable(WorkerPrivate* aWorkerPrivate,
const nsAString& aScriptURL,
const mozilla::Encoding* aDocumentEncoding)
- : WorkerDebuggerRunnable(aWorkerPrivate, "CompileDebuggerScriptRunnable"),
+ : WorkerDebuggerRunnable("CompileDebuggerScriptRunnable"),
mScriptURL(aScriptURL),
mDocumentEncoding(aDocumentEncoding) {}
@@ -376,7 +376,7 @@ WorkerDebugger::Initialize(const nsAString& aURL) {
RefPtr<CompileDebuggerScriptRunnable> runnable =
new CompileDebuggerScriptRunnable(mWorkerPrivate, aURL,
aDocumentEncoding);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(mWorkerPrivate)) {
return NS_ERROR_FAILURE;
}
@@ -396,7 +396,7 @@ WorkerDebugger::PostMessageMoz(const nsAString& aMessage) {
RefPtr<DebuggerMessageEventRunnable> runnable =
new DebuggerMessageEventRunnable(mWorkerPrivate, aMessage);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(mWorkerPrivate)) {
return NS_ERROR_FAILURE;
}
diff --git a/dom/workers/WorkerDocumentListener.cpp b/dom/workers/WorkerDocumentListener.cpp
index cdbe30e072..a5285f7ad9 100644
--- a/dom/workers/WorkerDocumentListener.cpp
+++ b/dom/workers/WorkerDocumentListener.cpp
@@ -52,11 +52,10 @@ void WorkerDocumentListener::OnVisible(bool aVisible) {
return;
}
- class VisibleRunnable final : public WorkerRunnable {
+ class VisibleRunnable final : public WorkerThreadRunnable {
public:
VisibleRunnable(WorkerPrivate* aWorkerPrivate, bool aVisible)
- : WorkerRunnable(aWorkerPrivate, "VisibleRunnable"),
- mVisible(aVisible) {}
+ : WorkerThreadRunnable("VisibleRunnable"), mVisible(aVisible) {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
WorkerGlobalScope* scope = aWorkerPrivate->GlobalScope();
@@ -70,7 +69,7 @@ void WorkerDocumentListener::OnVisible(bool aVisible) {
};
auto runnable = MakeRefPtr<VisibleRunnable>(mWorkerRef->Private(), aVisible);
- runnable->Dispatch();
+ runnable->Dispatch(mWorkerRef->Private());
}
void WorkerDocumentListener::SetListening(uint64_t aWindowID, bool aListen) {
diff --git a/dom/workers/WorkerError.cpp b/dom/workers/WorkerError.cpp
index 1b75599211..4fe9b237fe 100644
--- a/dom/workers/WorkerError.cpp
+++ b/dom/workers/WorkerError.cpp
@@ -62,13 +62,13 @@ namespace mozilla::dom {
namespace {
-class ReportErrorRunnable final : public WorkerDebuggeeRunnable {
+class ReportErrorRunnable final : public WorkerParentDebuggeeRunnable {
UniquePtr<WorkerErrorReport> mReport;
public:
ReportErrorRunnable(WorkerPrivate* aWorkerPrivate,
UniquePtr<WorkerErrorReport> aReport)
- : WorkerDebuggeeRunnable(aWorkerPrivate, "ReportErrorRunnable"),
+ : WorkerParentDebuggeeRunnable("ReportErrorRunnable"),
mReport(std::move(aReport)) {}
private:
@@ -138,7 +138,7 @@ class ReportErrorRunnable final : public WorkerDebuggeeRunnable {
}
};
-class ReportGenericErrorRunnable final : public WorkerDebuggeeRunnable {
+class ReportGenericErrorRunnable final : public WorkerParentDebuggeeRunnable {
public:
static void CreateAndDispatch(WorkerPrivate* aWorkerPrivate) {
MOZ_ASSERT(aWorkerPrivate);
@@ -146,12 +146,12 @@ class ReportGenericErrorRunnable final : public WorkerDebuggeeRunnable {
RefPtr<ReportGenericErrorRunnable> runnable =
new ReportGenericErrorRunnable(aWorkerPrivate);
- runnable->Dispatch();
+ runnable->Dispatch(aWorkerPrivate);
}
private:
explicit ReportGenericErrorRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerDebuggeeRunnable(aWorkerPrivate, "ReportGenericErrorRunnable") {
+ : WorkerParentDebuggeeRunnable("ReportGenericErrorRunnable") {
aWorkerPrivate->AssertIsOnWorkerThread();
}
@@ -354,7 +354,7 @@ void WorkerErrorReport::ReportError(
if (aWorkerPrivate) {
RefPtr<ReportErrorRunnable> runnable =
new ReportErrorRunnable(aWorkerPrivate, std::move(aReport));
- runnable->Dispatch();
+ runnable->Dispatch(aWorkerPrivate);
return;
}
diff --git a/dom/workers/WorkerEventTarget.cpp b/dom/workers/WorkerEventTarget.cpp
index cb58b4f8ed..94ba7a8097 100644
--- a/dom/workers/WorkerEventTarget.cpp
+++ b/dom/workers/WorkerEventTarget.cpp
@@ -34,8 +34,7 @@ class WrappedControlRunnable final : public WorkerControlRunnable {
public:
WrappedControlRunnable(WorkerPrivate* aWorkerPrivate,
nsCOMPtr<nsIRunnable>&& aInner)
- : WorkerControlRunnable(aWorkerPrivate, "WrappedControlRunnable",
- WorkerThread),
+ : WorkerControlRunnable("WrappedControlRunnable"),
mInner(std::move(aInner)) {}
virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
@@ -119,7 +118,7 @@ WorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
RefPtr<WorkerRunnable> r =
mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
- if (r->Dispatch()) {
+ if (r->Dispatch(mWorkerPrivate)) {
return NS_OK;
}
runnable = std::move(r);
@@ -134,7 +133,7 @@ WorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
("WorkerEventTarget::Dispatch [%p] Wrapped runnable as control "
"runnable(%p)",
this, r.get()));
- if (!r->Dispatch()) {
+ if (!r->Dispatch(mWorkerPrivate)) {
LOGV(
("WorkerEventTarget::Dispatch [%p] Dispatch as control runnable(%p) "
"fail",
diff --git a/dom/workers/WorkerNavigator.cpp b/dom/workers/WorkerNavigator.cpp
index 1be36bc7d4..0f9dada965 100644
--- a/dom/workers/WorkerNavigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -227,6 +227,8 @@ StorageManager* WorkerNavigator::Storage() {
MOZ_ASSERT(global);
mStorageManager = new StorageManager(global);
+
+ workerPrivate->NotifyStorageKeyUsed();
}
return mStorageManager;
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index df248acda4..d9bf764312 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -180,19 +180,20 @@ inline UniquePtrComparator<T> GetUniquePtrComparator(
// This class is used to wrap any runnables that the worker receives via the
// nsIEventTarget::Dispatch() method (either from NS_DispatchToCurrentThread or
// from the worker's EventTarget).
-class ExternalRunnableWrapper final : public WorkerRunnable {
+class ExternalRunnableWrapper final : public WorkerThreadRunnable {
nsCOMPtr<nsIRunnable> mWrappedRunnable;
public:
ExternalRunnableWrapper(WorkerPrivate* aWorkerPrivate,
nsIRunnable* aWrappedRunnable)
- : WorkerRunnable(aWorkerPrivate, "ExternalRunnableWrapper", WorkerThread),
+ : WorkerThreadRunnable("ExternalRunnableWrapper"),
mWrappedRunnable(aWrappedRunnable) {
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aWrappedRunnable);
}
- NS_INLINE_DECL_REFCOUNTING_INHERITED(ExternalRunnableWrapper, WorkerRunnable)
+ NS_INLINE_DECL_REFCOUNTING_INHERITED(ExternalRunnableWrapper,
+ WorkerThreadRunnable)
private:
~ExternalRunnableWrapper() = default;
@@ -249,8 +250,7 @@ class WorkerFinishedRunnable final : public WorkerControlRunnable {
public:
WorkerFinishedRunnable(WorkerPrivate* aWorkerPrivate,
WorkerPrivate* aFinishedWorker)
- : WorkerControlRunnable(aWorkerPrivate, "WorkerFinishedRunnable",
- WorkerThread),
+ : WorkerControlRunnable("WorkerFinishedRunnable"),
mFinishedWorker(aFinishedWorker) {
aFinishedWorker->IncreaseWorkerFinishedRunnableCount();
}
@@ -337,8 +337,7 @@ class CompileScriptRunnable final : public WorkerDebuggeeRunnable {
UniquePtr<SerializedStackHolder> aOriginStack,
const nsAString& aScriptURL,
const mozilla::Encoding* aDocumentEncoding)
- : WorkerDebuggeeRunnable(aWorkerPrivate, "CompileScriptRunnable",
- WorkerThread),
+ : WorkerDebuggeeRunnable("CompileScriptRunnable"),
mScriptURL(aScriptURL),
mDocumentEncoding(aDocumentEncoding),
mOriginStack(aOriginStack.release()) {}
@@ -436,7 +435,7 @@ class CompileScriptRunnable final : public WorkerDebuggeeRunnable {
if (!aRunResult) {
aWorkerPrivate->CloseInternal();
}
- WorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult);
+ WorkerThreadRunnable::PostRun(aCx, aWorkerPrivate, aRunResult);
}
};
@@ -445,8 +444,7 @@ class NotifyRunnable final : public WorkerControlRunnable {
public:
NotifyRunnable(WorkerPrivate* aWorkerPrivate, WorkerStatus aStatus)
- : WorkerControlRunnable(aWorkerPrivate, "NotifyRunnable", WorkerThread),
- mStatus(aStatus) {
+ : WorkerControlRunnable("NotifyRunnable"), mStatus(aStatus) {
MOZ_ASSERT(aStatus == Closing || aStatus == Canceling ||
aStatus == Killing);
}
@@ -474,7 +472,7 @@ class NotifyRunnable final : public WorkerControlRunnable {
class FreezeRunnable final : public WorkerControlRunnable {
public:
explicit FreezeRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerControlRunnable(aWorkerPrivate, "FreezeRunnable", WorkerThread) {}
+ : WorkerControlRunnable("FreezeRunnable") {}
private:
virtual bool WorkerRun(JSContext* aCx,
@@ -486,7 +484,7 @@ class FreezeRunnable final : public WorkerControlRunnable {
class ThawRunnable final : public WorkerControlRunnable {
public:
explicit ThawRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerControlRunnable(aWorkerPrivate, "ThawRunnable", WorkerThread) {}
+ : WorkerControlRunnable("ThawRunnable") {}
private:
virtual bool WorkerRun(JSContext* aCx,
@@ -500,9 +498,8 @@ class PropagateStorageAccessPermissionGrantedRunnable final
public:
explicit PropagateStorageAccessPermissionGrantedRunnable(
WorkerPrivate* aWorkerPrivate)
- : WorkerControlRunnable(aWorkerPrivate,
- "PropagateStorageAccessPermissionGrantedRunnable",
- WorkerThread) {}
+ : WorkerControlRunnable(
+ "PropagateStorageAccessPermissionGrantedRunnable") {}
private:
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
@@ -511,7 +508,7 @@ class PropagateStorageAccessPermissionGrantedRunnable final
}
};
-class ReportErrorToConsoleRunnable final : public WorkerRunnable {
+class ReportErrorToConsoleRunnable final : public WorkerParentThreadRunnable {
const char* mMessage;
const nsTArray<nsString> mParams;
@@ -529,7 +526,7 @@ class ReportErrorToConsoleRunnable final : public WorkerRunnable {
if (aWorkerPrivate) {
RefPtr<ReportErrorToConsoleRunnable> runnable =
new ReportErrorToConsoleRunnable(aWorkerPrivate, aMessage, aParams);
- runnable->Dispatch();
+ runnable->Dispatch(aWorkerPrivate);
return;
}
@@ -543,8 +540,7 @@ class ReportErrorToConsoleRunnable final : public WorkerRunnable {
ReportErrorToConsoleRunnable(WorkerPrivate* aWorkerPrivate,
const char* aMessage,
const nsTArray<nsString>& aParams)
- : WorkerRunnable(aWorkerPrivate, "ReportErrorToConsoleRunnable",
- ParentThread),
+ : WorkerParentThreadRunnable("ReportErrorToConsoleRunnable"),
mMessage(aMessage),
mParams(aParams.Clone()) {}
@@ -565,14 +561,13 @@ class ReportErrorToConsoleRunnable final : public WorkerRunnable {
}
};
-class RunExpiredTimoutsRunnable final : public WorkerRunnable,
+class RunExpiredTimoutsRunnable final : public WorkerThreadRunnable,
public nsITimerCallback {
public:
NS_DECL_ISUPPORTS_INHERITED
explicit RunExpiredTimoutsRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerRunnable(aWorkerPrivate, "RunExpiredTimoutsRunnable",
- WorkerThread) {}
+ : WorkerThreadRunnable("RunExpiredTimoutsRunnable") {}
private:
~RunExpiredTimoutsRunnable() = default;
@@ -599,17 +594,16 @@ class RunExpiredTimoutsRunnable final : public WorkerRunnable,
Notify(nsITimer* aTimer) override { return Run(); }
};
-NS_IMPL_ISUPPORTS_INHERITED(RunExpiredTimoutsRunnable, WorkerRunnable,
+NS_IMPL_ISUPPORTS_INHERITED(RunExpiredTimoutsRunnable, WorkerThreadRunnable,
nsITimerCallback)
-class DebuggerImmediateRunnable final : public WorkerRunnable {
+class DebuggerImmediateRunnable final : public WorkerThreadRunnable {
RefPtr<dom::Function> mHandler;
public:
explicit DebuggerImmediateRunnable(WorkerPrivate* aWorkerPrivate,
dom::Function& aHandler)
- : WorkerRunnable(aWorkerPrivate, "DebuggerImmediateRunnable",
- WorkerThread),
+ : WorkerThreadRunnable("DebuggerImmediateRunnable"),
mHandler(&aHandler) {}
private:
@@ -670,8 +664,7 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable {
public:
UpdateContextOptionsRunnable(WorkerPrivate* aWorkerPrivate,
const JS::ContextOptions& aContextOptions)
- : WorkerControlRunnable(aWorkerPrivate, "UpdateContextOptionsRunnable",
- WorkerThread),
+ : WorkerControlRunnable("UpdateContextOptionsRunnable"),
mContextOptions(aContextOptions) {}
private:
@@ -682,13 +675,13 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable {
}
};
-class UpdateLanguagesRunnable final : public WorkerRunnable {
+class UpdateLanguagesRunnable final : public WorkerThreadRunnable {
nsTArray<nsString> mLanguages;
public:
UpdateLanguagesRunnable(WorkerPrivate* aWorkerPrivate,
const nsTArray<nsString>& aLanguages)
- : WorkerRunnable(aWorkerPrivate, "UpdateLanguagesRunnable"),
+ : WorkerThreadRunnable("UpdateLanguagesRunnable"),
mLanguages(aLanguages.Clone()) {}
virtual bool WorkerRun(JSContext* aCx,
@@ -707,9 +700,7 @@ class UpdateJSWorkerMemoryParameterRunnable final
UpdateJSWorkerMemoryParameterRunnable(WorkerPrivate* aWorkerPrivate,
JSGCParamKey aKey,
Maybe<uint32_t> aValue)
- : WorkerControlRunnable(aWorkerPrivate,
- "UpdateJSWorkerMemoryParameterRunnable",
- WorkerThread),
+ : WorkerControlRunnable("UpdateJSWorkerMemoryParameterRunnable"),
mValue(aValue),
mKey(aKey) {}
@@ -729,8 +720,7 @@ class UpdateGCZealRunnable final : public WorkerControlRunnable {
public:
UpdateGCZealRunnable(WorkerPrivate* aWorkerPrivate, uint8_t aGCZeal,
uint32_t aFrequency)
- : WorkerControlRunnable(aWorkerPrivate, "UpdateGCZealRunnable",
- WorkerThread),
+ : WorkerControlRunnable("UpdateGCZealRunnable"),
mGCZeal(aGCZeal),
mFrequency(aFrequency) {}
@@ -748,9 +738,7 @@ class SetLowMemoryStateRunnable final : public WorkerControlRunnable {
public:
SetLowMemoryStateRunnable(WorkerPrivate* aWorkerPrivate, bool aState)
- : WorkerControlRunnable(aWorkerPrivate, "SetLowMemoryStateRunnable",
- WorkerThread),
- mState(aState) {}
+ : WorkerControlRunnable("SetLowMemoryStateRunnable"), mState(aState) {}
private:
virtual bool WorkerRun(JSContext* aCx,
@@ -767,8 +755,7 @@ class GarbageCollectRunnable final : public WorkerControlRunnable {
public:
GarbageCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aShrinking,
bool aCollectChildren)
- : WorkerControlRunnable(aWorkerPrivate, "GarbageCollectRunnable",
- WorkerThread),
+ : WorkerControlRunnable("GarbageCollectRunnable"),
mShrinking(aShrinking),
mCollectChildren(aCollectChildren) {}
@@ -802,8 +789,7 @@ class CycleCollectRunnable final : public WorkerControlRunnable {
public:
CycleCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aCollectChildren)
- : WorkerControlRunnable(aWorkerPrivate, "CycleCollectRunnable",
- WorkerThread),
+ : WorkerControlRunnable("CycleCollectRunnable"),
mCollectChildren(aCollectChildren) {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
@@ -812,10 +798,10 @@ class CycleCollectRunnable final : public WorkerControlRunnable {
}
};
-class OfflineStatusChangeRunnable final : public WorkerRunnable {
+class OfflineStatusChangeRunnable final : public WorkerThreadRunnable {
public:
OfflineStatusChangeRunnable(WorkerPrivate* aWorkerPrivate, bool aIsOffline)
- : WorkerRunnable(aWorkerPrivate, "OfflineStatusChangeRunnable"),
+ : WorkerThreadRunnable("OfflineStatusChangeRunnable"),
mIsOffline(aIsOffline) {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
@@ -830,8 +816,7 @@ class OfflineStatusChangeRunnable final : public WorkerRunnable {
class MemoryPressureRunnable final : public WorkerControlRunnable {
public:
explicit MemoryPressureRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerControlRunnable(aWorkerPrivate, "MemoryPressureRunnable",
- WorkerThread) {}
+ : WorkerControlRunnable("MemoryPressureRunnable") {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
aWorkerPrivate->MemoryPressureInternal();
@@ -859,11 +844,10 @@ PRThread* PRThreadFromThread(nsIThread* aThread) {
// called. This runnable is executed on the parent process in order to cancel
// the current runnable. It uses a normal WorkerDebuggeeRunnable in order to be
// sure that all the pending WorkerDebuggeeRunnables are executed before this.
-class CancelingOnParentRunnable final : public WorkerDebuggeeRunnable {
+class CancelingOnParentRunnable final : public WorkerParentDebuggeeRunnable {
public:
explicit CancelingOnParentRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerDebuggeeRunnable(aWorkerPrivate, "CancelingOnParentRunnable",
- ParentThread) {}
+ : WorkerParentDebuggeeRunnable("CancelingOnParentRunnable") {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
aWorkerPrivate->Cancel();
@@ -873,12 +857,10 @@ class CancelingOnParentRunnable final : public WorkerDebuggeeRunnable {
// A runnable to cancel the worker from the parent process.
class CancelingWithTimeoutOnParentRunnable final
- : public WorkerControlRunnable {
+ : public WorkerParentControlRunnable {
public:
explicit CancelingWithTimeoutOnParentRunnable(WorkerPrivate* aWorkerPrivate)
- : WorkerControlRunnable(aWorkerPrivate,
- "CancelingWithTimeoutOnParentRunnable",
- ParentThread) {}
+ : WorkerParentControlRunnable("CancelingWithTimeoutOnParentRunnable") {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
aWorkerPrivate->AssertIsOnParentThread();
@@ -926,7 +908,7 @@ class CancelingRunnable final : public Runnable {
// Now we can cancel the this worker from the parent process.
RefPtr<CancelingOnParentRunnable> r =
new CancelingOnParentRunnable(workerPrivate);
- r->Dispatch();
+ r->Dispatch(workerPrivate);
return NS_OK;
}
@@ -1252,7 +1234,7 @@ WorkerPrivate::MemoryReporter::CollectReports(
aAnonymize, path);
}
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(mWorkerPrivate)) {
return NS_ERROR_UNEXPECTED;
}
@@ -1262,7 +1244,7 @@ WorkerPrivate::MemoryReporter::CollectReports(
WorkerPrivate::MemoryReporter::CollectReportsRunnable::CollectReportsRunnable(
WorkerPrivate* aWorkerPrivate, nsIHandleReportCallback* aHandleReport,
nsISupports* aHandlerData, bool aAnonymize, const nsACString& aPath)
- : MainThreadWorkerControlRunnable(aWorkerPrivate),
+ : MainThreadWorkerControlRunnable("CollectReportsRunnable"),
mFinishCollectRunnable(new FinishCollectRunnable(
aHandleReport, aHandlerData, aAnonymize, aPath)),
mAnonymize(aAnonymize) {}
@@ -1559,8 +1541,48 @@ void WorkerPrivate::Traverse(nsCycleCollectionTraversalCallback& aCb) {
nsresult WorkerPrivate::Dispatch(already_AddRefed<WorkerRunnable> aRunnable,
nsIEventTarget* aSyncLoopTarget) {
// May be called on any thread!
+ RefPtr<WorkerRunnable> runnable(aRunnable);
+
+ LOGV(("WorkerPrivate::Dispatch [%p] runnable %p", this, runnable.get()));
+ if (!aSyncLoopTarget) {
+ // Dispatch control runnable
+ if (runnable->IsControlRunnable()) {
+ return DispatchControlRunnable(runnable.forget());
+ }
+
+ // Dispatch debugger runnable
+ if (runnable->IsDebuggerRunnable()) {
+ return DispatchDebuggerRunnable(runnable.forget());
+ }
+ }
MutexAutoLock lock(mMutex);
- return DispatchLockHeld(std::move(aRunnable), aSyncLoopTarget, lock);
+ return DispatchLockHeld(runnable.forget(), aSyncLoopTarget, lock);
+}
+
+nsresult WorkerPrivate::DispatchToParent(
+ already_AddRefed<WorkerRunnable> aRunnable) {
+ RefPtr<WorkerRunnable> runnable(aRunnable);
+
+ LOGV(("WorkerPrivate::DispatchToParent [%p] runnable %p", this,
+ runnable.get()));
+
+ WorkerPrivate* parent = GetParent();
+ // Dispatch to parent worker
+ if (parent) {
+ if (runnable->IsControlRunnable()) {
+ return parent->DispatchControlRunnable(runnable.forget());
+ }
+ return parent->Dispatch(runnable.forget());
+ }
+
+ // Dispatch to main thread
+ if (runnable->IsDebuggeeRunnable()) {
+ RefPtr<WorkerParentDebuggeeRunnable> debuggeeRunnable =
+ runnable.forget().downcast<WorkerParentDebuggeeRunnable>();
+ return DispatchDebuggeeToMainThread(debuggeeRunnable.forget(),
+ NS_DISPATCH_NORMAL);
+ }
+ return DispatchToMainThread(runnable.forget());
}
nsresult WorkerPrivate::DispatchLockHeld(
@@ -1573,6 +1595,7 @@ nsresult WorkerPrivate::DispatchLockHeld(
MOZ_ASSERT_IF(aSyncLoopTarget, mThread);
+ // Dispatch normal worker runnable
if (mStatus == Dead || (!aSyncLoopTarget && ParentStatus() > Canceling)) {
NS_WARNING(
"A runnable was posted to a worker that is already shutting "
@@ -1592,7 +1615,10 @@ nsresult WorkerPrivate::DispatchLockHeld(
("WorkerPrivate::DispatchLockHeld [%p] runnable %p is queued in "
"mPreStartRunnables",
this, runnable.get()));
- mPreStartRunnables.AppendElement(runnable);
+ RefPtr<WorkerThreadRunnable> workerThreadRunnable =
+ static_cast<WorkerThreadRunnable*>(runnable.get());
+ workerThreadRunnable->mWorkerPrivateForPreStartCleaning = this;
+ mPreStartRunnables.AppendElement(workerThreadRunnable);
return NS_OK;
}
@@ -1654,10 +1680,10 @@ void WorkerPrivate::DisableDebugger() {
}
nsresult WorkerPrivate::DispatchControlRunnable(
- already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable) {
+ already_AddRefed<WorkerRunnable> aWorkerRunnable) {
// May be called on any thread!
- RefPtr<WorkerControlRunnable> runnable(aWorkerControlRunnable);
- MOZ_ASSERT(runnable);
+ RefPtr<WorkerRunnable> runnable(aWorkerRunnable);
+ MOZ_ASSERT_DEBUG_OR_FUZZING(runnable && runnable->IsControlRunnable());
LOG(WorkerLog(), ("WorkerPrivate::DispatchControlRunnable [%p] runnable %p",
this, runnable.get()));
@@ -1769,6 +1795,8 @@ bool WorkerPrivate::Notify(WorkerStatus aStatus) {
mCancellationCallback = nullptr;
}
+ mParentRef->DropWorkerPrivate();
+
if (pending) {
#ifdef DEBUG
{
@@ -1803,7 +1831,7 @@ bool WorkerPrivate::Notify(WorkerStatus aStatus) {
}
RefPtr<NotifyRunnable> runnable = new NotifyRunnable(this, aStatus);
- return runnable->Dispatch();
+ return runnable->Dispatch(this);
}
bool WorkerPrivate::Freeze(const nsPIDOMWindowInner* aWindow) {
@@ -1841,7 +1869,7 @@ bool WorkerPrivate::Freeze(const nsPIDOMWindowInner* aWindow) {
DisableDebugger();
RefPtr<FreezeRunnable> runnable = new FreezeRunnable(this);
- return runnable->Dispatch();
+ return runnable->Dispatch(this);
}
bool WorkerPrivate::Thaw(const nsPIDOMWindowInner* aWindow) {
@@ -1883,7 +1911,7 @@ bool WorkerPrivate::Thaw(const nsPIDOMWindowInner* aWindow) {
EnableDebugger();
RefPtr<ThawRunnable> runnable = new ThawRunnable(this);
- return runnable->Dispatch();
+ return runnable->Dispatch(this);
}
void WorkerPrivate::ParentWindowPaused() {
@@ -1945,7 +1973,33 @@ void WorkerPrivate::PropagateStorageAccessPermissionGranted() {
RefPtr<PropagateStorageAccessPermissionGrantedRunnable> runnable =
new PropagateStorageAccessPermissionGrantedRunnable(this);
- Unused << NS_WARN_IF(!runnable->Dispatch());
+ Unused << NS_WARN_IF(!runnable->Dispatch(this));
+}
+
+void WorkerPrivate::NotifyStorageKeyUsed() {
+ AssertIsOnWorkerThread();
+
+ // Only notify once per global.
+ if (hasNotifiedStorageKeyUsed) {
+ return;
+ }
+ hasNotifiedStorageKeyUsed = true;
+
+ // Notify about storage access on the main thread.
+ RefPtr<StrongWorkerRef> strongRef =
+ StrongWorkerRef::Create(this, "WorkerPrivate::NotifyStorageKeyUsed");
+ if (!strongRef) {
+ return;
+ }
+ RefPtr<ThreadSafeWorkerRef> ref = new ThreadSafeWorkerRef(strongRef);
+ DispatchToMainThread(NS_NewRunnableFunction(
+ "WorkerPrivate::NotifyStorageKeyUsed", [ref = std::move(ref)] {
+ nsGlobalWindowInner* window =
+ nsGlobalWindowInner::Cast(ref->Private()->GetAncestorWindow());
+ if (window) {
+ window->MaybeNotifyStorageKeyUsed();
+ }
+ }));
}
bool WorkerPrivate::Close() {
@@ -1987,7 +2041,7 @@ void WorkerPrivate::UpdateContextOptions(
RefPtr<UpdateContextOptionsRunnable> runnable =
new UpdateContextOptionsRunnable(this, aContextOptions);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to update worker context options!");
}
}
@@ -1997,7 +2051,7 @@ void WorkerPrivate::UpdateLanguages(const nsTArray<nsString>& aLanguages) {
RefPtr<UpdateLanguagesRunnable> runnable =
new UpdateLanguagesRunnable(this, aLanguages);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to update worker languages!");
}
}
@@ -2016,7 +2070,7 @@ void WorkerPrivate::UpdateJSWorkerMemoryParameter(JSGCParamKey aKey,
if (changed) {
RefPtr<UpdateJSWorkerMemoryParameterRunnable> runnable =
new UpdateJSWorkerMemoryParameterRunnable(this, aKey, aValue);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to update memory parameter!");
}
}
@@ -2034,7 +2088,7 @@ void WorkerPrivate::UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency) {
RefPtr<UpdateGCZealRunnable> runnable =
new UpdateGCZealRunnable(this, aGCZeal, aFrequency);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to update worker gczeal!");
}
}
@@ -2045,7 +2099,7 @@ void WorkerPrivate::SetLowMemoryState(bool aState) {
RefPtr<SetLowMemoryStateRunnable> runnable =
new SetLowMemoryStateRunnable(this, aState);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to set low memory state!");
}
}
@@ -2055,7 +2109,7 @@ void WorkerPrivate::GarbageCollect(bool aShrinking) {
RefPtr<GarbageCollectRunnable> runnable = new GarbageCollectRunnable(
this, aShrinking, /* aCollectChildren = */ true);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to GC worker!");
}
}
@@ -2065,7 +2119,7 @@ void WorkerPrivate::CycleCollect() {
RefPtr<CycleCollectRunnable> runnable =
new CycleCollectRunnable(this, /* aCollectChildren = */ true);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to CC worker!");
}
}
@@ -2075,7 +2129,7 @@ void WorkerPrivate::OfflineStatusChangeEvent(bool aIsOffline) {
RefPtr<OfflineStatusChangeRunnable> runnable =
new OfflineStatusChangeRunnable(this, aIsOffline);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
NS_WARNING("Failed to dispatch offline status change event!");
}
}
@@ -2118,7 +2172,7 @@ void WorkerPrivate::MemoryPressure() {
AssertIsOnParentThread();
RefPtr<MemoryPressureRunnable> runnable = new MemoryPressureRunnable(this);
- Unused << NS_WARN_IF(!runnable->Dispatch());
+ Unused << NS_WARN_IF(!runnable->Dispatch(this));
}
RefPtr<WorkerPrivate::JSMemoryUsagePromise> WorkerPrivate::GetJSMemoryUsage() {
@@ -2661,6 +2715,7 @@ already_AddRefed<WorkerPrivate> WorkerPrivate::Constructor(
// must keep ourself alive. We can now only be cleared by
// ClearSelfAndParentEventTargetRef().
worker->mSelfRef = worker;
+ worker->mParentRef = MakeRefPtr<WorkerParentRef>(worker);
worker->EnableDebugger();
@@ -2681,7 +2736,7 @@ already_AddRefed<WorkerPrivate> WorkerPrivate::Constructor(
RefPtr<CompileScriptRunnable> compiler = new CompileScriptRunnable(
worker, std::move(stack), aScriptURL, aDocumentEncoding);
- if (!compiler->Dispatch()) {
+ if (!compiler->Dispatch(worker)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
@@ -3134,7 +3189,7 @@ void WorkerPrivate::RunLoopNeverRan() {
// After mStatus is set to Dead there can be no more
// WorkerControlRunnables so no need to lock here.
if (!mControlQueue.IsEmpty()) {
- WorkerControlRunnable* runnable = nullptr;
+ WorkerRunnable* runnable = nullptr;
while (mControlQueue.Pop(runnable)) {
runnable->Cancel();
runnable->Release();
@@ -3146,8 +3201,6 @@ void WorkerPrivate::RunLoopNeverRan() {
// PerformanceStorageWorker which holds a WeakWorkerRef.
// Notify WeakWorkerRefs with Dead status.
NotifyWorkerRefs(Dead);
-
- ScheduleDeletion(WorkerPrivate::WorkerRan);
}
void WorkerPrivate::UnrootGlobalScopes() {
@@ -3355,7 +3408,7 @@ void WorkerPrivate::DoRunLoop(JSContext* aCx) {
("WorkerPrivate::DoRunLoop [%p] dropping control runnables in "
"Dead status",
this));
- WorkerControlRunnable* runnable = nullptr;
+ WorkerRunnable* runnable = nullptr;
while (mControlQueue.Pop(runnable)) {
runnable->Cancel();
runnable->Release();
@@ -3530,8 +3583,11 @@ nsresult WorkerPrivate::DispatchToMainThread(
}
nsresult WorkerPrivate::DispatchDebuggeeToMainThread(
- already_AddRefed<WorkerDebuggeeRunnable> aRunnable, uint32_t aFlags) {
- return mMainThreadDebuggeeEventTarget->Dispatch(std::move(aRunnable), aFlags);
+ already_AddRefed<WorkerRunnable> aRunnable, uint32_t aFlags) {
+ RefPtr<WorkerRunnable> debuggeeRunnable = std::move(aRunnable);
+ MOZ_ASSERT_DEBUG_OR_FUZZING(debuggeeRunnable->IsDebuggeeRunnable());
+ return mMainThreadDebuggeeEventTarget->Dispatch(debuggeeRunnable.forget(),
+ aFlags);
}
nsISerialEventTarget* WorkerPrivate::ControlEventTarget() {
@@ -3915,7 +3971,7 @@ void WorkerPrivate::ScheduleDeletion(WorkerRanOrNot aRanOrNot) {
if (WorkerPrivate* parent = GetParent()) {
RefPtr<WorkerFinishedRunnable> runnable =
new WorkerFinishedRunnable(parent, this);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(parent)) {
NS_WARNING("Failed to dispatch runnable!");
}
} else {
@@ -4028,7 +4084,7 @@ WorkerPrivate::ProcessAllControlRunnablesLocked() {
auto result = ProcessAllControlRunnablesResult::Nothing;
for (;;) {
- WorkerControlRunnable* event;
+ WorkerRunnable* event;
if (!mControlQueue.Pop(event)) {
break;
}
@@ -4327,6 +4383,11 @@ void WorkerPrivate::RunShutdownTasks() {
mWorkerHybridEventTarget->ForgetWorkerPrivate(this);
}
+RefPtr<WorkerParentRef> WorkerPrivate::GetWorkerParentRef() const {
+ RefPtr<WorkerParentRef> ref(mParentRef);
+ return ref;
+}
+
void WorkerPrivate::AdjustNonblockingCCBackgroundActorCount(int32_t aCount) {
AssertIsOnWorkerThread();
auto data = mWorkerThreadAccessible.Access();
@@ -4704,7 +4765,7 @@ void WorkerPrivate::DispatchCancelingRunnable() {
this));
RefPtr<CancelingWithTimeoutOnParentRunnable> rr =
new CancelingWithTimeoutOnParentRunnable(this);
- rr->Dispatch();
+ rr->Dispatch(this);
}
void WorkerPrivate::ReportUseCounters() {
@@ -4848,8 +4909,8 @@ void WorkerPrivate::PostMessageToParent(
return;
}
- RefPtr<MessageEventRunnable> runnable =
- new MessageEventRunnable(this, WorkerRunnable::ParentThread);
+ RefPtr<MessageEventToParentRunnable> runnable =
+ new MessageEventToParentRunnable(this);
JS::CloneDataPolicy clonePolicy;
@@ -4866,7 +4927,7 @@ void WorkerPrivate::PostMessageToParent(
return;
}
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
aRv = NS_ERROR_FAILURE;
}
}
@@ -4966,7 +5027,7 @@ void WorkerPrivate::SetDebuggerImmediate(dom::Function& aHandler,
RefPtr<DebuggerImmediateRunnable> runnable =
new DebuggerImmediateRunnable(this, aHandler);
- if (!runnable->Dispatch()) {
+ if (!runnable->Dispatch(this)) {
aRv.Throw(NS_ERROR_FAILURE);
}
}
@@ -5711,10 +5772,11 @@ void WorkerPrivate::ResetWorkerPrivateInWorkerThread() {
// Release the mutex before doomedThread.
MutexAutoLock lock(mMutex);
+ MOZ_ASSERT(mStatus == Dead);
MOZ_ASSERT(mThread);
- mThread->SetWorker(WorkerThreadFriendKey{}, nullptr);
+ mThread->ClearEventQueueAndWorker(WorkerThreadFriendKey{});
mThread.swap(doomedThread);
}
@@ -6229,5 +6291,32 @@ WorkerPrivate::AutoPushEventLoopGlobal::~AutoPushEventLoopGlobal() {
data->mCurrentEventLoopGlobal = std::move(mOldEventLoopGlobal);
}
+// -----------------------------------------------------------------------------
+// WorkerParentRef
+WorkerParentRef::WorkerParentRef(RefPtr<WorkerPrivate>& aWorkerPrivate)
+ : mWorkerPrivate(aWorkerPrivate) {
+ LOGV(("WorkerParentRef::WorkerParentRef [%p] aWorkerPrivate %p", this,
+ aWorkerPrivate.get()));
+ MOZ_ASSERT(mWorkerPrivate);
+ mWorkerPrivate->AssertIsOnParentThread();
+}
+
+const RefPtr<WorkerPrivate>& WorkerParentRef::Private() const {
+ if (mWorkerPrivate) {
+ mWorkerPrivate->AssertIsOnParentThread();
+ }
+ return mWorkerPrivate;
+}
+
+void WorkerParentRef::DropWorkerPrivate() {
+ LOGV(("WorkerParentRef::DropWorkerPrivate [%p]", this));
+ if (mWorkerPrivate) {
+ mWorkerPrivate->AssertIsOnParentThread();
+ mWorkerPrivate = nullptr;
+ }
+}
+
+WorkerParentRef::~WorkerParentRef() = default;
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index ce754ba9f6..e9aa976bb3 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -85,6 +85,7 @@ class WorkerDebuggerGlobalScope;
class WorkerErrorReport;
class WorkerEventTarget;
class WorkerGlobalScope;
+class WorkerParentRef;
class WorkerRef;
class WorkerRunnable;
class WorkerDebuggeeRunnable;
@@ -590,7 +591,7 @@ class WorkerPrivate final
uint32_t aFlags = NS_DISPATCH_NORMAL);
nsresult DispatchDebuggeeToMainThread(
- already_AddRefed<WorkerDebuggeeRunnable> aRunnable,
+ already_AddRefed<WorkerRunnable> aRunnable,
uint32_t aFlags = NS_DISPATCH_NORMAL);
// Get an event target that will dispatch runnables as control runnables on
@@ -996,6 +997,8 @@ class WorkerPrivate final
void PropagateStorageAccessPermissionGranted();
+ void NotifyStorageKeyUsed();
+
void EnableDebugger();
void DisableDebugger();
@@ -1048,11 +1051,13 @@ class WorkerPrivate final
nsIEventTarget* aSyncLoopTarget = nullptr);
nsresult DispatchControlRunnable(
- already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable);
+ already_AddRefed<WorkerRunnable> aWorkerRunnable);
nsresult DispatchDebuggerRunnable(
already_AddRefed<WorkerRunnable> aDebuggerRunnable);
+ nsresult DispatchToParent(already_AddRefed<WorkerRunnable> aRunnable);
+
bool IsOnParentThread() const;
#ifdef DEBUG
@@ -1169,6 +1174,8 @@ class WorkerPrivate final
// Worker thread only.
void AdjustNonblockingCCBackgroundActorCount(int32_t aCount);
+ RefPtr<WorkerParentRef> GetWorkerParentRef() const;
+
private:
WorkerPrivate(
WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker,
@@ -1366,7 +1373,7 @@ class WorkerPrivate final
WorkerDebugger* mDebugger;
- workerinternals::Queue<WorkerControlRunnable*, 4> mControlQueue;
+ workerinternals::Queue<WorkerRunnable*, 4> mControlQueue;
workerinternals::Queue<WorkerRunnable*, 4> mDebuggerQueue;
// Touched on multiple threads, protected with mMutex. Only modified on the
@@ -1618,6 +1625,12 @@ class WorkerPrivate final
// The flag indicates if the worke is idle for events in the main event loop.
bool mWorkerLoopIsIdle MOZ_GUARDED_BY(mMutex){false};
+
+ // This flag is used to ensure we only call NotifyStorageKeyUsed once per
+ // global.
+ bool hasNotifiedStorageKeyUsed{false};
+
+ RefPtr<WorkerParentRef> mParentRef;
};
class AutoSyncLoopHolder {
@@ -1658,6 +1671,42 @@ class AutoSyncLoopHolder {
}
};
+/**
+ * WorkerParentRef is a RefPtr<WorkerPrivate> wrapper for cross-thread access.
+ * WorkerPrivate needs to be accessed in multiple threads; for example,
+ * in WorkerParentThreadRunnable, the associated WorkerPrivate must be accessed
+ * in the worker thread when creating/dispatching and in the parent thread when
+ * executing. Unfortunately, RefPtr can not be used on this WorkerPrivate since
+ * it is not a thread-safe ref-counted object.
+ *
+ * Instead of using a raw pointer and a complicated mechanism to ensure the
+ * WorkerPrivate's accessibility. WorkerParentRef is used to resolve the
+ * problem. WorkerParentRef has a RefPtr<WorkerPrivate> mWorkerPrivate
+ * initialized on the parent thread when WorkerPrivate::Constructor().
+ * WorkerParentRef is a thread-safe ref-counted object that can be copied at
+ * any thread by WorkerPrivate::GetWorkerParentRef() and propagated to other
+ * threads. In the target thread, call WorkerParentRef::Private() to get the
+ * reference for WorkerPrivate or get a nullptr if the Worker has shut down.
+ *
+ * Since currently usage cases, WorkerParentRef::Private() will assert to be on
+ * the parent thread.
+ */
+class WorkerParentRef final {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerParentRef);
+
+ explicit WorkerParentRef(RefPtr<WorkerPrivate>& aWorkerPrivate);
+
+ const RefPtr<WorkerPrivate>& Private() const;
+
+ void DropWorkerPrivate();
+
+ private:
+ ~WorkerParentRef();
+
+ RefPtr<WorkerPrivate> mWorkerPrivate;
+};
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/workers/WorkerRef.cpp b/dom/workers/WorkerRef.cpp
index 9ba9841041..7935a7c67f 100644
--- a/dom/workers/WorkerRef.cpp
+++ b/dom/workers/WorkerRef.cpp
@@ -20,8 +20,7 @@ class ReleaseRefControlRunnable final : public WorkerControlRunnable {
public:
ReleaseRefControlRunnable(WorkerPrivate* aWorkerPrivate,
already_AddRefed<StrongWorkerRef> aRef)
- : WorkerControlRunnable(aWorkerPrivate, "ReleaseRefControlRunnable",
- WorkerThread),
+ : WorkerControlRunnable("ReleaseRefControlRunnable"),
mRef(std::move(aRef)) {
MOZ_ASSERT(mRef);
}
@@ -211,7 +210,7 @@ ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
WorkerPrivate* workerPrivate = mRef->mWorkerPrivate;
RefPtr<ReleaseRefControlRunnable> r =
new ReleaseRefControlRunnable(workerPrivate, mRef.forget());
- r->Dispatch();
+ r->Dispatch(workerPrivate);
return;
}
}
diff --git a/dom/workers/WorkerRef.h b/dom/workers/WorkerRef.h
index e41ef07bfd..f1dc4deb1b 100644
--- a/dom/workers/WorkerRef.h
+++ b/dom/workers/WorkerRef.h
@@ -174,6 +174,8 @@ class WeakWorkerRef final : public WorkerRef {
WorkerPrivate* GetUnsafePrivate() const;
private:
+ friend class ThreadSafeWeakWorkerRef;
+
explicit WeakWorkerRef(WorkerPrivate* aWorkerPrivate);
~WeakWorkerRef();
diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp
index 14a3e5e3f9..05831c7cef 100644
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -54,129 +54,17 @@ const nsIID kWorkerRunnableIID = {
} // namespace
#ifdef DEBUG
-WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate, const char* aName,
- Target aTarget)
- : mWorkerPrivate(aWorkerPrivate),
- mTarget(aTarget),
+WorkerRunnable::WorkerRunnable(const char* aName)
# ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
- mName(aName),
-# endif
- mCallingCancelWithinRun(false) {
- LOG(("WorkerRunnable::WorkerRunnable [%p]", this));
- MOZ_ASSERT(aWorkerPrivate);
-}
-#endif
-
-bool WorkerRunnable::IsDebuggerRunnable() const { return false; }
-
-nsIGlobalObject* WorkerRunnable::DefaultGlobalObject() const {
- if (IsDebuggerRunnable()) {
- return mWorkerPrivate->DebuggerGlobalScope();
- } else {
- return mWorkerPrivate->GlobalScope();
- }
-}
-
-bool WorkerRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
-#ifdef DEBUG
- MOZ_ASSERT(aWorkerPrivate);
-
- switch (mTarget) {
- case ParentThread:
- aWorkerPrivate->AssertIsOnWorkerThread();
- break;
-
- case WorkerThread:
- aWorkerPrivate->AssertIsOnParentThread();
- break;
-
- default:
- MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
- }
-#endif
- return true;
-}
-
-bool WorkerRunnable::Dispatch() {
- bool ok = PreDispatch(mWorkerPrivate);
- if (ok) {
- ok = DispatchInternal();
- }
- PostDispatch(mWorkerPrivate, ok);
- return ok;
+ : mName(aName) {
+ LOG(("WorkerRunnable::WorkerRunnable [%p] (%s)", this, mName));
}
-
-bool WorkerRunnable::DispatchInternal() {
- LOG(("WorkerRunnable::DispatchInternal [%p]", this));
- RefPtr<WorkerRunnable> runnable(this);
-
- if (mTarget == WorkerThread) {
- if (IsDebuggerRunnable()) {
- return NS_SUCCEEDED(
- mWorkerPrivate->DispatchDebuggerRunnable(runnable.forget()));
- } else {
- return NS_SUCCEEDED(mWorkerPrivate->Dispatch(runnable.forget()));
- }
- }
-
- MOZ_ASSERT(mTarget == ParentThread);
-
- if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
- return NS_SUCCEEDED(parent->Dispatch(runnable.forget()));
- }
-
- if (IsDebuggeeRunnable()) {
- RefPtr<WorkerDebuggeeRunnable> debuggeeRunnable =
- runnable.forget().downcast<WorkerDebuggeeRunnable>();
- return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggeeToMainThread(
- debuggeeRunnable.forget(), NS_DISPATCH_NORMAL));
- }
-
- return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
-}
-
-void WorkerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
- bool aDispatchResult) {
- MOZ_ASSERT(aWorkerPrivate);
-
-#ifdef DEBUG
- switch (mTarget) {
- case ParentThread:
- aWorkerPrivate->AssertIsOnWorkerThread();
- break;
-
- case WorkerThread:
- aWorkerPrivate->AssertIsOnParentThread();
- break;
-
- default:
- MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
- }
-#endif
+# else
+{
+ LOG(("WorkerRunnable::WorkerRunnable [%p]", this));
}
-
-bool WorkerRunnable::PreRun(WorkerPrivate* aWorkerPrivate) { return true; }
-
-void WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
- bool aRunResult) {
- MOZ_ASSERT(aCx);
- MOZ_ASSERT(aWorkerPrivate);
-
-#ifdef DEBUG
- switch (mTarget) {
- case ParentThread:
- aWorkerPrivate->AssertIsOnParentThread();
- break;
-
- case WorkerThread:
- aWorkerPrivate->AssertIsOnWorkerThread();
- break;
-
- default:
- MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
- }
+# endif
#endif
-}
// static
WorkerRunnable* WorkerRunnable::FromRunnable(nsIRunnable* aRunnable) {
@@ -193,6 +81,20 @@ WorkerRunnable* WorkerRunnable::FromRunnable(nsIRunnable* aRunnable) {
return runnable;
}
+bool WorkerRunnable::Dispatch(WorkerPrivate* aWorkerPrivate) {
+ LOG(("WorkerRunnable::Dispatch [%p] aWorkerPrivate: %p", this,
+ aWorkerPrivate));
+ MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
+ bool ok = PreDispatch(aWorkerPrivate);
+ if (ok) {
+ ok = DispatchInternal(aWorkerPrivate);
+ }
+ PostDispatch(aWorkerPrivate, ok);
+ return ok;
+}
+
+NS_IMETHODIMP WorkerRunnable::Run() { return NS_OK; }
+
NS_IMPL_ADDREF(WorkerRunnable)
NS_IMPL_RELEASE(WorkerRunnable)
@@ -221,79 +123,83 @@ NS_INTERFACE_MAP_BEGIN(WorkerRunnable)
} else
NS_INTERFACE_MAP_END
-NS_IMETHODIMP
-WorkerRunnable::Run() {
- LOG(("WorkerRunnable::Run [%p]", this));
- bool targetIsWorkerThread = mTarget == WorkerThread;
+WorkerParentThreadRunnable::WorkerParentThreadRunnable(const char* aName)
+ : WorkerRunnable(aName) {
+ LOG(("WorkerParentThreadRunnable::WorkerParentThreadRunnable [%p]", this));
+}
+WorkerParentThreadRunnable::~WorkerParentThreadRunnable() = default;
+
+bool WorkerParentThreadRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
#ifdef DEBUG
- if (targetIsWorkerThread) {
- mWorkerPrivate->AssertIsOnWorkerThread();
- } else {
- MOZ_ASSERT(mTarget == ParentThread);
- mWorkerPrivate->AssertIsOnParentThread();
- }
+ MOZ_ASSERT(aWorkerPrivate);
+ aWorkerPrivate->AssertIsOnWorkerThread();
#endif
+ return true;
+}
- if (targetIsWorkerThread && !mCallingCancelWithinRun &&
- mWorkerPrivate->CancelBeforeWorkerScopeConstructed()) {
- mCallingCancelWithinRun = true;
- Cancel();
- mCallingCancelWithinRun = false;
+bool WorkerParentThreadRunnable::DispatchInternal(
+ WorkerPrivate* aWorkerPrivate) {
+ LOG(("WorkerParentThreadRunnable::DispatchInternal [%p]", this));
+ mWorkerParentRef = aWorkerPrivate->GetWorkerParentRef();
+ RefPtr<WorkerParentThreadRunnable> runnable(this);
+ return NS_SUCCEEDED(aWorkerPrivate->DispatchToParent(runnable.forget()));
+}
+
+void WorkerParentThreadRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
+ bool aDispatchResult) {
+#ifdef DEBUG
+ MOZ_ASSERT(aWorkerPrivate);
+ aWorkerPrivate->AssertIsOnWorkerThread();
+#endif
+}
+
+bool WorkerParentThreadRunnable::PreRun(WorkerPrivate* aWorkerPrivate) {
+ return true;
+}
+
+void WorkerParentThreadRunnable::PostRun(JSContext* aCx,
+ WorkerPrivate* aWorkerPrivate,
+ bool aRunResult) {
+ MOZ_ASSERT(aCx);
+#ifdef DEBUG
+ MOZ_ASSERT(aWorkerPrivate);
+ aWorkerPrivate->AssertIsOnParentThread();
+#endif
+}
+
+NS_IMETHODIMP
+WorkerParentThreadRunnable::Run() {
+ LOG(("WorkerParentThreadRunnable::Run [%p]", this));
+ RefPtr<WorkerPrivate> workerPrivate;
+ MOZ_ASSERT(mWorkerParentRef);
+ workerPrivate = mWorkerParentRef->Private();
+ if (!workerPrivate) {
+ NS_WARNING("Worker has already shut down!!!");
return NS_OK;
}
+#ifdef DEBUG
+ workerPrivate->AssertIsOnParentThread();
+#endif
- bool result = PreRun(mWorkerPrivate);
- if (!result) {
- MOZ_ASSERT(targetIsWorkerThread,
- "The only PreRun implementation that can fail is "
- "ScriptExecutorRunnable");
- mWorkerPrivate->AssertIsOnWorkerThread();
- MOZ_ASSERT(!JS_IsExceptionPending(mWorkerPrivate->GetJSContext()));
- // We can't enter a useful realm on the JSContext here; just pass it
- // in as-is.
- PostRun(mWorkerPrivate->GetJSContext(), mWorkerPrivate, false);
- return NS_ERROR_FAILURE;
- }
+ WorkerPrivate* parent = workerPrivate->GetParent();
+ bool isOnMainThread = !parent;
+ bool result = PreRun(workerPrivate);
+ MOZ_ASSERT(result);
+
+ LOG(("WorkerParentThreadRunnable::Run [%p] WorkerPrivate: %p, parent: %p",
+ this, workerPrivate.get(), parent));
// Track down the appropriate global, if any, to use for the AutoEntryScript.
nsCOMPtr<nsIGlobalObject> globalObject;
- bool isMainThread = !targetIsWorkerThread && !mWorkerPrivate->GetParent();
- MOZ_ASSERT(isMainThread == NS_IsMainThread());
- RefPtr<WorkerPrivate> kungFuDeathGrip;
- if (targetIsWorkerThread) {
- globalObject = mWorkerPrivate->GetCurrentEventLoopGlobal();
- if (!globalObject) {
- globalObject = DefaultGlobalObject();
- // Our worker thread may not be in a good state here if there is no
- // JSContext avaliable. The way this manifests itself is that
- // globalObject ends up null (though it's not clear to me how we can be
- // running runnables at all when DefaultGlobalObject() is returning
- // false!) and then when we try to init the AutoJSAPI either
- // CycleCollectedJSContext::Get() returns null or it has a null JSContext.
- // In any case, we used to have a check for
- // GetCurrentWorkerThreadJSContext() being non-null here and that seems to
- // avoid the problem, so let's keep doing that check even if we don't need
- // the JSContext here at all.
- if (NS_WARN_IF(!globalObject && !GetCurrentWorkerThreadJSContext())) {
- return NS_ERROR_FAILURE;
- }
- }
-
- // We may still not have a globalObject here: in the case of
- // CompileScriptRunnable, we don't actually create the global object until
- // we have the script data, which happens in a syncloop under
- // CompileScriptRunnable::WorkerRun, so we can't assert that it got created
- // in the PreRun call above.
+ if (isOnMainThread) {
+ MOZ_ASSERT(isOnMainThread == NS_IsMainThread());
+ globalObject = nsGlobalWindowInner::Cast(workerPrivate->GetWindow());
} else {
- kungFuDeathGrip = mWorkerPrivate;
- if (isMainThread) {
- globalObject = nsGlobalWindowInner::Cast(mWorkerPrivate->GetWindow());
- } else {
- globalObject = mWorkerPrivate->GetParent()->GlobalScope();
- }
+ MOZ_ASSERT(parent == GetCurrentThreadWorkerPrivate());
+ globalObject = parent->GlobalScope();
+ MOZ_DIAGNOSTIC_ASSERT(globalObject);
}
-
// We might run script as part of WorkerRun, so we need an AutoEntryScript.
// This is part of the HTML spec for workers at:
// http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
@@ -303,8 +209,9 @@ WorkerRunnable::Run() {
Maybe<mozilla::dom::AutoEntryScript> aes;
JSContext* cx;
AutoJSAPI* jsapi;
+
if (globalObject) {
- aes.emplace(globalObject, "Worker runnable", isMainThread);
+ aes.emplace(globalObject, "Worker parent thread runnable", isOnMainThread);
jsapi = aes.ptr();
cx = aes->cx();
} else {
@@ -315,7 +222,7 @@ WorkerRunnable::Run() {
}
// Note that we can't assert anything about
- // mWorkerPrivate->ParentEventTargetRef()->GetWrapper()
+ // workerPrivate->ParentEventTargetRef()->GetWrapper()
// existing, since it may in fact have been GCed (and we may be one of the
// runnables cleaning up the worker as a result).
@@ -325,17 +232,18 @@ WorkerRunnable::Run() {
// definitely have a globalObject. If it _is_ the main thread, globalObject
// can be null for workers started from JSMs or other non-window contexts,
// sadly.
- MOZ_ASSERT_IF(!targetIsWorkerThread && !isMainThread,
- mWorkerPrivate->IsDedicatedWorker() && globalObject);
+ MOZ_ASSERT_IF(!isOnMainThread,
+ workerPrivate->IsDedicatedWorker() && globalObject);
// If we're on the parent thread we might be in a null realm in the
// situation described above when globalObject is null. Make sure to enter
// the realm of the worker's reflector if there is one. There might
// not be one if we're just starting to compile the script for this worker.
Maybe<JSAutoRealm> ar;
- if (!targetIsWorkerThread && mWorkerPrivate->IsDedicatedWorker() &&
- mWorkerPrivate->ParentEventTargetRef()->GetWrapper()) {
- JSObject* wrapper = mWorkerPrivate->ParentEventTargetRef()->GetWrapper();
+ if (workerPrivate->IsDedicatedWorker() &&
+ workerPrivate->ParentEventTargetRef() &&
+ workerPrivate->ParentEventTargetRef()->GetWrapper()) {
+ JSObject* wrapper = workerPrivate->ParentEventTargetRef()->GetWrapper();
// If we're on the parent thread and have a reflector and a globalObject,
// then the realms of cx, globalObject, and the worker's reflector
@@ -359,12 +267,9 @@ WorkerRunnable::Run() {
}
MOZ_ASSERT(!jsapi->HasException());
- result = WorkerRun(cx, mWorkerPrivate);
+ result = WorkerRun(cx, workerPrivate);
jsapi->ReportException();
- // We can't even assert that this didn't create our global, since in the case
- // of CompileScriptRunnable it _does_.
-
// It would be nice to avoid passing a JSContext to PostRun, but in the case
// of ScriptExecutorRunnable we need to know the current compartment on the
// JSContext (the one we set up based on the global returned from PreRun) so
@@ -383,71 +288,226 @@ WorkerRunnable::Run() {
// this point; in the one case in which we could do that
// (CompileScriptRunnable) it actually doesn't matter which compartment we're
// in for PostRun.
- PostRun(cx, mWorkerPrivate, result);
+ PostRun(cx, workerPrivate, result);
MOZ_ASSERT(!jsapi->HasException());
return result ? NS_OK : NS_ERROR_FAILURE;
}
-nsresult WorkerRunnable::Cancel() {
- LOG(("WorkerRunnable::Cancel [%p]", this));
+nsresult WorkerParentThreadRunnable::Cancel() {
+ LOG(("WorkerParentThreadRunnable::Cancel [%p]", this));
return NS_OK;
}
-void WorkerDebuggerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
- bool aDispatchResult) {}
+WorkerParentControlRunnable::WorkerParentControlRunnable(const char* aName)
+ : WorkerParentThreadRunnable(aName) {}
-WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
- nsIEventTarget* aSyncLoopTarget,
- const char* aName)
- : WorkerRunnable(aWorkerPrivate, aName, WorkerThread),
- mSyncLoopTarget(aSyncLoopTarget) {
-#ifdef DEBUG
- if (mSyncLoopTarget) {
- mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
+WorkerParentControlRunnable::~WorkerParentControlRunnable() = default;
+
+nsresult WorkerParentControlRunnable::Cancel() {
+ LOG(("WorkerParentControlRunnable::Cancel [%p]", this));
+ if (NS_FAILED(Run())) {
+ NS_WARNING("WorkerParentControlRunnable::Run() failed.");
+ }
+ return NS_OK;
+}
+
+WorkerThreadRunnable::WorkerThreadRunnable(const char* aName)
+ : WorkerRunnable(aName), mCallingCancelWithinRun(false) {
+ LOG(("WorkerThreadRunnable::WorkerThreadRunnable [%p]", this));
+}
+
+nsIGlobalObject* WorkerThreadRunnable::DefaultGlobalObject(
+ WorkerPrivate* aWorkerPrivate) const {
+ MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
+ if (IsDebuggerRunnable()) {
+ return aWorkerPrivate->DebuggerGlobalScope();
}
+ return aWorkerPrivate->GlobalScope();
+}
+
+bool WorkerThreadRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
+ MOZ_ASSERT(aWorkerPrivate);
+#ifdef DEBUG
+ aWorkerPrivate->AssertIsOnParentThread();
#endif
+ return true;
}
-WorkerSyncRunnable::WorkerSyncRunnable(
- WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
- const char* aName)
- : WorkerRunnable(aWorkerPrivate, aName, WorkerThread),
- mSyncLoopTarget(std::move(aSyncLoopTarget)) {
+bool WorkerThreadRunnable::DispatchInternal(WorkerPrivate* aWorkerPrivate) {
+ LOG(("WorkerThreadRunnable::DispatchInternal [%p]", this));
+ RefPtr<WorkerThreadRunnable> runnable(this);
+ return NS_SUCCEEDED(aWorkerPrivate->Dispatch(runnable.forget()));
+}
+
+void WorkerThreadRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
+ bool aDispatchResult) {
+ MOZ_ASSERT(aWorkerPrivate);
#ifdef DEBUG
- if (mSyncLoopTarget) {
- mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
+ aWorkerPrivate->AssertIsOnParentThread();
+#endif
+}
+
+bool WorkerThreadRunnable::PreRun(WorkerPrivate* aWorkerPrivate) {
+ return true;
+}
+
+void WorkerThreadRunnable::PostRun(JSContext* aCx,
+ WorkerPrivate* aWorkerPrivate,
+ bool aRunResult) {
+ MOZ_ASSERT(aCx);
+ MOZ_ASSERT(aWorkerPrivate);
+
+#ifdef DEBUG
+ aWorkerPrivate->AssertIsOnWorkerThread();
+#endif
+}
+
+NS_IMETHODIMP
+WorkerThreadRunnable::Run() {
+ LOG(("WorkerThreadRunnable::Run [%p]", this));
+ WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+ if (!workerPrivate && mWorkerPrivateForPreStartCleaning) {
+ workerPrivate = mWorkerPrivateForPreStartCleaning;
+ mWorkerPrivateForPreStartCleaning = nullptr;
}
+ MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate);
+#ifdef DEBUG
+ workerPrivate->AssertIsOnWorkerThread();
#endif
+
+ if (!mCallingCancelWithinRun &&
+ workerPrivate->CancelBeforeWorkerScopeConstructed()) {
+ mCallingCancelWithinRun = true;
+ Cancel();
+ mCallingCancelWithinRun = false;
+ return NS_OK;
+ }
+
+ bool result = PreRun(workerPrivate);
+ if (!result) {
+ workerPrivate->AssertIsOnWorkerThread();
+ MOZ_ASSERT(!JS_IsExceptionPending(workerPrivate->GetJSContext()));
+ // We can't enter a useful realm on the JSContext here; just pass it
+ // in as-is.
+ PostRun(workerPrivate->GetJSContext(), workerPrivate, false);
+ return NS_ERROR_FAILURE;
+ }
+
+ // Track down the appropriate global, if any, to use for the AutoEntryScript.
+ nsCOMPtr<nsIGlobalObject> globalObject =
+ workerPrivate->GetCurrentEventLoopGlobal();
+ if (!globalObject) {
+ globalObject = DefaultGlobalObject(workerPrivate);
+ // Our worker thread may not be in a good state here if there is no
+ // JSContext avaliable. The way this manifests itself is that
+ // globalObject ends up null (though it's not clear to me how we can be
+ // running runnables at all when default globalObject(DebuggerGlobalScope
+ // for debugger runnable, and GlobalScope for normal runnables) is returning
+ // false!) and then when we try to init the AutoJSAPI either
+ // CycleCollectedJSContext::Get() returns null or it has a null JSContext.
+ // In any case, we used to have a check for
+ // GetCurrentWorkerThreadJSContext() being non-null here and that seems to
+ // avoid the problem, so let's keep doing that check even if we don't need
+ // the JSContext here at all.
+ if (NS_WARN_IF(!globalObject && !GetCurrentWorkerThreadJSContext())) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ // We might run script as part of WorkerRun, so we need an AutoEntryScript.
+ // This is part of the HTML spec for workers at:
+ // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
+ // If we don't have a globalObject we have to use an AutoJSAPI instead, but
+ // this is OK as we won't be running script in these circumstances.
+ Maybe<mozilla::dom::AutoJSAPI> maybeJSAPI;
+ Maybe<mozilla::dom::AutoEntryScript> aes;
+ JSContext* cx;
+ AutoJSAPI* jsapi;
+ if (globalObject) {
+ aes.emplace(globalObject, "Worker runnable", false);
+ jsapi = aes.ptr();
+ cx = aes->cx();
+ } else {
+ maybeJSAPI.emplace();
+ maybeJSAPI->Init();
+ jsapi = maybeJSAPI.ptr();
+ cx = jsapi->cx();
+ }
+
+ MOZ_ASSERT(!jsapi->HasException());
+ result = WorkerRun(cx, workerPrivate);
+ jsapi->ReportException();
+
+ // We can't even assert that this didn't create our global, since in the case
+ // of CompileScriptRunnable it _does_.
+
+ // It would be nice to avoid passing a JSContext to PostRun, but in the case
+ // of ScriptExecutorRunnable we need to know the current compartment on the
+ // JSContext (the one we set up based on the global returned from PreRun) so
+ // that we can sanely do exception reporting. In particular, we want to make
+ // sure that we do our JS_SetPendingException while still in that compartment,
+ // because otherwise we might end up trying to create a cross-compartment
+ // wrapper when we try to move the JS exception from our runnable's
+ // ErrorResult to the JSContext, and that's not desirable in this case.
+ //
+ // We _could_ skip passing a JSContext here and then in
+ // ScriptExecutorRunnable::PostRun end up grabbing it from the WorkerPrivate
+ // and looking at its current compartment. But that seems like slightly weird
+ // action-at-a-distance...
+ //
+ // In any case, we do NOT try to change the compartment on the JSContext at
+ // this point; in the one case in which we could do that
+ // (CompileScriptRunnable) it actually doesn't matter which compartment we're
+ // in for PostRun.
+ PostRun(cx, workerPrivate, result);
+ MOZ_ASSERT(!jsapi->HasException());
+
+ return result ? NS_OK : NS_ERROR_FAILURE;
}
+nsresult WorkerThreadRunnable::Cancel() {
+ LOG(("WorkerThreadRunnable::Cancel [%p]", this));
+ return NS_OK;
+}
+
+void WorkerDebuggerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
+ bool aDispatchResult) {}
+
+WorkerSyncRunnable::WorkerSyncRunnable(nsIEventTarget* aSyncLoopTarget,
+ const char* aName)
+ : WorkerThreadRunnable(aName), mSyncLoopTarget(aSyncLoopTarget) {}
+
+WorkerSyncRunnable::WorkerSyncRunnable(
+ nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, const char* aName)
+ : WorkerThreadRunnable(aName),
+ mSyncLoopTarget(std::move(aSyncLoopTarget)) {}
+
WorkerSyncRunnable::~WorkerSyncRunnable() = default;
-bool WorkerSyncRunnable::DispatchInternal() {
+bool WorkerSyncRunnable::DispatchInternal(WorkerPrivate* aWorkerPrivate) {
if (mSyncLoopTarget) {
+#ifdef DEBUG
+ aWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
+#endif
RefPtr<WorkerSyncRunnable> runnable(this);
return NS_SUCCEEDED(
mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
- return WorkerRunnable::DispatchInternal();
+ return WorkerThreadRunnable::DispatchInternal(aWorkerPrivate);
}
void MainThreadWorkerSyncRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) {}
MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable(
- WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
- nsresult aResult)
- : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget)),
- mResult(aResult) {
+ nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, nsresult aResult)
+ : WorkerSyncRunnable(std::move(aSyncLoopTarget)), mResult(aResult) {
LOG(("MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable [%p]",
this));
AssertIsOnMainThread();
-#ifdef DEBUG
- mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
-#endif
}
nsresult MainThreadStopSyncLoopRunnable::Cancel() {
@@ -470,9 +530,12 @@ bool MainThreadStopSyncLoopRunnable::WorkerRun(JSContext* aCx,
return true;
}
-bool MainThreadStopSyncLoopRunnable::DispatchInternal() {
+bool MainThreadStopSyncLoopRunnable::DispatchInternal(
+ WorkerPrivate* aWorkerPrivate) {
MOZ_ASSERT(mSyncLoopTarget);
-
+#ifdef DEBUG
+ aWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
+#endif
RefPtr<MainThreadStopSyncLoopRunnable> runnable(this);
return NS_SUCCEEDED(
mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
@@ -481,13 +544,8 @@ bool MainThreadStopSyncLoopRunnable::DispatchInternal() {
void MainThreadStopSyncLoopRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) {}
-#ifdef DEBUG
-WorkerControlRunnable::WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
- const char* aName, Target aTarget)
- : WorkerRunnable(aWorkerPrivate, aName, aTarget) {
- MOZ_ASSERT(aWorkerPrivate);
-}
-#endif
+WorkerControlRunnable::WorkerControlRunnable(const char* aName)
+ : WorkerThreadRunnable(aName) {}
nsresult WorkerControlRunnable::Cancel() {
LOG(("WorkerControlRunnable::Cancel [%p]", this));
@@ -498,21 +556,6 @@ nsresult WorkerControlRunnable::Cancel() {
return NS_OK;
}
-bool WorkerControlRunnable::DispatchInternal() {
- RefPtr<WorkerControlRunnable> runnable(this);
-
- if (mTarget == WorkerThread) {
- return NS_SUCCEEDED(
- mWorkerPrivate->DispatchControlRunnable(runnable.forget()));
- }
-
- if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
- return NS_SUCCEEDED(parent->DispatchControlRunnable(runnable.forget()));
- }
-
- return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
-}
-
WorkerMainThreadRunnable::WorkerMainThreadRunnable(
WorkerPrivate* aWorkerPrivate, const nsACString& aTelemetryKey)
: mozilla::Runnable("dom::WorkerMainThreadRunnable"),
@@ -570,11 +613,10 @@ WorkerMainThreadRunnable::Run() {
bool runResult = MainThreadRun();
RefPtr<MainThreadStopSyncLoopRunnable> response =
- new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
- std::move(mSyncLoopTarget),
+ new MainThreadStopSyncLoopRunnable(std::move(mSyncLoopTarget),
runResult ? NS_OK : NS_ERROR_FAILURE);
- MOZ_ALWAYS_TRUE(response->Dispatch());
+ MOZ_ALWAYS_TRUE(response->Dispatch(mWorkerPrivate));
return NS_OK;
}
@@ -633,15 +675,15 @@ void WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() {
RefPtr<WorkerProxyToMainThreadRunnable> mRunnable;
public:
- ReleaseRunnable(WorkerPrivate* aWorkerPrivate,
- WorkerProxyToMainThreadRunnable* aRunnable)
- : MainThreadWorkerControlRunnable(aWorkerPrivate),
+ explicit ReleaseRunnable(WorkerProxyToMainThreadRunnable* aRunnable)
+ : MainThreadWorkerControlRunnable("ReleaseRunnable"),
mRunnable(aRunnable) {
MOZ_ASSERT(aRunnable);
}
virtual nsresult Cancel() override {
- Unused << WorkerRun(nullptr, mWorkerPrivate);
+ MOZ_ASSERT(GetCurrentThreadWorkerPrivate());
+ Unused << WorkerRun(nullptr, GetCurrentThreadWorkerPrivate());
return NS_OK;
}
@@ -665,25 +707,10 @@ void WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() {
~ReleaseRunnable() = default;
};
- RefPtr<WorkerControlRunnable> runnable =
- new ReleaseRunnable(mWorkerRef->Private(), this);
- Unused << NS_WARN_IF(!runnable->Dispatch());
+ RefPtr<WorkerControlRunnable> runnable = new ReleaseRunnable(this);
+ Unused << NS_WARN_IF(!runnable->Dispatch(mWorkerRef->Private()));
}
void WorkerProxyToMainThreadRunnable::ReleaseWorker() { mWorkerRef = nullptr; }
-bool WorkerDebuggeeRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
- if (mTarget == ParentThread) {
- RefPtr<StrongWorkerRef> strongRef = StrongWorkerRef::Create(
- aWorkerPrivate, "WorkerDebuggeeRunnable::mSender");
- if (!strongRef) {
- return false;
- }
-
- mSender = new ThreadSafeWorkerRef(strongRef);
- }
-
- return WorkerRunnable::PreDispatch(aWorkerPrivate);
-}
-
} // namespace mozilla::dom
diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h
index d133f11ea2..d404e12d8d 100644
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -12,8 +12,11 @@
#include "MainThreadUtils.h"
#include "mozilla/Atomics.h"
#include "mozilla/RefPtr.h"
+#include "mozilla/ThreadSafeWeakPtr.h"
+#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/dom/WorkerStatus.h"
+#include "mozilla/dom/quota/CheckedUnsafePtr.h"
#include "nsCOMPtr.h"
#include "nsIRunnable.h"
#include "nsISupports.h"
@@ -31,53 +34,30 @@ class ErrorResult;
namespace dom {
-class WorkerPrivate;
+class Worker;
-// Use this runnable to communicate from the worker to its parent or vice-versa.
class WorkerRunnable : public nsIRunnable
#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
,
public nsINamed
#endif
{
- public:
- enum Target {
- // Target the main thread for top-level workers, otherwise target the
- // WorkerThread of the worker's parent.
- ParentThread,
-
- // Target the thread where the worker event loop runs.
- WorkerThread,
- };
-
protected:
- // The WorkerPrivate that this runnable is associated with.
- WorkerPrivate* mWorkerPrivate;
-
- // See above.
- Target mTarget;
-
#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
const char* mName = nullptr;
#endif
- private:
- // Whether or not Cancel() is currently being called from inside the Run()
- // method. Avoids infinite recursion when a subclass calls Run() from inside
- // Cancel(). Only checked and modified on the target thread.
- bool mCallingCancelWithinRun;
-
public:
NS_DECL_THREADSAFE_ISUPPORTS
#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
NS_DECL_NSINAMED
#endif
- virtual nsresult Cancel();
+ virtual nsresult Cancel() = 0;
// The return value is true if and only if both PreDispatch and
// DispatchInternal return true.
- bool Dispatch();
+ virtual bool Dispatch(WorkerPrivate* aWorkerPrivate);
// True if this runnable is handled by running JavaScript in some global that
// could possibly be a debuggee, and thus needs to be deferred when the target
@@ -90,41 +70,43 @@ class WorkerRunnable : public nsIRunnable
// support debugging the debugger server at the moment.
virtual bool IsDebuggeeRunnable() const { return false; }
+ // True if this runnable needs to be dispatched to
+ // WorkerPrivate::mControlEventTareget.
+ virtual bool IsControlRunnable() const { return false; }
+
+ // True if this runnable should be dispatched to the debugger queue,
+ // and false otherwise.
+ virtual bool IsDebuggerRunnable() const { return false; }
+
static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable);
protected:
- WorkerRunnable(WorkerPrivate* aWorkerPrivate,
- const char* aName = "WorkerRunnable",
- Target aTarget = WorkerThread)
+ explicit WorkerRunnable(const char* aName = "WorkerRunnable")
#ifdef DEBUG
;
#else
- : mWorkerPrivate(aWorkerPrivate),
- mTarget(aTarget),
# ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
- mName(aName),
+ : mName(aName)
# endif
- mCallingCancelWithinRun(false) {
+ {
}
#endif
// This class is reference counted.
virtual ~WorkerRunnable() = default;
- // Returns true if this runnable should be dispatched to the debugger queue,
- // and false otherwise.
- virtual bool IsDebuggerRunnable() const;
-
- nsIGlobalObject* DefaultGlobalObject() const;
+ // Calling Run() directly is not supported. Just call Dispatch() and
+ // WorkerRun() will be called on the correct thread automatically.
+ NS_DECL_NSIRUNNABLE
// By default asserts that Dispatch() is being called on the right thread
- // (ParentThread if |mTarget| is WorkerThread).
- virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate);
+ virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) = 0;
// By default asserts that Dispatch() is being called on the right thread
- // (ParentThread if |mTarget| is WorkerThread).
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
- bool aDispatchResult);
+ bool aDispatchResult) = 0;
+
+ virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) = 0;
// May be implemented by subclasses if desired if they need to do some sort of
// setup before we try to set up our JSContext and compartment for real.
@@ -133,17 +115,19 @@ class WorkerRunnable : public nsIRunnable
//
// If false is returned, WorkerRun will not be called at all. PostRun will
// still be called, with false passed for aRunResult.
- virtual bool PreRun(WorkerPrivate* aWorkerPrivate);
+ virtual bool PreRun(WorkerPrivate* aWorkerPrivate) = 0;
// Must be implemented by subclasses. Called on the target thread. The return
// value will be passed to PostRun(). The JSContext passed in here comes from
- // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If
- // mTarget is ParentThread, it is in the compartment of
+ // an AutoJSAPI (or AutoEntryScript) that we set up on the stack.
+ //
+ // If the runnable is for parent thread, aCx is in the compartment of
// mWorkerPrivate's reflector (i.e. the worker object in the parent thread),
// unless that reflector is null, in which case it's in the compartment of the
// parent global (which is the compartment reflector would have been in), or
- // in the null compartment if there is no parent global. For other mTarget
- // values, we're running on the worker thread and aCx is in whatever
+ // in the null compartment if there is no parent global.
+ //
+ // For runnables on the worker thread, aCx is in whatever
// compartment GetCurrentWorkerThreadJSContext() was in when
// nsIRunnable::Run() got called. This is actually important for cases when a
// runnable spins a syncloop and wants everything that happens during the
@@ -166,21 +150,138 @@ class WorkerRunnable : public nsIRunnable
// exception on the JSContext and must not run script, because the incoming
// JSContext may be in the null compartment.
virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
- bool aRunResult);
+ bool aRunResult) = 0;
+};
+
+class WorkerParentThreadRunnable : public WorkerRunnable {
+ public:
+ NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentThreadRunnable,
+ WorkerRunnable)
+
+ virtual nsresult Cancel() override;
+
+ protected:
+ explicit WorkerParentThreadRunnable(
+ const char* aName = "WorkerParentThreadRunnable");
+
+ // This class is reference counted.
+ virtual ~WorkerParentThreadRunnable();
+
+ virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
+
+ virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
+ bool aDispatchResult) override;
+
+ virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override;
+
+ virtual bool WorkerRun(JSContext* aCx,
+ WorkerPrivate* aWorkerPrivate) override = 0;
+
+ virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+ bool aRunResult) override;
+
+ virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final;
+
+ // Calling Run() directly is not supported. Just call Dispatch() and
+ // WorkerRun() will be called on the correct thread automatically.
+ NS_DECL_NSIRUNNABLE
+
+ private:
+ RefPtr<WorkerParentRef> mWorkerParentRef;
+};
+
+class WorkerParentControlRunnable : public WorkerParentThreadRunnable {
+ friend class WorkerPrivate;
+
+ protected:
+ explicit WorkerParentControlRunnable(
+ const char* aName = "WorkerParentControlRunnable");
+
+ virtual ~WorkerParentControlRunnable();
+
+ nsresult Cancel() override;
+
+ public:
+ NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentControlRunnable,
+ WorkerParentThreadRunnable)
+
+ private:
+ bool IsControlRunnable() const override { return true; }
+
+ // Should only be called by WorkerPrivate::DoRunLoop.
+ using WorkerParentThreadRunnable::Cancel;
+};
+
+class WorkerParentDebuggeeRunnable : public WorkerParentThreadRunnable {
+ protected:
+ explicit WorkerParentDebuggeeRunnable(
+ const char* aName = "WorkerParentDebuggeeRunnable")
+ : WorkerParentThreadRunnable(aName) {}
+
+ private:
+ // This override is deliberately private: it doesn't make sense to call it if
+ // we know statically that we are a WorkerDebuggeeRunnable.
+ bool IsDebuggeeRunnable() const override { return true; }
+};
+
+class WorkerThreadRunnable : public WorkerRunnable {
+ friend class WorkerPrivate;
+
+ public:
+ NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerThreadRunnable, WorkerRunnable)
+
+ virtual nsresult Cancel() override;
+
+ protected:
+ explicit WorkerThreadRunnable(const char* aName = "WorkerThreadRunnable");
+
+ // This class is reference counted.
+ virtual ~WorkerThreadRunnable() = default;
+
+ nsIGlobalObject* DefaultGlobalObject(WorkerPrivate* aWorkerPrivate) const;
+
+ virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
+
+ virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
+ bool aDispatchResult) override;
+
+ virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override;
+
+ virtual bool WorkerRun(JSContext* aCx,
+ WorkerPrivate* aWorkerPrivate) override = 0;
+
+ virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+ bool aRunResult) override;
- virtual bool DispatchInternal();
+ virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override;
// Calling Run() directly is not supported. Just call Dispatch() and
// WorkerRun() will be called on the correct thread automatically.
NS_DECL_NSIRUNNABLE
+
+ // Whether or not Cancel() is currently being called from inside the Run()
+ // method. Avoids infinite recursion when a subclass calls Run() from inside
+ // Cancel(). Only checked and modified on the target thread.
+ bool mCallingCancelWithinRun;
+
+ // If dispatching a WorkerThreadRunnable before Worker initialization complete
+ // in worker thread, which are in WorkerPrivate::mPreStartRunnables, when
+ // GetCurrentThreadWorkerPrivate() might get an invalid WorkerPrivate for
+ // WorkerThreadRunnable::Run() because it is in Worker's shutdown.
+ //
+ // This is specific for cleanup these pre-start runnables if the shutdown
+ // starts before Worker executes its event loop.
+ // This member is only set when the runnable is dispatched to
+ // WorkerPrivate::mPreStartRunnables. Any other cases to use this
+ // WorkerPrivate is always wrong.
+ CheckedUnsafePtr<WorkerPrivate> mWorkerPrivateForPreStartCleaning;
};
// This runnable is used to send a message to a worker debugger.
-class WorkerDebuggerRunnable : public WorkerRunnable {
+class WorkerDebuggerRunnable : public WorkerThreadRunnable {
protected:
- explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate,
- const char* aName = "WorkerDebuggerRunnable")
- : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {}
+ explicit WorkerDebuggerRunnable(const char* aName = "WorkerDebuggerRunnable")
+ : WorkerThreadRunnable(aName) {}
virtual ~WorkerDebuggerRunnable() = default;
@@ -198,23 +299,21 @@ class WorkerDebuggerRunnable : public WorkerRunnable {
};
// This runnable is used to send a message directly to a worker's sync loop.
-class WorkerSyncRunnable : public WorkerRunnable {
+class WorkerSyncRunnable : public WorkerThreadRunnable {
protected:
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
// Passing null for aSyncLoopTarget is allowed and will result in the behavior
- // of a normal WorkerRunnable.
- WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
- nsIEventTarget* aSyncLoopTarget,
- const char* aName = "WorkerSyncRunnable");
+ // of a normal WorkerThreadRunnable.
+ explicit WorkerSyncRunnable(nsIEventTarget* aSyncLoopTarget,
+ const char* aName = "WorkerSyncRunnable");
- WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
- nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
- const char* aName = "WorkerSyncRunnable");
+ explicit WorkerSyncRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
+ const char* aName = "WorkerSyncRunnable");
virtual ~WorkerSyncRunnable();
- virtual bool DispatchInternal() override;
+ virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override;
};
// This runnable is identical to WorkerSyncRunnable except it is meant to be
@@ -223,18 +322,18 @@ class WorkerSyncRunnable : public WorkerRunnable {
class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
protected:
// Passing null for aSyncLoopTarget is allowed and will result in the behavior
- // of a normal WorkerRunnable.
- MainThreadWorkerSyncRunnable(
- WorkerPrivate* aWorkerPrivate, nsIEventTarget* aSyncLoopTarget,
+ // of a normal WorkerThreadRunnable.
+ explicit MainThreadWorkerSyncRunnable(
+ nsIEventTarget* aSyncLoopTarget,
const char* aName = "MainThreadWorkerSyncRunnable")
- : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget, aName) {
+ : WorkerSyncRunnable(aSyncLoopTarget, aName) {
AssertIsOnMainThread();
}
- MainThreadWorkerSyncRunnable(
- WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
+ explicit MainThreadWorkerSyncRunnable(
+ nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
const char* aName = "MainThreadWorkerSyncRunnable")
- : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget), aName) {
+ : WorkerSyncRunnable(std::move(aSyncLoopTarget), aName) {
AssertIsOnMainThread();
}
@@ -254,42 +353,34 @@ class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
// potentially running before previously queued runnables and perhaps even with
// other JS code executing on the stack. These runnables must not alter the
// state of the JS runtime and should only twiddle state values.
-class WorkerControlRunnable : public WorkerRunnable {
+class WorkerControlRunnable : public WorkerThreadRunnable {
friend class WorkerPrivate;
protected:
- WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
- const char* aName = "WorkerControlRunnable",
- Target aTarget = WorkerThread)
-#ifdef DEBUG
- ;
-#else
- : WorkerRunnable(aWorkerPrivate, aName, aTarget) {
- }
-#endif
+ explicit WorkerControlRunnable(const char* aName = "WorkerControlRunnable");
virtual ~WorkerControlRunnable() = default;
nsresult Cancel() override;
public:
- NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, WorkerRunnable)
+ NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable,
+ WorkerThreadRunnable)
private:
- virtual bool DispatchInternal() override;
+ bool IsControlRunnable() const override { return true; }
// Should only be called by WorkerPrivate::DoRunLoop.
- using WorkerRunnable::Cancel;
+ using WorkerThreadRunnable::Cancel;
};
-// A convenience class for WorkerRunnables that are originated on the main
+// A convenience class for WorkerThreadRunnables that are originated on the main
// thread.
-class MainThreadWorkerRunnable : public WorkerRunnable {
+class MainThreadWorkerRunnable : public WorkerThreadRunnable {
protected:
explicit MainThreadWorkerRunnable(
- WorkerPrivate* aWorkerPrivate,
const char* aName = "MainThreadWorkerRunnable")
- : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {
+ : WorkerThreadRunnable(aName) {
AssertIsOnMainThread();
}
@@ -311,9 +402,8 @@ class MainThreadWorkerRunnable : public WorkerRunnable {
class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
protected:
explicit MainThreadWorkerControlRunnable(
- WorkerPrivate* aWorkerPrivate,
const char* aName = "MainThreadWorkerControlRunnable")
- : WorkerControlRunnable(aWorkerPrivate, aName, WorkerThread) {}
+ : WorkerControlRunnable(aName) {}
virtual ~MainThreadWorkerControlRunnable() = default;
@@ -328,17 +418,16 @@ class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
}
};
-// A WorkerRunnable that should be dispatched from the worker to itself for
-// async tasks.
+// A WorkerThreadRunnable that should be dispatched from the worker to itself
+// for async tasks.
//
// Async tasks will almost always want to use this since
// a WorkerSameThreadRunnable keeps the Worker from being GCed.
-class WorkerSameThreadRunnable : public WorkerRunnable {
+class WorkerSameThreadRunnable : public WorkerThreadRunnable {
protected:
explicit WorkerSameThreadRunnable(
- WorkerPrivate* aWorkerPrivate,
const char* aName = "WorkerSameThreadRunnable")
- : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {}
+ : WorkerThreadRunnable(aName) {}
virtual ~WorkerSameThreadRunnable() = default;
@@ -347,7 +436,7 @@ class WorkerSameThreadRunnable : public WorkerRunnable {
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) override;
- // We just delegate PostRun to WorkerRunnable, since it does exactly
+ // We just delegate PostRun to WorkerThreadRunnable, since it does exactly
// what we want.
};
@@ -424,8 +513,7 @@ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
public:
// Passing null for aSyncLoopTarget is not allowed.
- MainThreadStopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
- nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
+ MainThreadStopSyncLoopRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
nsresult aResult);
// By default StopSyncLoopRunnables cannot be canceled since they could leave
@@ -447,7 +535,7 @@ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
virtual bool WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) override;
- bool DispatchInternal() final;
+ bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final;
};
// Runnables handled by content JavaScript (MessageEventRunnable, JavaScript
@@ -470,31 +558,15 @@ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
// from a top-level frozen worker to its parent window must not be delivered
// either, even as the main thread event loop continues to spin. Thus, freezing
// a top-level worker also pauses mMainThreadDebuggeeEventTarget.
-class WorkerDebuggeeRunnable : public WorkerRunnable {
+class WorkerDebuggeeRunnable : public WorkerThreadRunnable {
protected:
- WorkerDebuggeeRunnable(WorkerPrivate* aWorkerPrivate,
- const char* aName = "WorkerDebuggeeRunnable",
- Target aTarget = ParentThread)
- : WorkerRunnable(aWorkerPrivate, aName, aTarget) {}
-
- bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
+ explicit WorkerDebuggeeRunnable(const char* aName = "WorkerDebuggeeRunnable")
+ : WorkerThreadRunnable(aName) {}
private:
// This override is deliberately private: it doesn't make sense to call it if
// we know statically that we are a WorkerDebuggeeRunnable.
bool IsDebuggeeRunnable() const override { return true; }
-
- // Runnables sent upwards, to the content window or parent worker, must keep
- // their sender alive until they are delivered: they check back with the
- // sender in case it has been terminated after having dispatched the runnable
- // (in which case it should not be acted upon); and runnables sent to content
- // wait until delivery to determine the target window, since
- // WorkerPrivate::GetWindow may only be used on the main thread.
- //
- // Runnables sent downwards, from content to a worker or from a worker to a
- // child, keep the sender alive because they are WorkerThread
- // runnables, and so leave this null.
- RefPtr<ThreadSafeWorkerRef> mSender;
};
} // namespace dom
diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp
index 2121a99cb3..cbb61c7055 100644
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -468,6 +468,7 @@ already_AddRefed<CacheStorage> WorkerGlobalScope::GetCaches(ErrorResult& aRv) {
if (!mCacheStorage) {
mCacheStorage = CacheStorage::CreateOnWorker(cache::DEFAULT_NAMESPACE, this,
mWorkerPrivate, aRv);
+ mWorkerPrivate->NotifyStorageKeyUsed();
}
RefPtr<CacheStorage> ref = mCacheStorage;
@@ -735,25 +736,28 @@ already_AddRefed<IDBFactory> WorkerGlobalScope::GetIndexedDB(
if (!indexedDB) {
StorageAccess access = mWorkerPrivate->StorageAccess();
+ bool allowed = true;
if (access == StorageAccess::eDeny) {
NS_WARNING("IndexedDB is not allowed in this worker!");
- aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
- return nullptr;
+ allowed = false;
}
if (ShouldPartitionStorage(access) &&
!StoragePartitioningEnabled(access,
mWorkerPrivate->CookieJarSettings())) {
NS_WARNING("IndexedDB is not allowed in this worker!");
- aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
- return nullptr;
+ allowed = false;
}
- const PrincipalInfo& principalInfo =
- mWorkerPrivate->GetEffectiveStoragePrincipalInfo();
+ auto windowID = mWorkerPrivate->WindowID();
+
+ auto principalInfoPtr =
+ allowed ? MakeUnique<PrincipalInfo>(
+ mWorkerPrivate->GetEffectiveStoragePrincipalInfo())
+ : nullptr;
+ auto res = IDBFactory::CreateForWorker(this, std::move(principalInfoPtr),
+ windowID);
- auto res = IDBFactory::CreateForWorker(this, principalInfo,
- mWorkerPrivate->WindowID());
if (NS_WARN_IF(res.isErr())) {
aErrorResult = res.unwrapErr();
return nullptr;
@@ -763,6 +767,8 @@ already_AddRefed<IDBFactory> WorkerGlobalScope::GetIndexedDB(
mIndexedDB = indexedDB;
}
+ mWorkerPrivate->NotifyStorageKeyUsed();
+
return indexedDB.forget();
}
diff --git a/dom/workers/WorkerThread.cpp b/dom/workers/WorkerThread.cpp
index 14d944e4d3..2b051c0440 100644
--- a/dom/workers/WorkerThread.cpp
+++ b/dom/workers/WorkerThread.cpp
@@ -117,50 +117,54 @@ SafeRefPtr<WorkerThread> WorkerThread::Create(
void WorkerThread::SetWorker(const WorkerThreadFriendKey& /* aKey */,
WorkerPrivate* aWorkerPrivate) {
MOZ_ASSERT(PR_GetCurrentThread() == mThread);
+ MOZ_ASSERT(aWorkerPrivate);
- if (aWorkerPrivate) {
- {
- MutexAutoLock lock(mLock);
+ {
+ MutexAutoLock lock(mLock);
- MOZ_ASSERT(!mWorkerPrivate);
- MOZ_ASSERT(mAcceptingNonWorkerRunnables);
+ MOZ_ASSERT(!mWorkerPrivate);
+ MOZ_ASSERT(mAcceptingNonWorkerRunnables);
- mWorkerPrivate = aWorkerPrivate;
+ mWorkerPrivate = aWorkerPrivate;
#ifdef DEBUG
- mAcceptingNonWorkerRunnables = false;
+ mAcceptingNonWorkerRunnables = false;
#endif
- }
+ }
- mObserver = new Observer(aWorkerPrivate);
- MOZ_ALWAYS_SUCCEEDS(AddObserver(mObserver));
- } else {
- MOZ_ALWAYS_SUCCEEDS(RemoveObserver(mObserver));
- mObserver = nullptr;
+ mObserver = new Observer(aWorkerPrivate);
+ MOZ_ALWAYS_SUCCEEDS(AddObserver(mObserver));
+}
- {
- MutexAutoLock lock(mLock);
+void WorkerThread::ClearEventQueueAndWorker(
+ const WorkerThreadFriendKey& /* aKey */) {
+ MOZ_ASSERT(PR_GetCurrentThread() == mThread);
- MOZ_ASSERT(mWorkerPrivate);
- MOZ_ASSERT(!mAcceptingNonWorkerRunnables);
- // mOtherThreadsDispatchingViaEventTarget can still be non-zero here
- // because WorkerThread::Dispatch isn't atomic so a thread initiating
- // dispatch can have dispatched a runnable at this thread allowing us to
- // begin shutdown before that thread gets a chance to decrement
- // mOtherThreadsDispatchingViaEventTarget back to 0. So we need to wait
- // for that.
- while (mOtherThreadsDispatchingViaEventTarget) {
- mWorkerPrivateCondVar.Wait();
- }
- // Need to clean up the dispatched runnables if
- // mOtherThreadsDispatchingViaEventTarget was non-zero.
- if (NS_HasPendingEvents(nullptr)) {
- NS_ProcessPendingEvents(nullptr);
- }
+ MOZ_ALWAYS_SUCCEEDS(RemoveObserver(mObserver));
+ mObserver = nullptr;
+
+ {
+ MutexAutoLock lock(mLock);
+
+ MOZ_ASSERT(mWorkerPrivate);
+ MOZ_ASSERT(!mAcceptingNonWorkerRunnables);
+ // mOtherThreadsDispatchingViaEventTarget can still be non-zero here
+ // because WorkerThread::Dispatch isn't atomic so a thread initiating
+ // dispatch can have dispatched a runnable at this thread allowing us to
+ // begin shutdown before that thread gets a chance to decrement
+ // mOtherThreadsDispatchingViaEventTarget back to 0. So we need to wait
+ // for that.
+ while (mOtherThreadsDispatchingViaEventTarget) {
+ mWorkerPrivateCondVar.Wait();
+ }
+ // Need to clean up the dispatched runnables if
+ // mOtherThreadsDispatchingViaEventTarget was non-zero.
+ if (NS_HasPendingEvents(nullptr)) {
+ NS_ProcessPendingEvents(nullptr);
+ }
#ifdef DEBUG
- mAcceptingNonWorkerRunnables = true;
+ mAcceptingNonWorkerRunnables = true;
#endif
- mWorkerPrivate = nullptr;
- }
+ mWorkerPrivate = nullptr;
}
}
@@ -246,8 +250,13 @@ WorkerThread::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
WorkerPrivate* workerPrivate = nullptr;
if (onWorkerThread) {
+ // If the mWorkerPrivate has already disconnected by
+ // WorkerPrivate::ResetWorkerPrivateInWorkerThread(), there is no chance
+ // that to execute this runnable. Return NS_ERROR_UNEXPECTED here.
+ if (!mWorkerPrivate) {
+ return NS_ERROR_UNEXPECTED;
+ }
// No need to lock here because it is only modified on this thread.
- MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
workerPrivate = mWorkerPrivate;
@@ -266,13 +275,7 @@ WorkerThread::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
}
nsresult rv;
- if (runnable && onWorkerThread) {
- RefPtr<WorkerRunnable> workerRunnable =
- workerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
- rv = nsThread::Dispatch(workerRunnable.forget(), NS_DISPATCH_NORMAL);
- } else {
- rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
- }
+ rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (!onWorkerThread && workerPrivate) {
// We need to wake the worker thread if we're not already on the right
diff --git a/dom/workers/WorkerThread.h b/dom/workers/WorkerThread.h
index 06624f60c1..8da085b51b 100644
--- a/dom/workers/WorkerThread.h
+++ b/dom/workers/WorkerThread.h
@@ -25,9 +25,6 @@ namespace dom {
class WorkerRunnable;
class WorkerPrivate;
-template <class>
-class WorkerPrivateParent;
-
namespace workerinternals {
class RuntimeService;
}
@@ -38,7 +35,6 @@ class RuntimeService;
class WorkerThreadFriendKey {
friend class workerinternals::RuntimeService;
friend class WorkerPrivate;
- friend class WorkerPrivateParent<WorkerPrivate>;
WorkerThreadFriendKey();
~WorkerThreadFriendKey();
@@ -76,6 +72,13 @@ class WorkerThread final : public nsThread {
void SetWorker(const WorkerThreadFriendKey& aKey,
WorkerPrivate* aWorkerPrivate);
+ // This method is used to decouple the connection with the WorkerPrivate which
+ // is set in SetWorker(). And it also clears all pending runnables on this
+ // WorkerThread.
+ // After decoupling, WorkerThreadRunnable can not run on this WorkerThread
+ // anymore, since WorkerPrivate is invalid.
+ void ClearEventQueueAndWorker(const WorkerThreadFriendKey& aKey);
+
nsresult DispatchPrimaryRunnable(const WorkerThreadFriendKey& aKey,
already_AddRefed<nsIRunnable> aRunnable);
diff --git a/dom/workers/remoteworkers/RemoteWorkerChild.cpp b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
index bf63c1729c..9a4ca60287 100644
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -106,12 +106,12 @@ NS_IMPL_RELEASE(SharedWorkerInterfaceRequestor)
NS_IMPL_QUERY_INTERFACE(SharedWorkerInterfaceRequestor, nsIInterfaceRequestor)
// Normal runnable because AddPortIdentifier() is going to exec JS code.
-class MessagePortIdentifierRunnable final : public WorkerRunnable {
+class MessagePortIdentifierRunnable final : public WorkerThreadRunnable {
public:
MessagePortIdentifierRunnable(WorkerPrivate* aWorkerPrivate,
RemoteWorkerChild* aActor,
const MessagePortIdentifier& aPortIdentifier)
- : WorkerRunnable(aWorkerPrivate, "MessagePortIdentifierRunnable"),
+ : WorkerThreadRunnable("MessagePortIdentifierRunnable"),
mActor(aActor),
mPortIdentifier(aPortIdentifier) {}
@@ -933,7 +933,7 @@ class RemoteWorkerChild::SharedWorkerOp : public RemoteWorkerChild::Op {
new MessagePortIdentifierRunnable(
workerPrivate, aOwner,
mOp.get_RemoteWorkerPortIdentifierOp().portIdentifier());
- if (NS_WARN_IF(!r->Dispatch())) {
+ if (NS_WARN_IF(!r->Dispatch(workerPrivate))) {
aOwner->ErrorPropagationDispatch(NS_ERROR_FAILURE);
}
} else if (mOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp) {
diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js
index c53c0b2b0f..c3535fadba 100644
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -46,6 +46,7 @@ let wasmGlobalInterfaces = [
{ name: "Function", insecureContext: true, nightly: true },
{ name: "Exception", insecureContext: true },
{ name: "Tag", insecureContext: true },
+ { name: "JSTag", insecureContext: true, earlyBetaOrEarlier: true },
{ name: "compile", insecureContext: true },
{ name: "compileStreaming", insecureContext: true },
{ name: "instantiate", insecureContext: true },