Bug 1792984 - Introduce aggressive cancellation r=asuth
Differential Revision: https://phabricator.services.mozilla.com/D158558
This commit is contained in:
@@ -371,6 +371,21 @@ class ScriptExecutorRunnable final : public MainThreadWorkerSyncRunnable {
|
||||
nsresult Cancel() override;
|
||||
};
|
||||
|
||||
class AbruptCancellationRunnable final : public MainThreadWorkerSyncRunnable {
|
||||
WorkerScriptLoader& mScriptLoader;
|
||||
|
||||
public:
|
||||
AbruptCancellationRunnable(WorkerScriptLoader& aScriptLoader,
|
||||
nsIEventTarget* aSyncLoopTarget);
|
||||
private:
|
||||
~AbruptCancellationRunnable() = default;
|
||||
|
||||
virtual bool WorkerRun(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename Unit>
|
||||
static bool EvaluateSourceBuffer(JSContext* aCx,
|
||||
const JS::CompileOptions& aOptions,
|
||||
@@ -402,7 +417,12 @@ WorkerScriptLoader::WorkerScriptLoader(
|
||||
|
||||
RefPtr<StrongWorkerRef> workerRef =
|
||||
StrongWorkerRef::Create(aWorkerPrivate, "ScriptLoader", [self]() {
|
||||
// This code runs if the workerPrivate is released without being
|
||||
// released by the ScriptLoader. In other words, something has caused
|
||||
// the process to close and we have no control over it. We cannot wait
|
||||
// for a safe cleanup. This usually impacts service workers.
|
||||
nsTArray<WorkerLoadContext*> scriptLoadList = self->GetLoadingList();
|
||||
// Dispatch to clear out any service worker promises that may be running
|
||||
NS_DispatchToMainThread(
|
||||
NewRunnableMethod<nsTArray<WorkerLoadContext*>&&>(
|
||||
"WorkerScriptLoader::CancelMainThreadWithBindingAborted", self,
|
||||
@@ -694,17 +714,8 @@ void WorkerScriptLoader::CancelMainThread(
|
||||
loadContext->mCachePromise->MaybeReject(NS_BINDING_ABORTED);
|
||||
loadContext->mCachePromise = nullptr;
|
||||
}
|
||||
// Both Service workers and other scripts may or may not have been started
|
||||
// at this point. Regardless of their status, call loadingFinished on them
|
||||
// with the cancel result. This must be done eagerly! Otherwise, the
|
||||
// worker private may not live long enough (for example if the browser is
|
||||
// shutting down).
|
||||
if (!loadContext->mLoadingFinished) {
|
||||
// Eagerly signal that we aborted to ensure proper cleanup.
|
||||
// DO NOT wait on LoadHandlers to complete!
|
||||
LoadingFinished(loadContext->mRequest, aCancelResult);
|
||||
}
|
||||
}
|
||||
DispatchAbruptShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -973,6 +984,31 @@ nsresult WorkerScriptLoader::FillCompileOptionsForRequest(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void WorkerScriptLoader::DispatchAbruptShutdown() {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
{
|
||||
// We may have already terminated the thread. In this case, bail.
|
||||
MutexAutoLock lock(CleanUpLock());
|
||||
if (CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<AbruptCancellationRunnable> runnable =
|
||||
new AbruptCancellationRunnable(*this, mSyncLoopTarget);
|
||||
if (!runnable->Dispatch()) {
|
||||
MOZ_ASSERT(false, "This should never fail!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerScriptLoader::AbruptShutdown() {
|
||||
mWorkerRef->Private()->AssertIsOnWorkerThread();
|
||||
mLoadedRequests.CancelRequestsAndClear();
|
||||
mLoadingRequests.CancelRequestsAndClear();
|
||||
ShutdownScriptLoader(true, false);
|
||||
}
|
||||
|
||||
bool WorkerScriptLoader::EvaluateScript(JSContext* aCx,
|
||||
ScriptLoadRequest* aRequest) {
|
||||
mWorkerRef->Private()->AssertIsOnWorkerThread();
|
||||
@@ -1075,6 +1111,10 @@ void WorkerScriptLoader::ShutdownScriptLoader(bool aResult, bool aMutedError) {
|
||||
{
|
||||
MutexAutoLock lock(CleanUpLock());
|
||||
|
||||
if (CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWorkerRef->Private()->AssertIsOnWorkerThread();
|
||||
mWorkerRef->Private()->StopSyncLoop(mSyncLoopTarget, aResult);
|
||||
|
||||
@@ -1124,6 +1164,25 @@ void WorkerScriptLoader::LogExceptionToConsole(JSContext* aCx,
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerScriptLoader, nsINamed)
|
||||
|
||||
AbruptCancellationRunnable::AbruptCancellationRunnable(
|
||||
WorkerScriptLoader& aScriptLoader, nsIEventTarget* aSyncLoopTarget)
|
||||
: MainThreadWorkerSyncRunnable(aScriptLoader.mWorkerRef->Private(),
|
||||
aSyncLoopTarget),
|
||||
mScriptLoader(aScriptLoader) {}
|
||||
|
||||
bool AbruptCancellationRunnable::WorkerRun(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate) {
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// We must be on the same worker as we started on.
|
||||
MOZ_ASSERT(
|
||||
mScriptLoader.mSyncLoopTarget == mSyncLoopTarget,
|
||||
"Unexpected SyncLoopTarget. Check if the sync loop was closed early");
|
||||
|
||||
mScriptLoader.AbruptShutdown();
|
||||
return true;
|
||||
}
|
||||
|
||||
ScriptExecutorRunnable::ScriptExecutorRunnable(
|
||||
WorkerScriptLoader& aScriptLoader, nsIEventTarget* aSyncLoopTarget,
|
||||
ScriptLoadRequest* aRequest)
|
||||
|
||||
Reference in New Issue
Block a user