Backed out 5 changesets (bug 1672493) for causing serviceworker related perma failures. CLOSED TREE

Backed out changeset a38e64bdda2c (bug 1672493)
Backed out changeset b4e568bfb9c7 (bug 1672493)
Backed out changeset 4f1ee5c1e441 (bug 1672493)
Backed out changeset e05276c441ef (bug 1672493)
Backed out changeset e80cf5cf2fe5 (bug 1672493)
This commit is contained in:
Sandor Molnar 2024-06-27 13:02:33 +03:00
parent 9d3ac00b50
commit 3f11cda5a4
30 changed files with 379 additions and 1010 deletions

View File

@ -17,7 +17,6 @@
#include "mozilla/dom/InternalResponse.h"
#include "mozilla/dom/RemoteWorkerControllerParent.h"
#include "mozilla/dom/RemoteWorkerParent.h"
#include "mozilla/dom/RemoteWorkerServiceParent.h"
#include "mozilla/ipc/BackgroundParent.h"
namespace mozilla {

View File

@ -22,9 +22,7 @@
#include "mozilla/dom/InternalResponse.h"
#include "mozilla/dom/PRemoteWorkerParent.h"
#include "mozilla/dom/PRemoteWorkerControllerParent.h"
#include "mozilla/dom/PRemoteWorkerServiceParent.h"
#include "mozilla/dom/FetchEventOpParent.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/RemoteLazyInputStreamStorage.h"

View File

@ -51,7 +51,6 @@
#include "mozilla/dom/PerformanceStorage.h"
#include "mozilla/dom/PushEventBinding.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/RemoteWorkerService.h"
#include "mozilla/dom/Request.h"
#include "mozilla/dom/Response.h"
@ -67,11 +66,6 @@
namespace mozilla::dom {
using remoteworker::Canceled;
using remoteworker::Killed;
using remoteworker::Pending;
using remoteworker::Running;
namespace {
class ExtendableEventKeepAliveHandler final
@ -286,6 +280,7 @@ class ServiceWorkerOp::ServiceWorkerOpRunnable final
WorkerPrivate* aWorkerPrivate)
: WorkerDebuggeeRunnable("ServiceWorkerOpRunnable"),
mOwner(std::move(aOwner)) {
AssertIsOnMainThread();
MOZ_ASSERT(mOwner);
MOZ_ASSERT(aWorkerPrivate);
}
@ -311,12 +306,6 @@ class ServiceWorkerOp::ServiceWorkerOpRunnable final
return rv;
}
// Silent PreDispatch and PostDispatch, since ServiceWorkerOpRunnable can be
// from the main thread or from the worker thread.
bool PreDispatch(WorkerPrivate* WorkerPrivate) override { return true; }
void PostDispatch(WorkerPrivate* WorkerPrivate,
bool aDispatchResult) override {}
nsresult Cancel() override {
MOZ_ASSERT(mOwner);
@ -333,7 +322,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(ServiceWorkerOp::ServiceWorkerOpRunnable,
WorkerThreadRunnable)
bool ServiceWorkerOp::MaybeStart(RemoteWorkerChild* aOwner,
RemoteWorkerState& aState) {
RemoteWorkerChild::State& aState) {
MOZ_ASSERT(!mStarted);
MOZ_ASSERT(aOwner);
MOZ_ASSERT(aOwner->GetActorEventTarget()->IsOnCurrentThread());
@ -351,13 +340,14 @@ bool ServiceWorkerOp::MaybeStart(RemoteWorkerChild* aOwner,
return false;
}
if (NS_WARN_IF(aState.is<Canceled>()) || NS_WARN_IF(aState.is<Killed>())) {
if (NS_WARN_IF(aState.is<RemoteWorkerChild::Canceled>()) ||
NS_WARN_IF(aState.is<RemoteWorkerChild::Killed>())) {
RejectAll(NS_ERROR_DOM_INVALID_STATE_ERR);
mStarted = true;
return true;
}
MOZ_ASSERT(aState.is<Running>() || IsTerminationOp());
MOZ_ASSERT(aState.is<RemoteWorkerChild::Running>() || IsTerminationOp());
RefPtr<ServiceWorkerOp> self = this;
@ -395,7 +385,6 @@ bool ServiceWorkerOp::MaybeStart(RemoteWorkerChild* aOwner,
}
void ServiceWorkerOp::StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) {
AssertIsOnMainThread();
MaybeReportServiceWorkerShutdownProgress(mArgs);
{
@ -423,49 +412,14 @@ void ServiceWorkerOp::StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) {
}
}
void ServiceWorkerOp::Start(RemoteWorkerNonLifeCycleOpControllerChild* aOwner,
RemoteWorkerState& aState) {
MOZ_ASSERT(!mStarted);
MOZ_ASSERT(aOwner);
if (NS_WARN_IF(!aOwner->CanSend())) {
RejectAll(NS_ERROR_DOM_ABORT_ERR);
mStarted = true;
return;
}
// NonLifeCycle related operations would never start at Pending state.
MOZ_ASSERT(!aState.is<Pending>());
if (NS_WARN_IF(aState.is<Canceled>()) || NS_WARN_IF(aState.is<Killed>())) {
RejectAll(NS_ERROR_DOM_INVALID_STATE_ERR);
mStarted = true;
return;
}
MOZ_ASSERT(aState.is<Running>());
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate);
RefPtr<WorkerThreadRunnable> workerRunnable = GetRunnable(workerPrivate);
if (NS_WARN_IF(!workerRunnable->Dispatch(workerPrivate))) {
RejectAll(NS_ERROR_FAILURE);
}
mStarted = true;
}
void ServiceWorkerOp::Cancel() { RejectAll(NS_ERROR_DOM_ABORT_ERR); }
ServiceWorkerOp::ServiceWorkerOp(
ServiceWorkerOpArgs&& aArgs,
std::function<void(const ServiceWorkerOpResult&)>&& aCallback)
: mArgs(std::move(aArgs)) {
// Can be on the Worker Launcher thread for Terminate operations or on the
// Worker thread for other operations
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
RefPtr<ServiceWorkerOpPromise> promise = mPromiseHolder.Ensure(__func__);
promise->Then(
@ -489,6 +443,7 @@ ServiceWorkerOp::~ServiceWorkerOp() {
bool ServiceWorkerOp::Started() const {
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
return mStarted;
}
@ -499,6 +454,7 @@ bool ServiceWorkerOp::IsTerminationOp() const {
RefPtr<WorkerThreadRunnable> ServiceWorkerOp::GetRunnable(
WorkerPrivate* aWorkerPrivate) {
AssertIsOnMainThread();
MOZ_ASSERT(aWorkerPrivate);
return new ServiceWorkerOpRunnable(this, aWorkerPrivate);
@ -560,27 +516,17 @@ class UpdateServiceWorkerStateOp final : public ServiceWorkerOp {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UpdateServiceWorkerStateOp, override);
private:
class UpdateStateOpRunnable final : public WorkerControlRunnable {
class UpdateStateOpRunnable final : public MainThreadWorkerControlRunnable {
public:
NS_DECL_ISUPPORTS_INHERITED
UpdateStateOpRunnable(RefPtr<UpdateServiceWorkerStateOp> aOwner,
WorkerPrivate* aWorkerPrivate)
: WorkerControlRunnable("UpdateStateOpRunnable"),
: MainThreadWorkerControlRunnable("UpdateStateOpRunnable"),
mOwner(std::move(aOwner)) {
AssertIsOnMainThread();
MOZ_ASSERT(mOwner);
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
}
virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
aWorkerPrivate->AssertIsOnWorkerThread();
return true;
}
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) override {
aWorkerPrivate->AssertIsOnWorkerThread();
}
private:
@ -615,8 +561,8 @@ class UpdateServiceWorkerStateOp final : public ServiceWorkerOp {
RefPtr<WorkerThreadRunnable> GetRunnable(
WorkerPrivate* aWorkerPrivate) override {
AssertIsOnMainThread();
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->IsOnWorkerThread();
MOZ_ASSERT(mArgs.type() ==
ServiceWorkerOpArgs::TServiceWorkerUpdateStateOpArgs);
@ -640,7 +586,7 @@ class UpdateServiceWorkerStateOp final : public ServiceWorkerOp {
};
NS_IMPL_ISUPPORTS_INHERITED0(UpdateServiceWorkerStateOp::UpdateStateOpRunnable,
WorkerControlRunnable)
MainThreadWorkerControlRunnable)
void ExtendableEventOp::FinishedWithResult(ExtendableEventResult aResult) {
MOZ_ASSERT(IsCurrentThreadRunningWorker());
@ -1927,8 +1873,8 @@ class ExtensionAPIEventOp final : public ServiceWorkerOp {
/* static */ already_AddRefed<ServiceWorkerOp> ServiceWorkerOp::Create(
ServiceWorkerOpArgs&& aArgs,
std::function<void(const ServiceWorkerOpResult&)>&& aCallback) {
// Can be on the Worker Launcher thread for Terminate operations or on the
// Worker thread for other operations.
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
RefPtr<ServiceWorkerOp> op;
switch (aArgs.type()) {

View File

@ -20,17 +20,14 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerOp.h"
#include "mozilla/dom/ServiceWorkerOpArgs.h"
#include "mozilla/dom/WorkerRunnable.h"
namespace mozilla::dom {
using remoteworker::RemoteWorkerState;
class FetchEventOpProxyChild;
class ServiceWorkerOp : public RemoteWorkerOp {
class ServiceWorkerOp : public RemoteWorkerChild::Op {
public:
// `aCallback` will be called when the operation completes or is canceled.
static already_AddRefed<ServiceWorkerOp> Create(
@ -50,13 +47,11 @@ class ServiceWorkerOp : public RemoteWorkerOp {
ServiceWorkerOp& operator=(ServiceWorkerOp&&) = default;
// Returns `true` if the operation has started and `false` otherwise.
bool MaybeStart(RemoteWorkerChild* aOwner, RemoteWorkerState& aState) final;
bool MaybeStart(RemoteWorkerChild* aOwner,
RemoteWorkerChild::State& aState) final;
void StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) final;
void Start(RemoteWorkerNonLifeCycleOpControllerChild* aOwner,
RemoteWorkerState& aState) final;
void Cancel() final;
protected:

View File

@ -50,7 +50,6 @@
#include "mozilla/dom/PromiseDebugging.h"
#include "mozilla/dom/ReferrerInfo.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/RemoteWorkerService.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/SimpleGlobalObject.h"
@ -2437,9 +2436,7 @@ WorkerPrivate::WorkerPrivate(
nsString&& aId, const nsID& aAgentClusterId,
const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy,
CancellationCallback&& aCancellationCallback,
TerminationCallback&& aTerminationCallback,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp)
TerminationCallback&& aTerminationCallback)
: mMutex("WorkerPrivate Mutex"),
mCondVar(mMutex, "WorkerPrivate CondVar"),
mParent(aParent),
@ -2458,7 +2455,6 @@ WorkerPrivate::WorkerPrivate(
this, WorkerEventTarget::Behavior::ControlOnly)),
mWorkerHybridEventTarget(
new WorkerEventTarget(this, WorkerEventTarget::Behavior::Hybrid)),
mChildEp(std::move(aChildEp)),
mParentStatus(Pending),
mStatus(Pending),
mCreationTimeStamp(TimeStamp::Now()),
@ -2676,9 +2672,7 @@ already_AddRefed<WorkerPrivate> WorkerPrivate::Constructor(
const nsACString& aServiceWorkerScope, WorkerLoadInfo* aLoadInfo,
ErrorResult& aRv, nsString aId,
CancellationCallback&& aCancellationCallback,
TerminationCallback&& aTerminationCallback,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp) {
TerminationCallback&& aTerminationCallback) {
WorkerPrivate* parent =
NS_IsMainThread() ? nullptr : GetCurrentThreadWorkerPrivate();
@ -2743,7 +2737,7 @@ already_AddRefed<WorkerPrivate> WorkerPrivate::Constructor(
parent, aScriptURL, aIsChromeWorker, aWorkerKind, aRequestCredentials,
aWorkerType, aWorkerName, aServiceWorkerScope, *aLoadInfo, std::move(aId),
idAndCoop.mId, idAndCoop.mCoop, std::move(aCancellationCallback),
std::move(aTerminationCallback), std::move(aChildEp));
std::move(aTerminationCallback));
// Gecko contexts always have an explicitly-set default locale (set by
// XPJSRuntime::Initialize for the main thread, set by
@ -3287,19 +3281,6 @@ void WorkerPrivate::DoRunLoop(JSContext* aCx) {
MOZ_ASSERT(mStatus == Pending);
mStatus = Running;
// Create IPC between the content process worker thread and the parent
// process background thread for non-life cycle related operations of
// SharedWorker/ServiceWorker
if (mChildEp.IsValid()) {
mRemoteWorkerNonLifeCycleOpController =
RemoteWorkerNonLifeCycleOpControllerChild::Create();
// RemoteWorkerNonLifeCycleOpControllerChild::Create() can fail when
// Worker enters "Canceling." But Worker just gets into "Running,"
// probably can replace the if statement with an assertion.
MOZ_ASSERT_DEBUG_OR_FUZZING(mRemoteWorkerNonLifeCycleOpController);
mChildEp.Bind(mRemoteWorkerNonLifeCycleOpController);
}
// Now, start to run the event loop, mPreStartRunnables can be cleared,
// since when get here, Worker initialization has done successfully.
mPreStartRunnables.Clear();
@ -5225,15 +5206,6 @@ bool WorkerPrivate::NotifyInternal(WorkerStatus aStatus) {
NotifyWorkerRefs(aStatus);
}
if (aStatus == Canceling && mRemoteWorkerNonLifeCycleOpController) {
mRemoteWorkerNonLifeCycleOpController->TransistionStateToCanceled();
}
if (aStatus == Killing && mRemoteWorkerNonLifeCycleOpController) {
mRemoteWorkerNonLifeCycleOpController->TransistionStateToKilled();
mRemoteWorkerNonLifeCycleOpController = nullptr;
}
// If the worker script never ran, or failed to compile, we don't need to do
// anything else.
WorkerGlobalScope* global = GlobalScope();

View File

@ -28,8 +28,6 @@
#include "mozilla/UseCounter.h"
#include "mozilla/dom/ClientSource.h"
#include "mozilla/dom/FlippedOnce.h"
#include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/dom/Timeout.h"
#include "mozilla/dom/quota/CheckedUnsafePtr.h"
#include "mozilla/dom/Worker.h"
@ -40,13 +38,11 @@
#include "mozilla/dom/workerinternals/JSSettings.h"
#include "mozilla/dom/workerinternals/Queue.h"
#include "mozilla/dom/JSExecutionManager.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "mozilla/StaticPrefs_extensions.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIContentSecurityPolicy.h"
#include "nsID.h"
#include "nsIEventTarget.h"
#include "nsILoadInfo.h"
#include "nsRFPService.h"
@ -64,7 +60,6 @@ class ThrottledEventQueue;
namespace dom {
class RemoteWorkerChild;
class RemoteWorkerNonLifeCycleOpControllerChild;
// If you change this, the corresponding list in nsIWorkerDebugger.idl needs
// to be updated too. And histograms enum for worker use counters uses the same
@ -236,10 +231,7 @@ class WorkerPrivate final
const nsACString& aServiceWorkerScope, WorkerLoadInfo* aLoadInfo,
ErrorResult& aRv, nsString aId = u""_ns,
CancellationCallback&& aCancellationCallback = {},
TerminationCallback&& aTerminationCallback = {},
mozilla::ipc::Endpoint<
PRemoteWorkerNonLifeCycleOpControllerChild>&& aChildEp =
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>());
TerminationCallback&& aTerminationCallback = {});
enum LoadGroupBehavior { InheritLoadGroup, OverrideLoadGroup };
@ -1204,9 +1196,7 @@ class WorkerPrivate final
nsString&& aId, const nsID& aAgentClusterId,
const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy,
CancellationCallback&& aCancellationCallback,
TerminationCallback&& aTerminationCallback,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp);
TerminationCallback&& aTerminationCallback);
~WorkerPrivate();
@ -1453,13 +1443,6 @@ class WorkerPrivate final
// ServiceWorker RemoteWorkers.
RefPtr<RemoteWorkerChild> mRemoteWorkerController;
// Only touched on the worker thread. Used for both SharedWorker and
// ServiceWorker RemoteWorkers.
RefPtr<RemoteWorkerNonLifeCycleOpControllerChild>
mRemoteWorkerNonLifeCycleOpController;
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild> mChildEp;
JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
TimeStamp mKillTime;
WorkerStatus mParentStatus MOZ_GUARDED_BY(mMutex);

View File

@ -5,13 +5,54 @@
include protocol PFetchEventOpProxy;
include protocol PRemoteWorkerService;
include DOMTypes;
include ServiceWorkerOpArgs;
include SharedWorkerOpArgs;
include RemoteWorkerTypes;
namespace mozilla {
namespace dom {
struct RemoteWorkerSuspendOp
{};
struct RemoteWorkerResumeOp
{};
struct RemoteWorkerFreezeOp
{};
struct RemoteWorkerThawOp
{};
struct RemoteWorkerTerminateOp
{};
struct RemoteWorkerPortIdentifierOp
{
MessagePortIdentifier portIdentifier;
};
struct RemoteWorkerAddWindowIDOp
{
uint64_t windowID;
};
struct RemoteWorkerRemoveWindowIDOp
{
uint64_t windowID;
};
union RemoteWorkerOp {
RemoteWorkerSuspendOp;
RemoteWorkerResumeOp;
RemoteWorkerFreezeOp;
RemoteWorkerThawOp;
RemoteWorkerTerminateOp;
RemoteWorkerPortIdentifierOp;
RemoteWorkerAddWindowIDOp;
RemoteWorkerRemoveWindowIDOp;
};
// This protocol is used to make a remote worker controllable from the parent
// process. The parent process will receive operations from the
// PRemoteWorkerController protocol.
@ -39,7 +80,7 @@ child:
async __delete__();
async ExecOp(SharedWorkerOpArgs aArgs);
async ExecOp(RemoteWorkerOp op);
async ExecServiceWorkerOp(ServiceWorkerOpArgs aArgs)
returns (ServiceWorkerOpResult aResult);

View File

@ -1,31 +0,0 @@
/* 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 RemoteWorkerTypes;
include ServiceWorkerOpArgs;
include SharedWorkerOpArgs;
namespace mozilla {
namespace dom{
[ChildProc=any]
protocol PRemoteWorkerNonLifeCycleOpController
{
parent:
async Terminated();
async Error(ErrorValue aValue);
child:
async ExecOp(SharedWorkerOpArgs aOpArgs);
async ExecServiceWorkerOp(ServiceWorkerOpArgs aOpArgs)
returns (ServiceWorkerOpResult aResult) ;
async Shutdown();
};
} // namespace dom
} // namespace mozilla

View File

@ -3,7 +3,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PRemoteWorker;
include protocol PRemoteWorkerNonLifeCycleOpController;
include ProtocolTypes;
include RemoteWorkerTypes;
@ -20,8 +19,7 @@ protocol PRemoteWorkerService
manages PRemoteWorker;
child:
async PRemoteWorker(RemoteWorkerData data,
Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild> childEp);
async PRemoteWorker(RemoteWorkerData data);
};
} // namespace dom

View File

@ -40,7 +40,6 @@
#include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
#include "mozilla/dom/ServiceWorkerShutdownState.h"
#include "mozilla/dom/ServiceWorkerUtils.h"
#include "mozilla/dom/SharedWorkerOp.h"
#include "mozilla/dom/workerinternals/ScriptLoader.h"
#include "mozilla/dom/WorkerError.h"
#include "mozilla/dom/WorkerPrivate.h"
@ -67,11 +66,6 @@ namespace dom {
using workerinternals::ChannelFromScriptURLMainThread;
using remoteworker::Canceled;
using remoteworker::Killed;
using remoteworker::Pending;
using remoteworker::Running;
namespace {
class SharedWorkerInterfaceRequestor final : public nsIInterfaceRequestor {
@ -111,6 +105,30 @@ NS_IMPL_ADDREF(SharedWorkerInterfaceRequestor)
NS_IMPL_RELEASE(SharedWorkerInterfaceRequestor)
NS_IMPL_QUERY_INTERFACE(SharedWorkerInterfaceRequestor, nsIInterfaceRequestor)
// Normal runnable because AddPortIdentifier() is going to exec JS code.
class MessagePortIdentifierRunnable final : public WorkerThreadRunnable {
public:
MessagePortIdentifierRunnable(WorkerPrivate* aWorkerPrivate,
RemoteWorkerChild* aActor,
const MessagePortIdentifier& aPortIdentifier)
: WorkerThreadRunnable("MessagePortIdentifierRunnable"),
mActor(aActor),
mPortIdentifier(aPortIdentifier) {}
private:
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
if (aWorkerPrivate->GlobalScope()->IsDying()) {
mPortIdentifier.ForceClose();
return true;
}
mActor->AddPortIdentifier(aCx, aWorkerPrivate, mPortIdentifier);
return true;
}
RefPtr<RemoteWorkerChild> mActor;
UniqueMessagePortId mPortIdentifier;
};
// This is used to propagate the CSP violation when loading the SharedWorker
// main-script and nothing else.
class RemoteWorkerCSPEventListener final : public nsICSPEventListener {
@ -118,7 +136,7 @@ class RemoteWorkerCSPEventListener final : public nsICSPEventListener {
NS_DECL_ISUPPORTS
explicit RemoteWorkerCSPEventListener(RemoteWorkerChild* aActor)
: mActor(aActor) {};
: mActor(aActor){};
NS_IMETHOD OnCSPViolationEvent(const nsAString& aJSON) override {
mActor->CSPViolationPropagationOnMainThread(aJSON);
@ -136,7 +154,7 @@ NS_IMPL_ISUPPORTS(RemoteWorkerCSPEventListener, nsICSPEventListener)
} // anonymous namespace
RemoteWorkerChild::RemoteWorkerChild(const RemoteWorkerData& aData)
: mState(VariantType<remoteworker::Pending>(), "RemoteWorkerState"),
: mState(VariantType<Pending>(), "RemoteWorkerChild::mState"),
mServiceKeepAlive(RemoteWorkerService::MaybeGetKeepAlive()),
mIsServiceWorker(aData.serviceWorkerData().type() ==
OptionalServiceWorkerData::TServiceWorkerData) {
@ -187,10 +205,7 @@ void RemoteWorkerChild::ActorDestroy(ActorDestroyReason) {
}
}
void RemoteWorkerChild::ExecWorker(
const RemoteWorkerData& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp) {
void RemoteWorkerChild::ExecWorker(const RemoteWorkerData& aData) {
#ifdef DEBUG
MOZ_ASSERT(GetActorEventTarget()->IsOnCurrentThread());
auto launcherData = mLauncherData.Access();
@ -200,10 +215,8 @@ void RemoteWorkerChild::ExecWorker(
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [self = std::move(self), data = aData,
childEp = std::move(aChildEp)]() mutable {
nsresult rv =
self->ExecWorkerOnMainThread(std::move(data), std::move(childEp));
__func__, [self = std::move(self), data = aData]() mutable {
nsresult rv = self->ExecWorkerOnMainThread(std::move(data));
// Creation failure will already have been reported via the method
// above internally using ScopeExit.
@ -213,10 +226,7 @@ void RemoteWorkerChild::ExecWorker(
MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
}
nsresult RemoteWorkerChild::ExecWorkerOnMainThread(
RemoteWorkerData&& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp) {
nsresult RemoteWorkerChild::ExecWorkerOnMainThread(RemoteWorkerData&& aData) {
MOZ_ASSERT(NS_IsMainThread());
// Ensure that the IndexedDatabaseManager is initialized so that if any
@ -385,8 +395,7 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(
// begin to transition when the worker thread would reach the Canceling
// state. This lambda ensures that we not only wait for the Killing state
// to be reached but that the global shutdown has already occurred.
[self]() { self->TransitionStateFromCanceledToKilled(); },
std::move(aChildEp));
[self]() { self->TransitionStateFromCanceledToKilled(); });
if (NS_WARN_IF(error.Failed())) {
MOZ_ASSERT(!workerPrivate);
@ -668,6 +677,22 @@ void RemoteWorkerChild::FlushReportsOnMainThread(
/**
* Worker state transition methods
*/
RemoteWorkerChild::WorkerPrivateAccessibleState::
~WorkerPrivateAccessibleState() {
// We should now only be performing state transitions on the main thread, so
// we should assert we're only releasing on the main thread.
MOZ_ASSERT(!mWorkerPrivate || NS_IsMainThread());
// mWorkerPrivate can be safely released on the main thread.
if (!mWorkerPrivate || NS_IsMainThread()) {
return;
}
// But as a backstop, do proxy the release to the main thread.
NS_ReleaseOnMainThread(
"RemoteWorkerChild::WorkerPrivateAccessibleState::mWorkerPrivate",
mWorkerPrivate.forget());
}
void RemoteWorkerChild::
OnWorkerCancellationTransitionStateFromPendingOrRunningToCanceled() {
auto lock = mState.Lock();
@ -677,21 +702,20 @@ void RemoteWorkerChild::
if (lock->is<Pending>()) {
TransitionStateFromPendingToCanceled(lock.ref());
} else if (lock->is<Running>()) {
*lock = VariantType<remoteworker::Canceled>();
*lock = VariantType<Canceled>();
} else {
MOZ_ASSERT(false, "State should have been Pending or Running");
}
}
void RemoteWorkerChild::TransitionStateFromPendingToCanceled(
RemoteWorkerState& aState) {
void RemoteWorkerChild::TransitionStateFromPendingToCanceled(State& aState) {
AssertIsOnMainThread();
MOZ_ASSERT(aState.is<Pending>());
LOG(("TransitionStateFromPendingToCanceled[this=%p]", this));
CancelAllPendingOps(aState);
aState = VariantType<remoteworker::Canceled>();
aState = VariantType<Canceled>();
}
void RemoteWorkerChild::TransitionStateFromCanceledToKilled() {
@ -702,7 +726,7 @@ void RemoteWorkerChild::TransitionStateFromCanceledToKilled() {
auto lock = mState.Lock();
MOZ_ASSERT(lock->is<Canceled>());
*lock = VariantType<remoteworker::Killed>();
*lock = VariantType<Killed>();
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__, [self]() {
@ -730,7 +754,7 @@ void RemoteWorkerChild::TransitionStateToRunning() {
LOG(("TransitionStateToRunning[this=%p]", this));
nsTArray<RefPtr<RemoteWorkerOp>> pendingOps;
nsTArray<RefPtr<Op>> pendingOps;
{
auto lock = mState.Lock();
@ -751,7 +775,7 @@ void RemoteWorkerChild::TransitionStateToRunning() {
// Move the worker private into place to avoid gratuitous ref churn; prior
// comments here suggest the Variant can't accept a move.
*lock = VariantType<remoteworker::Running>();
*lock = VariantType<Running>();
lock->as<Running>().mWorkerPrivate = std::move(workerPrivate);
}
@ -805,7 +829,153 @@ void RemoteWorkerChild::ExceptionalErrorTransitionDuringExecWorker() {
}
}
void RemoteWorkerChild::CancelAllPendingOps(RemoteWorkerState& aState) {
/**
* Operation execution classes/methods
*/
class RemoteWorkerChild::SharedWorkerOp : public RemoteWorkerChild::Op {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerOp, override)
explicit SharedWorkerOp(RemoteWorkerOp&& aOp) : mOp(std::move(aOp)) {}
bool MaybeStart(RemoteWorkerChild* aOwner,
RemoteWorkerChild::State& aState) override {
MOZ_ASSERT(!mStarted);
MOZ_ASSERT(aOwner);
// Thread: We are on the Worker Launcher thread.
// Return false, indicating we should queue this op if our current state is
// pending and this isn't a termination op (which should skip the line).
if (aState.is<Pending>() && !IsTerminationOp()) {
return false;
}
// If the worker is already shutting down (which should be unexpected
// because we should be told new operations after a termination op), just
// return true to indicate the op should be discarded.
if (aState.is<Canceled>() || aState.is<Killed>()) {
#ifdef DEBUG
mStarted = true;
#endif
if (mOp.type() == RemoteWorkerOp::TRemoteWorkerPortIdentifierOp) {
MessagePort::ForceClose(
mOp.get_RemoteWorkerPortIdentifierOp().portIdentifier());
}
return true;
}
MOZ_ASSERT(aState.is<Running>() || IsTerminationOp());
RefPtr<SharedWorkerOp> self = this;
RefPtr<RemoteWorkerChild> owner = aOwner;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [self = std::move(self), owner = std::move(owner)]() mutable {
{
auto lock = owner->mState.Lock();
if (NS_WARN_IF(lock->is<Canceled>() || lock->is<Killed>())) {
self->Cancel();
// Worker has already canceled, force close the MessagePort.
if (self->mOp.type() ==
RemoteWorkerOp::TRemoteWorkerPortIdentifierOp) {
MessagePort::ForceClose(
self->mOp.get_RemoteWorkerPortIdentifierOp()
.portIdentifier());
}
return;
}
}
self->StartOnMainThread(owner);
});
MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
#ifdef DEBUG
mStarted = true;
#endif
return true;
}
void StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) final {
using Running = RemoteWorkerChild::Running;
AssertIsOnMainThread();
if (IsTerminationOp()) {
aOwner->CloseWorkerOnMainThread();
return;
}
auto lock = aOwner->mState.Lock();
MOZ_ASSERT(lock->is<Running>());
if (!lock->is<Running>()) {
aOwner->ErrorPropagationDispatch(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
RefPtr<WorkerPrivate> workerPrivate = lock->as<Running>().mWorkerPrivate;
MOZ_ASSERT(workerPrivate);
if (mOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp) {
workerPrivate->ParentWindowPaused();
} else if (mOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp) {
workerPrivate->ParentWindowResumed();
} else if (mOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp) {
workerPrivate->Freeze(nullptr);
} else if (mOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp) {
workerPrivate->Thaw(nullptr);
} else if (mOp.type() == RemoteWorkerOp::TRemoteWorkerPortIdentifierOp) {
RefPtr<MessagePortIdentifierRunnable> r =
new MessagePortIdentifierRunnable(
workerPrivate, aOwner,
mOp.get_RemoteWorkerPortIdentifierOp().portIdentifier());
if (NS_WARN_IF(!r->Dispatch(workerPrivate))) {
aOwner->ErrorPropagationDispatch(NS_ERROR_FAILURE);
}
} else if (mOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp) {
aOwner->mWindowIDs.AppendElement(
mOp.get_RemoteWorkerAddWindowIDOp().windowID());
} else if (mOp.type() == RemoteWorkerOp::TRemoteWorkerRemoveWindowIDOp) {
aOwner->mWindowIDs.RemoveElement(
mOp.get_RemoteWorkerRemoveWindowIDOp().windowID());
} else {
MOZ_CRASH("Unknown RemoteWorkerOp type!");
}
}
void Cancel() override {
#ifdef DEBUG
mStarted = true;
#endif
}
private:
~SharedWorkerOp() { MOZ_ASSERT(mStarted); }
bool IsTerminationOp() const {
return mOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp;
}
RemoteWorkerOp mOp;
#ifdef DEBUG
bool mStarted = false;
#endif
};
void RemoteWorkerChild::AddPortIdentifier(
JSContext* aCx, WorkerPrivate* aWorkerPrivate,
UniqueMessagePortId& aPortIdentifier) {
if (NS_WARN_IF(!aWorkerPrivate->ConnectMessagePort(aCx, aPortIdentifier))) {
ErrorPropagationDispatch(NS_ERROR_FAILURE);
}
}
void RemoteWorkerChild::CancelAllPendingOps(State& aState) {
MOZ_ASSERT(aState.is<Pending>());
auto pendingOps = std::move(aState.as<Pending>().mPendingOps);
@ -815,7 +985,7 @@ void RemoteWorkerChild::CancelAllPendingOps(RemoteWorkerState& aState) {
}
}
void RemoteWorkerChild::MaybeStartOp(RefPtr<RemoteWorkerOp>&& aOp) {
void RemoteWorkerChild::MaybeStartOp(RefPtr<Op>&& aOp) {
MOZ_ASSERT(aOp);
auto lock = mState.Lock();
@ -826,10 +996,10 @@ void RemoteWorkerChild::MaybeStartOp(RefPtr<RemoteWorkerOp>&& aOp) {
}
}
IPCResult RemoteWorkerChild::RecvExecOp(SharedWorkerOpArgs&& aOpArgs) {
IPCResult RemoteWorkerChild::RecvExecOp(RemoteWorkerOp&& aOp) {
MOZ_ASSERT(!mIsServiceWorker);
MaybeStartOp(new SharedWorkerOp(std::move(aOpArgs)));
MaybeStartOp(new SharedWorkerOp(std::move(aOp)));
return IPC_OK();
}

View File

@ -16,24 +16,18 @@
#include "mozilla/RefPtr.h"
#include "mozilla/ThreadBound.h"
#include "mozilla/dom/PRemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerOp.h"
#include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/ServiceWorkerOpArgs.h"
#include "mozilla/dom/SharedWorkerOpArgs.h"
class nsISerialEventTarget;
class nsIConsoleReportCollector;
namespace mozilla::dom {
using remoteworker::RemoteWorkerState;
class ErrorValue;
class FetchEventOpProxyChild;
class RemoteWorkerData;
class RemoteWorkerServiceKeepAlive;
class ServiceWorkerOp;
class SharedWorkerOp;
class UniqueMessagePortId;
class WeakWorkerRef;
class WorkerErrorReport;
@ -50,7 +44,6 @@ class RemoteWorkerChild final : public PRemoteWorkerChild {
friend class FetchEventOpProxyChild;
friend class PRemoteWorkerChild;
friend class ServiceWorkerOp;
friend class SharedWorkerOp;
~RemoteWorkerChild();
@ -62,10 +55,7 @@ class RemoteWorkerChild final : public PRemoteWorkerChild {
explicit RemoteWorkerChild(const RemoteWorkerData& aData);
void ExecWorker(
const RemoteWorkerData& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp);
void ExecWorker(const RemoteWorkerData& aData);
void ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
bool aIsErrorEvent);
@ -78,6 +68,9 @@ class RemoteWorkerChild final : public PRemoteWorkerChild {
void FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter);
void AddPortIdentifier(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
UniqueMessagePortId& aPortIdentifier);
RefPtr<GenericNonExclusivePromise> GetTerminationPromise();
RefPtr<GenericPromise> MaybeSendSetServiceWorkerSkipWaitingFlag();
@ -87,17 +80,86 @@ class RemoteWorkerChild final : public PRemoteWorkerChild {
private:
class InitializeWorkerRunnable;
class Op;
class SharedWorkerOp;
struct WorkerPrivateAccessibleState {
~WorkerPrivateAccessibleState();
RefPtr<WorkerPrivate> mWorkerPrivate;
};
// Initial state, mWorkerPrivate is initially null but will be initialized on
// the main thread by ExecWorkerOnMainThread when the WorkerPrivate is
// created. The state will transition to Running or Canceled, also from the
// main thread.
struct Pending : WorkerPrivateAccessibleState {
nsTArray<RefPtr<Op>> mPendingOps;
};
// Running, with the state transition happening on the main thread as a result
// of the worker successfully processing our initialization runnable,
// indicating that top-level script execution successfully completed. Because
// all of our state transitions happen on the main thread and are posed in
// terms of the main thread's perspective of the worker's state, it's very
// possible for us to skip directly from Pending to Canceled because we decide
// to cancel/terminate the worker prior to it finishing script loading or
// reporting back to us.
struct Running : WorkerPrivateAccessibleState {};
// Cancel() has been called on the WorkerPrivate on the main thread by a
// TerminationOp, top-level script evaluation has failed and canceled the
// worker, or in the case of a SharedWorker, close() has been called on
// the global scope by content code and the worker has advanced to the
// Canceling state. (Dedicated Workers can also self close, but they will
// never be RemoteWorkers. Although a SharedWorker can own DedicatedWorkers.)
// Browser shutdown will result in a TerminationOp thanks to use of a shutdown
// blocker in the parent, so the RuntimeService shouldn't get involved, but we
// would also handle that case acceptably too.
//
// Because worker self-closing is still handled by dispatching a runnable to
// the main thread to effectively call WorkerPrivate::Cancel(), there isn't
// a race between a worker deciding to self-close and our termination ops.
//
// In this state, we have dropped the reference to the WorkerPrivate and will
// no longer be dispatching runnables to the worker. We wait in this state
// until the termination lambda is invoked letting us know that the worker has
// entirely shutdown and we can advanced to the Killed state.
struct Canceled {};
// The worker termination lambda has been invoked and we know the Worker is
// entirely shutdown. (Inherently it is possible for us to advance to this
// state while the nsThread for the worker is still in the process of
// shutting down, but no more worker code will run on it.)
//
// This name is chosen to match the Worker's own state model.
struct Killed {};
using State = Variant<Pending, Running, Canceled, Killed>;
// The state of the WorkerPrivate as perceived by the owner on the main
// thread. All state transitions now happen on the main thread, but the
// Worker Launcher thread will consult the state and will directly append ops
// to the Pending queue
DataMutex<RemoteWorkerState> mState;
DataMutex<State> mState;
const RefPtr<RemoteWorkerServiceKeepAlive> mServiceKeepAlive;
class Op {
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual ~Op() = default;
virtual bool MaybeStart(RemoteWorkerChild* aOwner, State& aState) = 0;
virtual void StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) = 0;
virtual void Cancel() = 0;
};
void ActorDestroy(ActorDestroyReason) override;
mozilla::ipc::IPCResult RecvExecOp(SharedWorkerOpArgs&& aOpArgs);
mozilla::ipc::IPCResult RecvExecOp(RemoteWorkerOp&& aOp);
mozilla::ipc::IPCResult RecvExecServiceWorkerOp(
ServiceWorkerOpArgs&& aArgs, ExecServiceWorkerOpResolver&& aResolve);
@ -109,10 +171,7 @@ class RemoteWorkerChild final : public PRemoteWorkerChild {
PFetchEventOpProxyChild* aActor,
const ParentToChildServiceWorkerFetchEventOpArgs& aArgs) override;
nsresult ExecWorkerOnMainThread(
RemoteWorkerData&& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp);
nsresult ExecWorkerOnMainThread(RemoteWorkerData&& aData);
void ExceptionalErrorTransitionDuringExecWorker();
@ -147,18 +206,18 @@ class RemoteWorkerChild final : public PRemoteWorkerChild {
// the worker hasn't started running, or in exceptional cases where we bail
// out of the ExecWorker method early. The caller must be holding the lock
// (in order to pass in the state).
void TransitionStateFromPendingToCanceled(RemoteWorkerState& aState);
void TransitionStateFromPendingToCanceled(State& aState);
void TransitionStateFromCanceledToKilled();
void TransitionStateToRunning();
void TransitionStateToTerminated();
void TransitionStateToTerminated(RemoteWorkerState& aState);
void TransitionStateToTerminated(State& aState);
void CancelAllPendingOps(RemoteWorkerState& aState);
void CancelAllPendingOps(State& aState);
void MaybeStartOp(RefPtr<RemoteWorkerOp>&& aOp);
void MaybeStartOp(RefPtr<Op>&& aOp);
const bool mIsServiceWorker;

View File

@ -23,7 +23,6 @@
#include "mozilla/ipc/BackgroundParent.h"
#include "RemoteWorkerControllerParent.h"
#include "RemoteWorkerManager.h"
#include "RemoteWorkerNonLifeCycleOpControllerParent.h"
#include "RemoteWorkerParent.h"
namespace mozilla {
@ -97,7 +96,6 @@ void RemoteWorkerController::CreationFailed() {
if (mState == eTerminated) {
MOZ_ASSERT(!mActor);
MOZ_ASSERT(!mNonLifeCycleOpController);
MOZ_ASSERT(mPendingOps.IsEmpty());
// Nothing to do.
return;
@ -114,14 +112,12 @@ void RemoteWorkerController::CreationSucceeded() {
if (mState == eTerminated) {
MOZ_ASSERT(!mActor);
MOZ_ASSERT(!mNonLifeCycleOpController);
MOZ_ASSERT(mPendingOps.IsEmpty());
// Nothing to do.
return;
}
MOZ_ASSERT(mActor);
MOZ_ASSERT(mNonLifeCycleOpController);
mState = eReady;
mObserver->CreationSucceeded();
@ -183,11 +179,6 @@ void RemoteWorkerController::Shutdown() {
CancelAllPendingOps();
if (mNonLifeCycleOpController) {
mNonLifeCycleOpController->Shutdown();
mNonLifeCycleOpController = nullptr;
}
if (!mActor) {
return;
}
@ -201,7 +192,7 @@ void RemoteWorkerController::Shutdown() {
if (mIsServiceWorker) {
mActor->MaybeSendDelete();
} else {
Unused << mActor->SendExecOp(SharedWorkerTerminateOpArgs());
Unused << mActor->SendExecOp(RemoteWorkerTerminateOp());
}
mActor = nullptr;
@ -381,39 +372,28 @@ bool RemoteWorkerController::PendingSharedWorkerOp::MaybeStart(
aOwner->Shutdown();
break;
case eSuspend:
Unused << aOwner->mActor->SendExecOp(SharedWorkerSuspendOpArgs());
Unused << aOwner->mActor->SendExecOp(RemoteWorkerSuspendOp());
break;
case eResume:
Unused << aOwner->mActor->SendExecOp(SharedWorkerResumeOpArgs());
Unused << aOwner->mActor->SendExecOp(RemoteWorkerResumeOp());
break;
case eFreeze:
Unused << aOwner->mActor->SendExecOp(SharedWorkerFreezeOpArgs());
Unused << aOwner->mActor->SendExecOp(RemoteWorkerFreezeOp());
break;
case eThaw:
Unused << aOwner->mActor->SendExecOp(SharedWorkerThawOpArgs());
Unused << aOwner->mActor->SendExecOp(RemoteWorkerThawOp());
break;
case ePortIdentifier:
// mNonLifeCycleOpController can be nullptr if the Worker is in "Killing."
// RemoteWorkerNonLifeCycleOpControllerChild switches to the Killed status
// earlier than RemoteWorkerChild since it switches the status on the
// worker thread, not the main thread.
if (!aOwner->mNonLifeCycleOpController) {
Cancel();
return true;
}
if (!aOwner->mNonLifeCycleOpController->CanSend()) {
return false;
}
Unused << aOwner->mNonLifeCycleOpController->SendExecOp(
SharedWorkerPortIdentifierOpArgs(mPortIdentifier));
Unused << aOwner->mActor->SendExecOp(
RemoteWorkerPortIdentifierOp(mPortIdentifier));
break;
case eAddWindowID:
Unused << aOwner->mActor->SendExecOp(
SharedWorkerAddWindowIDOpArgs(mWindowID));
RemoteWorkerAddWindowIDOp(mWindowID));
break;
case eRemoveWindowID:
Unused << aOwner->mActor->SendExecOp(
SharedWorkerRemoveWindowIDOpArgs(mWindowID));
RemoteWorkerRemoveWindowIDOp(mWindowID));
break;
default:
MOZ_CRASH("Unknown op.");
@ -491,51 +471,21 @@ bool RemoteWorkerController::PendingServiceWorkerOp::MaybeStart(
return false;
}
switch (mArgs.type()) {
case ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs:
case ServiceWorkerOpArgs::TParentToChildServiceWorkerFetchEventOpArgs: {
MaybeReportServiceWorkerShutdownProgress(mArgs);
MaybeReportServiceWorkerShutdownProgress(mArgs);
aOwner->mActor->SendExecServiceWorkerOp(mArgs)->Then(
GetCurrentSerialEventTarget(), __func__,
[promise = std::move(mPromise)](
PRemoteWorkerParent::ExecServiceWorkerOpPromise::
ResolveOrRejectValue&& aResult) {
if (NS_WARN_IF(aResult.IsReject())) {
promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
return;
}
aOwner->mActor->SendExecServiceWorkerOp(mArgs)->Then(
GetCurrentSerialEventTarget(), __func__,
[promise = std::move(mPromise)](
PRemoteWorkerParent::ExecServiceWorkerOpPromise::
ResolveOrRejectValue&& aResult) {
if (NS_WARN_IF(aResult.IsReject())) {
promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
return;
}
promise->Resolve(std::move(aResult.ResolveValue()), __func__);
});
break;
}
default: {
// mNonLifeCycleOpController can be nullptr if the Worker is in "Killing."
// RemoteWorkerNonLifeCycleOpControllerChild switches to the Killed status
// earlier than RemoteWorkerChild since it switches the status on the
// worker thread, not the main thread.
if (!aOwner->mNonLifeCycleOpController) {
Cancel();
return true;
}
if (!aOwner->mNonLifeCycleOpController->CanSend()) {
return false;
}
aOwner->mNonLifeCycleOpController->SendExecServiceWorkerOp(mArgs)->Then(
GetCurrentSerialEventTarget(), __func__,
[promise = std::move(mPromise)](
PRemoteWorkerParent::ExecServiceWorkerOpPromise::
ResolveOrRejectValue&& aResult) {
if (NS_WARN_IF(aResult.IsReject())) {
promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
return;
}
promise->Resolve(std::move(aResult.ResolveValue()), __func__);
});
promise->Resolve(std::move(aResult.ResolveValue()), __func__);
});
}
}
return true;
}

View File

@ -15,7 +15,6 @@
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/dom/ServiceWorkerOpArgs.h"
#include "mozilla/dom/ServiceWorkerOpPromise.h"
#include "mozilla/dom/SharedWorkerOpArgs.h"
namespace mozilla::dom {
@ -90,7 +89,6 @@ class FetchEventOpParent;
class RemoteWorkerControllerParent;
class RemoteWorkerData;
class RemoteWorkerManager;
class RemoteWorkerNonLifeCycleOpControllerParent;
class RemoteWorkerParent;
class RemoteWorkerObserver {
@ -126,7 +124,6 @@ class RemoteWorkerController final {
friend class RemoteWorkerControllerParent;
friend class RemoteWorkerManager;
friend class RemoteWorkerParent;
friend class RemoteWorkerNonLifeCycleOpControllerParent;
public:
NS_INLINE_DECL_REFCOUNTING(RemoteWorkerController)
@ -195,7 +192,6 @@ class RemoteWorkerController final {
RefPtr<RemoteWorkerObserver> mObserver;
RefPtr<RemoteWorkerParent> mActor;
RefPtr<RemoteWorkerNonLifeCycleOpControllerParent> mNonLifeCycleOpController;
enum {
ePending,

View File

@ -12,10 +12,7 @@
#include "mozilla/ScopeExit.h"
#include "mozilla/dom/ContentChild.h" // ContentChild::GetSingleton
#include "mozilla/dom/ProcessIsolation.h"
#include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerParent.h"
#include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/RemoteWorkerController.h"
#include "mozilla/dom/RemoteWorkerNonLifeCycleOpControllerParent.h"
#include "mozilla/dom/RemoteWorkerParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/BackgroundUtils.h"
@ -326,20 +323,7 @@ void RemoteWorkerManager::LaunchInternal(
RefPtr<RemoteWorkerParent> workerActor =
MakeAndAddRef<RemoteWorkerParent>(std::move(aKeepAlive));
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerParent> parentEp;
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild> childEp;
MOZ_ALWAYS_SUCCEEDS(PRemoteWorkerNonLifeCycleOpController::CreateEndpoints(
&parentEp, &childEp));
MOZ_ASSERT(!aController->mNonLifeCycleOpController);
aController->mNonLifeCycleOpController =
MakeAndAddRef<RemoteWorkerNonLifeCycleOpControllerParent>(aController);
parentEp.Bind(aController->mNonLifeCycleOpController);
if (!aTargetActor->SendPRemoteWorkerConstructor(workerActor, aData,
std::move(childEp))) {
if (!aTargetActor->SendPRemoteWorkerConstructor(workerActor, aData)) {
AsyncCreationFailed(aController);
return;
}

View File

@ -19,7 +19,6 @@ namespace mozilla::dom {
class RemoteWorkerController;
class RemoteWorkerServiceParent;
class RemoteWorkerNonLifeCycleOpControllerParent;
/**
* PBackground instance that keeps tracks of RemoteWorkerServiceParent actors

View File

@ -1,100 +0,0 @@
/* 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 "RemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/ServiceWorkerOp.h"
#include "mozilla/dom/SharedWorkerOp.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
namespace mozilla::dom {
using remoteworker::Canceled;
using remoteworker::Killed;
using remoteworker::Running;
/* static */
RefPtr<RemoteWorkerNonLifeCycleOpControllerChild>
RemoteWorkerNonLifeCycleOpControllerChild::Create() {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(GetCurrentThreadWorkerPrivate());
RefPtr<RemoteWorkerNonLifeCycleOpControllerChild> actor =
MakeAndAddRef<RemoteWorkerNonLifeCycleOpControllerChild>();
return actor;
}
RemoteWorkerNonLifeCycleOpControllerChild::
RemoteWorkerNonLifeCycleOpControllerChild()
: mState(VariantType<remoteworker::Running>(),
"RemoteWorkerNonLifeCycleOpControllerChild") {}
RemoteWorkerNonLifeCycleOpControllerChild::
~RemoteWorkerNonLifeCycleOpControllerChild() = default;
void RemoteWorkerNonLifeCycleOpControllerChild::TransistionStateToCanceled() {
auto lock = mState.Lock();
MOZ_ASSERT(lock->is<Running>());
/*Canceling pending/processing operations here*/
*lock = VariantType<Canceled>();
}
void RemoteWorkerNonLifeCycleOpControllerChild::TransistionStateToKilled() {
auto lock = mState.Lock();
MOZ_ASSERT(lock->is<Canceled>());
*lock = VariantType<Killed>();
if (!CanSend()) {
return;
}
Unused << SendTerminated();
}
void RemoteWorkerNonLifeCycleOpControllerChild::ErrorPropagation(
nsresult aError) {
if (!CanSend()) {
return;
}
Unused << SendError(aError);
}
void RemoteWorkerNonLifeCycleOpControllerChild::StartOp(
RefPtr<RemoteWorkerOp>&& aOp) {
MOZ_ASSERT(aOp);
auto lock = mState.Lock();
// ServiceWorkerOp/SharedWorkerOp handles the Canceled/Killed state cases.
aOp->Start(this, lock.ref());
}
IPCResult RemoteWorkerNonLifeCycleOpControllerChild::RecvExecOp(
SharedWorkerOpArgs&& aOpArgs) {
MOZ_ASSERT(aOpArgs.type() ==
SharedWorkerOpArgs::TSharedWorkerPortIdentifierOpArgs);
StartOp(new SharedWorkerOp(std::move(aOpArgs)));
return IPC_OK();
}
IPCResult RemoteWorkerNonLifeCycleOpControllerChild::RecvExecServiceWorkerOp(
ServiceWorkerOpArgs&& aOpArgs, ExecServiceWorkerOpResolver&& aResolve) {
MOZ_ASSERT(
aOpArgs.type() !=
ServiceWorkerOpArgs::TParentToChildServiceWorkerFetchEventOpArgs,
"FetchEvent operations should be sent via PFetchEventOp(Proxy) actors!");
MOZ_ASSERT(aOpArgs.type() !=
ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs,
"Terminate operations should be sent via PRemoteWorker actros!");
StartOp(ServiceWorkerOp::Create(std::move(aOpArgs), std::move(aResolve)));
return IPC_OK();
}
IPCResult RemoteWorkerNonLifeCycleOpControllerChild::RecvShutdown() {
return IPC_OK();
}
} // namespace mozilla::dom

View File

@ -1,57 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_RemoteWorkerNonLifeCycleOpControllerChild_h
#define mozilla_dom_RemoteWorkerNonLifeCycleOpControllerChild_h
#include "mozilla/DataMutex.h"
#include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/RemoteWorkerOp.h"
#include "mozilla/dom/ServiceWorkerOpArgs.h"
#include "mozilla/dom/SharedWorkerOpArgs.h"
#include "nsISupportsImpl.h"
using mozilla::ipc::IPCResult;
namespace mozilla::dom {
using remoteworker::RemoteWorkerState;
class ServiceWorkerOp;
class RemoteWorkerNonLifeCycleOpControllerChild final
: public PRemoteWorkerNonLifeCycleOpControllerChild {
friend class PRemoteWorkerNonLifeCycleOpControllerChild;
friend class ServiceWorkerOp;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(
RemoteWorkerNonLifeCycleOpControllerChild, final)
static RefPtr<RemoteWorkerNonLifeCycleOpControllerChild> Create();
RemoteWorkerNonLifeCycleOpControllerChild();
IPCResult RecvExecOp(SharedWorkerOpArgs&& aOpArgs);
IPCResult RecvExecServiceWorkerOp(ServiceWorkerOpArgs&& aOpArgs,
ExecServiceWorkerOpResolver&& aResolve);
IPCResult RecvShutdown();
void TransistionStateToCanceled();
void TransistionStateToKilled();
void ErrorPropagation(nsresult aError);
private:
void StartOp(RefPtr<RemoteWorkerOp>&& aOp);
~RemoteWorkerNonLifeCycleOpControllerChild();
DataMutex<RemoteWorkerState> mState;
};
} // namespace mozilla::dom
#endif // mozilla_dom_RemoteWorkerNonLifeCycleOpControllerChild_h

View File

@ -1,52 +0,0 @@
/* 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 "RemoteWorkerNonLifeCycleOpControllerParent.h"
#include "mozilla/dom/RemoteWorkerController.h"
namespace mozilla::dom {
RemoteWorkerNonLifeCycleOpControllerParent::
RemoteWorkerNonLifeCycleOpControllerParent(
RemoteWorkerController* aController)
: mController(aController) {
MOZ_ASSERT(mController);
}
RemoteWorkerNonLifeCycleOpControllerParent::
~RemoteWorkerNonLifeCycleOpControllerParent() = default;
void RemoteWorkerNonLifeCycleOpControllerParent::Shutdown() {
if (CanSend()) {
Unused << SendShutdown();
}
mController = nullptr;
}
IPCResult RemoteWorkerNonLifeCycleOpControllerParent::RecvTerminated() {
// mController could be nullptr when the controller had already shutted down.
if (mController) {
mController->mNonLifeCycleOpController = nullptr;
mController = nullptr;
}
return IPC_OK();
}
IPCResult RemoteWorkerNonLifeCycleOpControllerParent::RecvError(
const ErrorValue& aError) {
MOZ_ASSERT(mController);
mController->ErrorPropagation(aError);
return IPC_OK();
}
void RemoteWorkerNonLifeCycleOpControllerParent::ActorDestroy(
IProtocol::ActorDestroyReason) {
if (mController) {
mController->mNonLifeCycleOpController = nullptr;
mController = nullptr;
}
}
} // namespace mozilla::dom

View File

@ -1,41 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_RemoteWorkerNonLifeCycleOpControllerParent_h
#define mozilla_dom_RemoteWorkerNonLifeCycleOpControllerParent_h
#include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerParent.h"
using mozilla::ipc::IPCResult;
namespace mozilla::dom {
class RemoteWorkerController;
class RemoteWorkerNonLifeCycleOpControllerParent final
: public PRemoteWorkerNonLifeCycleOpControllerParent {
public:
NS_INLINE_DECL_REFCOUNTING(RemoteWorkerNonLifeCycleOpControllerParent,
override);
explicit RemoteWorkerNonLifeCycleOpControllerParent(
RemoteWorkerController* aRemoteWorkerController);
IPCResult RecvTerminated();
IPCResult RecvError(const ErrorValue& aError);
void ActorDestroy(IProtocol::ActorDestroyReason) override;
void Shutdown();
private:
~RemoteWorkerNonLifeCycleOpControllerParent();
RefPtr<RemoteWorkerController> mController;
};
} // namespace mozilla::dom
#endif // mozilla_dom_RemoteWorkerNonLifeCycleOpControllerParent_h

View File

@ -1,23 +0,0 @@
/* 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 "RemoteWorkerOp.h"
namespace mozilla::dom::remoteworker {
WorkerPrivateAccessibleState::~WorkerPrivateAccessibleState() {
// We should now only be performing state transitions on the main thread, so
// we should assert we're only releasing on the main thread.
MOZ_ASSERT(!mWorkerPrivate || NS_IsMainThread());
// mWorkerPrivate can be safely released on the main thread.
if (!mWorkerPrivate || NS_IsMainThread()) {
return;
}
// But as a backstop, do proxy the release to the main thread.
NS_ReleaseOnMainThread(
"RemoteWorkerChild::WorkerPrivateAccessibleState::mWorkerPrivate",
mWorkerPrivate.forget());
}
} // namespace mozilla::dom::remoteworker

View File

@ -1,95 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_RemoteWorkerOp_h
#define mozilla_dom_RemoteWorkerOp_h
#include "mozilla/RefPtr.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/Variant.h"
namespace mozilla::dom {
class RemoteWorkerChild;
class RemtoeWorkerNonfLifeCycleOpControllerChild;
class RemoteWorkerOp;
// class RemoteWorkerNonLifeCycleOpControllerChild;
namespace remoteworker {
struct WorkerPrivateAccessibleState {
~WorkerPrivateAccessibleState();
RefPtr<WorkerPrivate> mWorkerPrivate;
};
// Initial state, mWorkerPrivate is initially null but will be initialized on
// the main thread by ExecWorkerOnMainThread when the WorkerPrivate is
// created. The state will transition to Running or Canceled, also from the
// main thread.
struct Pending : WorkerPrivateAccessibleState {
nsTArray<RefPtr<RemoteWorkerOp>> mPendingOps;
};
// Running, with the state transition happening on the main thread as a result
// of the worker successfully processing our initialization runnable,
// indicating that top-level script execution successfully completed. Because
// all of our state transitions happen on the main thread and are posed in
// terms of the main thread's perspective of the worker's state, it's very
// possible for us to skip directly from Pending to Canceled because we decide
// to cancel/terminate the worker prior to it finishing script loading or
// reporting back to us.
struct Running : WorkerPrivateAccessibleState {};
// Cancel() has been called on the WorkerPrivate on the main thread by a
// TerminationOp, top-level script evaluation has failed and canceled the
// worker, or in the case of a SharedWorker, close() has been called on
// the global scope by content code and the worker has advanced to the
// Canceling state. (Dedicated Workers can also self close, but they will
// never be RemoteWorkers. Although a SharedWorker can own DedicatedWorkers.)
// Browser shutdown will result in a TerminationOp thanks to use of a shutdown
// blocker in the parent, so the RuntimeService shouldn't get involved, but we
// would also handle that case acceptably too.
//
// Because worker self-closing is still handled by dispatching a runnable to
// the main thread to effectively call WorkerPrivate::Cancel(), there isn't
// a race between a worker deciding to self-close and our termination ops.
//
// In this state, we have dropped the reference to the WorkerPrivate and will
// no longer be dispatching runnables to the worker. We wait in this state
// until the termination lambda is invoked letting us know that the worker has
// entirely shutdown and we can advanced to the Killed state.
struct Canceled {};
// The worker termination lambda has been invoked and we know the Worker is
// entirely shutdown. (Inherently it is possible for us to advance to this
// state while the nsThread for the worker is still in the process of
// shutting down, but no more worker code will run on it.)
//
// This name is chosen to match the Worker's own state model.
struct Killed {};
using RemoteWorkerState = Variant<Pending, Running, Canceled, Killed>;
} // namespace remoteworker
class RemoteWorkerOp {
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual ~RemoteWorkerOp() = default;
virtual bool MaybeStart(RemoteWorkerChild* aOwner,
remoteworker::RemoteWorkerState& aState) = 0;
virtual void StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) = 0;
virtual void Start(RemoteWorkerNonLifeCycleOpControllerChild* aOwner,
remoteworker::RemoteWorkerState& aState) = 0;
virtual void Cancel() = 0;
};
} // namespace mozilla::dom
#endif

View File

@ -16,18 +16,14 @@ RemoteWorkerServiceChild::~RemoteWorkerServiceChild() = default;
already_AddRefed<PRemoteWorkerChild>
RemoteWorkerServiceChild::AllocPRemoteWorkerChild(
const RemoteWorkerData& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&
aChildEp) {
const RemoteWorkerData& aData) {
return MakeAndAddRef<RemoteWorkerChild>(aData);
}
mozilla::ipc::IPCResult RemoteWorkerServiceChild::RecvPRemoteWorkerConstructor(
PRemoteWorkerChild* aActor, const RemoteWorkerData& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp) {
PRemoteWorkerChild* aActor, const RemoteWorkerData& aData) {
RemoteWorkerChild* actor = static_cast<RemoteWorkerChild*>(aActor);
actor->ExecWorker(aData, std::move(aChildEp));
actor->ExecWorker(aData);
return IPC_OK();
}

View File

@ -8,7 +8,6 @@
#define mozilla_dom_RemoteWorkerServiceChild_h
#include "mozilla/dom/PRemoteWorkerServiceChild.h"
#include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h"
#include "nsISupportsImpl.h"
namespace mozilla::dom {
@ -27,14 +26,9 @@ class RemoteWorkerServiceChild final : public PRemoteWorkerServiceChild {
RemoteWorkerServiceChild();
already_AddRefed<PRemoteWorkerChild> AllocPRemoteWorkerChild(
const RemoteWorkerData& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&
aChildEp);
const RemoteWorkerData& aData);
mozilla::ipc::IPCResult RecvPRemoteWorkerConstructor(
PRemoteWorkerChild* aActor, const RemoteWorkerData& aData,
mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&&
aChildEp);
PRemoteWorkerChild* aActor, const RemoteWorkerData& aData);
private:
~RemoteWorkerServiceChild();

View File

@ -6,8 +6,6 @@
#include "RemoteWorkerServiceParent.h"
#include "RemoteWorkerManager.h"
#include "RemoteWorkerParent.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/ipc/BackgroundParent.h"
namespace mozilla {

View File

@ -10,9 +10,6 @@ EXPORTS.mozilla.dom += [
"RemoteWorkerControllerChild.h",
"RemoteWorkerControllerParent.h",
"RemoteWorkerManager.h",
"RemoteWorkerNonLifeCycleOpControllerChild.h",
"RemoteWorkerNonLifeCycleOpControllerParent.h",
"RemoteWorkerOp.h",
"RemoteWorkerParent.h",
"RemoteWorkerService.h",
"RemoteWorkerServiceChild.h",
@ -25,9 +22,6 @@ UNIFIED_SOURCES += [
"RemoteWorkerControllerChild.cpp",
"RemoteWorkerControllerParent.cpp",
"RemoteWorkerManager.cpp",
"RemoteWorkerNonLifeCycleOpControllerChild.cpp",
"RemoteWorkerNonLifeCycleOpControllerParent.cpp",
"RemoteWorkerOp.cpp",
"RemoteWorkerParent.cpp",
"RemoteWorkerService.cpp",
"RemoteWorkerServiceChild.cpp",
@ -42,7 +36,6 @@ LOCAL_INCLUDES += [
IPDL_SOURCES += [
"PRemoteWorker.ipdl",
"PRemoteWorkerController.ipdl",
"PRemoteWorkerNonLifeCycleOpController.ipdl",
"PRemoteWorkerService.ipdl",
"RemoteWorkerTypes.ipdlh",
]

View File

@ -1,202 +0,0 @@
/* 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 "SharedWorkerOp.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerNonLifeCycleOpControllerChild.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/dom/WorkerScope.h"
namespace mozilla::dom {
using remoteworker::Canceled;
using remoteworker::Killed;
using remoteworker::Pending;
using remoteworker::Running;
namespace {
// Normal runnable because AddPortIdentifier() is going to exec JS code.
class MessagePortIdentifierRunnable final : public WorkerSameThreadRunnable {
public:
MessagePortIdentifierRunnable(
RemoteWorkerNonLifeCycleOpControllerChild* aActor,
const MessagePortIdentifier& aPortIdentifier)
: WorkerSameThreadRunnable("MessagePortIdentifierRunnable"),
mActor(aActor),
mPortIdentifier(aPortIdentifier) {}
private:
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
if (aWorkerPrivate->GlobalScope()->IsDying()) {
mPortIdentifier.ForceClose();
return true;
}
if (!aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier)) {
mActor->ErrorPropagation(NS_ERROR_FAILURE);
}
return true;
}
RefPtr<RemoteWorkerNonLifeCycleOpControllerChild> mActor;
UniqueMessagePortId mPortIdentifier;
};
} // namespace
SharedWorkerOp::SharedWorkerOp(SharedWorkerOpArgs&& aArgs)
: mOpArgs(std::move(aArgs)) {}
SharedWorkerOp::~SharedWorkerOp() { MOZ_ASSERT(mStarted); }
void SharedWorkerOp::Cancel() {
#ifdef DEBUG
mStarted = true;
#endif
}
bool SharedWorkerOp::MaybeStart(RemoteWorkerChild* aOwner,
RemoteWorkerState& aState) {
MOZ_ASSERT(!mStarted);
MOZ_ASSERT(aOwner);
// Thread: We are on the Worker Launcher thread.
// Return false, indicating we should queue this op if our current state is
// pending and this isn't a termination op (which should skip the line).
if (aState.is<Pending>() && !IsTerminationOp()) {
return false;
}
// If the worker is already shutting down (which should be unexpected
// because we should be told new operations after a termination op), just
// return true to indicate the op should be discarded.
if (aState.is<Canceled>() || aState.is<Killed>()) {
#ifdef DEBUG
mStarted = true;
#endif
return true;
}
MOZ_ASSERT(aState.is<Running>() || IsTerminationOp());
RefPtr<SharedWorkerOp> self = this;
RefPtr<RemoteWorkerChild> owner = aOwner;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [self = std::move(self), owner = std::move(owner)]() mutable {
{
auto lock = owner->mState.Lock();
if (NS_WARN_IF(lock->is<Canceled>() || lock->is<Killed>())) {
self->Cancel();
return;
}
}
self->StartOnMainThread(owner);
});
MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
#ifdef DEBUG
mStarted = true;
#endif
return true;
}
void SharedWorkerOp::StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) {
AssertIsOnMainThread();
if (IsTerminationOp()) {
aOwner->CloseWorkerOnMainThread();
return;
}
auto lock = aOwner->mState.Lock();
MOZ_ASSERT(lock->is<Running>());
if (!lock->is<Running>()) {
aOwner->ErrorPropagationDispatch(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
RefPtr<WorkerPrivate> workerPrivate = lock->as<Running>().mWorkerPrivate;
MOZ_ASSERT(workerPrivate);
if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerSuspendOpArgs) {
workerPrivate->ParentWindowPaused();
} else if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerResumeOpArgs) {
workerPrivate->ParentWindowResumed();
} else if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerFreezeOpArgs) {
workerPrivate->Freeze(nullptr);
} else if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerThawOpArgs) {
workerPrivate->Thaw(nullptr);
} else if (mOpArgs.type() ==
SharedWorkerOpArgs::TSharedWorkerPortIdentifierOpArgs) {
MOZ_CRASH(
"PortIdentifierOpArgs should not be processed by "
"StartOnMainThread!!!");
} else if (mOpArgs.type() ==
SharedWorkerOpArgs::TSharedWorkerAddWindowIDOpArgs) {
aOwner->mWindowIDs.AppendElement(
mOpArgs.get_SharedWorkerAddWindowIDOpArgs().windowID());
} else if (mOpArgs.type() ==
SharedWorkerOpArgs::TSharedWorkerRemoveWindowIDOpArgs) {
aOwner->mWindowIDs.RemoveElement(
mOpArgs.get_SharedWorkerRemoveWindowIDOpArgs().windowID());
} else {
MOZ_CRASH("Unknown SharedWorkerOpArgs type!");
}
}
void SharedWorkerOp::Start(RemoteWorkerNonLifeCycleOpControllerChild* aOwner,
RemoteWorkerState& aState) {
MOZ_ASSERT(!mStarted);
MOZ_ASSERT(aOwner);
// Thread: We are on the Worker thread.
// Only PortIdentifierOp is NonLifeCycle related opertaion.
MOZ_ASSERT(mOpArgs.type() ==
SharedWorkerOpArgs::TSharedWorkerPortIdentifierOpArgs);
// Should never be Pending state.
MOZ_ASSERT(!aState.is<Pending>());
// If the worker is already shutting down (which should be unexpected
// because we should be told new operations after a termination op), just
// return directly.
if (aState.is<Canceled>() || aState.is<Killed>()) {
#ifdef DEBUG
mStarted = true;
#endif
MessagePort::ForceClose(
mOpArgs.get_SharedWorkerPortIdentifierOpArgs().portIdentifier());
return;
}
MOZ_ASSERT(aState.is<Running>());
// RefPtr<WorkerPrivate> workerPrivate = aState.as<Running>().mWorkerPrivate;
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
RefPtr<MessagePortIdentifierRunnable> r = new MessagePortIdentifierRunnable(
aOwner, mOpArgs.get_SharedWorkerPortIdentifierOpArgs().portIdentifier());
if (NS_WARN_IF(!r->Dispatch(workerPrivate))) {
aOwner->ErrorPropagation(NS_ERROR_FAILURE);
}
#ifdef DEBUG
mStarted = true;
#endif
}
bool SharedWorkerOp::IsTerminationOp() const {
return mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerTerminateOpArgs;
}
} // namespace mozilla::dom

View File

@ -1,47 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_sharedworkerop_h__
#define mozilla_dom_sharedworkerop_h__
#include "mozilla/SchedulerGroup.h"
#include "mozilla/dom/RemoteWorkerOp.h"
#include "mozilla/dom/SharedWorkerOpArgs.h"
namespace mozilla::dom {
using remoteworker::RemoteWorkerState;
class SharedWorkerOp : public RemoteWorkerOp {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerOp, override)
explicit SharedWorkerOp(SharedWorkerOpArgs&& aArgs);
bool MaybeStart(RemoteWorkerChild* aOwner,
RemoteWorkerState& aState) override;
void StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) final;
void Start(RemoteWorkerNonLifeCycleOpControllerChild* aOwner,
RemoteWorkerState& aState) final;
void Cancel() override;
private:
~SharedWorkerOp();
bool IsTerminationOp() const;
SharedWorkerOpArgs mOpArgs;
#ifdef DEBUG
bool mStarted = false;
#endif
};
} // namespace mozilla::dom
#endif

View File

@ -1,52 +0,0 @@
/* 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 DOMTypes;
namespace mozilla {
namespace dom {
struct SharedWorkerSuspendOpArgs
{};
struct SharedWorkerResumeOpArgs
{};
struct SharedWorkerFreezeOpArgs
{};
struct SharedWorkerThawOpArgs
{};
struct SharedWorkerTerminateOpArgs
{};
struct SharedWorkerPortIdentifierOpArgs
{
MessagePortIdentifier portIdentifier;
};
struct SharedWorkerAddWindowIDOpArgs
{
uint64_t windowID;
};
struct SharedWorkerRemoveWindowIDOpArgs
{
uint64_t windowID;
};
union SharedWorkerOpArgs {
SharedWorkerSuspendOpArgs;
SharedWorkerResumeOpArgs;
SharedWorkerFreezeOpArgs;
SharedWorkerThawOpArgs;
SharedWorkerTerminateOpArgs;
SharedWorkerPortIdentifierOpArgs;
SharedWorkerAddWindowIDOpArgs;
SharedWorkerRemoveWindowIDOpArgs;
};
} // namespace dom
} // namespace mozilla

View File

@ -8,7 +8,6 @@ EXPORTS.mozilla.dom += [
"SharedWorker.h",
"SharedWorkerChild.h",
"SharedWorkerManager.h",
"SharedWorkerOp.h",
"SharedWorkerParent.h",
]
@ -16,14 +15,12 @@ UNIFIED_SOURCES += [
"SharedWorker.cpp",
"SharedWorkerChild.cpp",
"SharedWorkerManager.cpp",
"SharedWorkerOp.cpp",
"SharedWorkerParent.cpp",
"SharedWorkerService.cpp",
]
IPDL_SOURCES += [
"PSharedWorker.ipdl",
"SharedWorkerOpArgs.ipdlh",
]
include("/ipc/chromium/chromium-config.mozbuild")

View File

@ -27,6 +27,7 @@
#include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
#include "mozilla/dom/indexedDB/ThreadLocal.h"
#include "mozilla/dom/quota/PQuotaChild.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerControllerChild.h"
#include "mozilla/dom/RemoteWorkerServiceChild.h"
#include "mozilla/dom/ServiceWorkerChild.h"