fune/dom/workers/sharedworkers/SharedWorkerService.cpp
Nika Layzell 852d02ec16 Bug 1809753 - Part 3: Replace all callers of GetCurrentEventTarget with GetCurrentSerialEventTarget, r=mccr8,necko-reviewers,valentin
This only changes the behaviour when called with a TaskQueue or other type
using SerialEventTargetGuard on the stack. They are being switched over as the
existing GetCurrentEventTarget method is being removed, as it is somewhat
confusing, and poorly documented.

Callers which need to get the current thread even when on a threadpool or
behind a TaskQueue were switched to GetCurrentEventTarget in the previous part.

Differential Revision: https://phabricator.services.mozilla.com/D166607
2023-01-16 23:14:11 +00:00

260 lines
8.5 KiB
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/. */
#include "SharedWorkerService.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/dom/SharedWorkerManager.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/StaticMutex.h"
#include "nsIPrincipal.h"
#include "nsProxyRelease.h"
namespace mozilla {
using namespace ipc;
namespace dom {
namespace {
StaticMutex sSharedWorkerMutex;
StaticRefPtr<SharedWorkerService> sSharedWorkerService;
class GetOrCreateWorkerManagerRunnable final : public Runnable {
public:
GetOrCreateWorkerManagerRunnable(SharedWorkerService* aService,
SharedWorkerParent* aActor,
const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier)
: Runnable("GetOrCreateWorkerManagerRunnable"),
mBackgroundEventTarget(GetCurrentSerialEventTarget()),
mService(aService),
mActor(aActor),
mData(aData),
mWindowID(aWindowID),
mPortIdentifier(aPortIdentifier) {}
NS_IMETHOD
Run() {
mService->GetOrCreateWorkerManagerOnMainThread(
mBackgroundEventTarget, mActor, mData, mWindowID, mPortIdentifier);
return NS_OK;
}
private:
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
RefPtr<SharedWorkerService> mService;
RefPtr<SharedWorkerParent> mActor;
RemoteWorkerData mData;
uint64_t mWindowID;
UniqueMessagePortId mPortIdentifier;
};
class WorkerManagerCreatedRunnable final : public Runnable {
public:
WorkerManagerCreatedRunnable(
already_AddRefed<SharedWorkerManagerWrapper> aManagerWrapper,
SharedWorkerParent* aActor, const RemoteWorkerData& aData,
uint64_t aWindowID, UniqueMessagePortId& aPortIdentifier)
: Runnable("WorkerManagerCreatedRunnable"),
mManagerWrapper(aManagerWrapper),
mActor(aActor),
mData(aData),
mWindowID(aWindowID),
mPortIdentifier(std::move(aPortIdentifier)) {}
NS_IMETHOD
Run() {
AssertIsOnBackgroundThread();
if (NS_WARN_IF(!mManagerWrapper->Manager()->MaybeCreateRemoteWorker(
mData, mWindowID, mPortIdentifier, mActor->OtherPid()))) {
mActor->ErrorPropagation(NS_ERROR_FAILURE);
return NS_OK;
}
mManagerWrapper->Manager()->AddActor(mActor);
mActor->ManagerCreated(mManagerWrapper.forget());
return NS_OK;
}
private:
RefPtr<SharedWorkerManagerWrapper> mManagerWrapper;
RefPtr<SharedWorkerParent> mActor;
RemoteWorkerData mData;
uint64_t mWindowID;
UniqueMessagePortId mPortIdentifier;
};
class ErrorPropagationRunnable final : public Runnable {
public:
ErrorPropagationRunnable(SharedWorkerParent* aActor, nsresult aError)
: Runnable("ErrorPropagationRunnable"), mActor(aActor), mError(aError) {}
NS_IMETHOD
Run() {
AssertIsOnBackgroundThread();
mActor->ErrorPropagation(mError);
return NS_OK;
}
private:
RefPtr<SharedWorkerParent> mActor;
nsresult mError;
};
} // namespace
/* static */
already_AddRefed<SharedWorkerService> SharedWorkerService::GetOrCreate() {
AssertIsOnBackgroundThread();
StaticMutexAutoLock lock(sSharedWorkerMutex);
if (!sSharedWorkerService) {
sSharedWorkerService = new SharedWorkerService();
// ClearOnShutdown can only be called on main thread
nsresult rv = SchedulerGroup::Dispatch(
TaskCategory::Other,
NS_NewRunnableFunction("RegisterSharedWorkerServiceClearOnShutdown",
[]() {
StaticMutexAutoLock lock(sSharedWorkerMutex);
MOZ_ASSERT(sSharedWorkerService);
ClearOnShutdown(&sSharedWorkerService);
}));
Unused << NS_WARN_IF(NS_FAILED(rv));
}
RefPtr<SharedWorkerService> instance = sSharedWorkerService;
return instance.forget();
}
/* static */
SharedWorkerService* SharedWorkerService::Get() {
StaticMutexAutoLock lock(sSharedWorkerMutex);
MOZ_ASSERT(sSharedWorkerService);
return sSharedWorkerService;
}
void SharedWorkerService::GetOrCreateWorkerManager(
SharedWorkerParent* aActor, const RemoteWorkerData& aData,
uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier) {
AssertIsOnBackgroundThread();
// The real check happens on main-thread.
RefPtr<GetOrCreateWorkerManagerRunnable> r =
new GetOrCreateWorkerManagerRunnable(this, aActor, aData, aWindowID,
aPortIdentifier);
nsresult rv = SchedulerGroup::Dispatch(TaskCategory::Other, r.forget());
Unused << NS_WARN_IF(NS_FAILED(rv));
}
void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
const RemoteWorkerData& aData, uint64_t aWindowID,
UniqueMessagePortId& aPortIdentifier) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aBackgroundEventTarget);
MOZ_ASSERT(aActor);
auto partitionedPrincipalOrErr =
PrincipalInfoToPrincipal(aData.partitionedPrincipalInfo());
if (NS_WARN_IF(partitionedPrincipalOrErr.isErr())) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
partitionedPrincipalOrErr.unwrapErr());
return;
}
auto loadingPrincipalOrErr =
PrincipalInfoToPrincipal(aData.loadingPrincipalInfo());
if (NS_WARN_IF(loadingPrincipalOrErr.isErr())) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
loadingPrincipalOrErr.unwrapErr());
return;
}
RefPtr<SharedWorkerManagerHolder> managerHolder;
nsCOMPtr<nsIPrincipal> loadingPrincipal = loadingPrincipalOrErr.unwrap();
nsCOMPtr<nsIPrincipal> partitionedPrincipal =
partitionedPrincipalOrErr.unwrap();
nsCOMPtr<nsIPrincipal> effectiveStoragePrincipal = partitionedPrincipal;
if (aData.useRegularPrincipal()) {
effectiveStoragePrincipal = loadingPrincipal;
}
// Let's see if there is already a SharedWorker to share.
nsCOMPtr<nsIURI> resolvedScriptURL =
DeserializeURI(aData.resolvedScriptURL());
for (SharedWorkerManager* workerManager : mWorkerManagers) {
managerHolder = workerManager->MatchOnMainThread(
this, aData.domain(), resolvedScriptURL, aData.name(), loadingPrincipal,
BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef());
if (managerHolder) {
break;
}
}
// Let's create a new one.
if (!managerHolder) {
managerHolder = SharedWorkerManager::Create(
this, aBackgroundEventTarget, aData, loadingPrincipal,
BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef());
mWorkerManagers.AppendElement(managerHolder->Manager());
} else {
// We are attaching the actor to an existing one.
if (managerHolder->Manager()->IsSecureContext() !=
aData.isSecureContext()) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
NS_ERROR_DOM_SECURITY_ERR);
return;
}
}
RefPtr<SharedWorkerManagerWrapper> wrapper =
new SharedWorkerManagerWrapper(managerHolder.forget());
RefPtr<WorkerManagerCreatedRunnable> r = new WorkerManagerCreatedRunnable(
wrapper.forget(), aActor, aData, aWindowID, aPortIdentifier);
aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void SharedWorkerService::ErrorPropagationOnMainThread(
nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
nsresult aError) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aBackgroundEventTarget);
MOZ_ASSERT(aActor);
MOZ_ASSERT(NS_FAILED(aError));
RefPtr<ErrorPropagationRunnable> r =
new ErrorPropagationRunnable(aActor, aError);
aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void SharedWorkerService::RemoveWorkerManagerOnMainThread(
SharedWorkerManager* aManager) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aManager);
MOZ_ASSERT(mWorkerManagers.Contains(aManager));
mWorkerManagers.RemoveElement(aManager);
}
} // namespace dom
} // namespace mozilla