Quellcode-Bibliothek WorkerRunnable.cpp
Sprache: C
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
NS_INTERFACE_MAP_BEGIN(WorkerRunnable)
NS_INTERFACE_MAP_ENTRY(nsIRunnable) #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
NS_INTERFACE_MAP_ENTRY(nsINamed) #endif
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable) // kWorkerRunnableIID is special in that it does not AddRef its result. if (aIID.Equals(kWorkerRunnableIID)) {
*aInstancePtr = this; return NS_OK;
} else
NS_INTERFACE_MAP_END
// Track down the appropriate global, if any, to use for the AutoEntryScript.
nsCOMPtr<nsIGlobalObject> globalObject; if (isOnMainThread) {
MOZ_ASSERT(isOnMainThread == NS_IsMainThread());
globalObject = nsGlobalWindowInner::Cast(workerPrivate->GetWindow());
} else {
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 // 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;
// Note that we can't assert anything about // 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).
// If we are on the parent thread and that thread is not the main thread, // then we must be a dedicated worker (because there are no // Shared/ServiceWorkers whose parent is itself a worker) and then we // 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(!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 (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 // should all match.
MOZ_ASSERT_IF(globalObject,
js::GetNonCCWObjectRealm(wrapper) == js::GetContextRealm(cx));
MOZ_ASSERT_IF(globalObject,
js::GetNonCCWObjectRealm(wrapper) ==
js::GetNonCCWObjectRealm(
globalObject->GetGlobalJSObjectPreserveColor()));
// If we're on the parent thread and have a reflector, then our // JSContext had better be either in the null realm (and hence // have no globalObject) or in the realm of our reflector.
MOZ_ASSERT(!js::GetContextRealm(cx) ||
js::GetNonCCWObjectRealm(wrapper) == js::GetContextRealm(cx), "Must either be in the null compartment or in our reflector " "compartment");
ar.emplace(cx, wrapper);
}
MOZ_ASSERT(!jsapi->HasException());
result = WorkerRun(cx, workerPrivate);
jsapi->ReportException();
// 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());
// The Worker initialization fails, there is no valid WorkerPrivate and // WorkerJSContext to run this WorkerThreadRunnable. if (mCleanPreStartDispatching) {
LOG(("Clean the pre-start dispatched WorkerThreadRunnable [%p]", this)); 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());
RefPtr<StrongWorkerRef> workerRef; if (aFailStatus < Canceling) { // Nothing but logging debugging messages in the WorkerRef's // shutdown callback. // Stopping syncLoop in the shutdown callback could cause memory leaks or // UAF when the main thread job completes.
workerRef =
StrongWorkerRef::Create(aWorkerPrivate, mName, [self = RefPtr{this}]() {
LOG(
("WorkerMainThreadRunnable::Dispatch [%p](%s) Worker starts to " "shutdown while underlying SyncLoop is still running",
self.get(), self->mName));
});
} else {
LOG(
("WorkerMainThreadRunnable::Dispatch [%p](%s) Creating a SyncLoop when" "the Worker is shutting down", this, mName));
workerRef = StrongWorkerRef::CreateForcibly(aWorkerPrivate, mName);
} if (!workerRef) { // WorkerRef creation can fail if the worker is not in a valid status.
aRv.ThrowInvalidStateError("The worker has already shut down"); return;
}
mWorkerRef = MakeRefPtr<ThreadSafeWorkerRef>(workerRef);
mSyncLoopTarget = syncLoop.GetSerialEventTarget(); if (!mSyncLoopTarget) { // SyncLoop creation can fail if the worker is shutting down.
aRv.ThrowInvalidStateError("The worker is shutting down"); return;
}
DebugOnly<nsresult> rv = aWorkerPrivate->DispatchToMainThread(this);
MOZ_ASSERT(
NS_SUCCEEDED(rv), "Should only fail after xpcom-shutdown-threads and we're gone by then");
bool success = NS_SUCCEEDED(syncLoop.Run());
// syncLoop is done, release WorkerRef to unblock shutdown.
mWorkerRef = nullptr;
// This shouldn't be necessary once we're better about making sure no workers // are created during shutdown in earlier phases. if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
}
bool runResult = MainThreadRun();
RefPtr<MainThreadStopSyncLoopRunnable> response = new MainThreadStopSyncLoopRunnable(std::move(mSyncLoopTarget),
runResult ? NS_OK : NS_ERROR_FAILURE);
void WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() { class ReleaseRunnable final : public MainThreadWorkerControlRunnable {
RefPtr<WorkerProxyToMainThreadRunnable> mRunnable;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.30Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.