Bug 1231213 - Refactor RemoteWorkerChild to handle Service Workers' and Shared Workers' operations and to make its state data/transitions safer. r=asuth

Differential Revision: https://phabricator.services.mozilla.com/D26170

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Perry Jiang 2019-08-13 05:16:40 +00:00
Родитель 59fbbec62d
Коммит c0a3f641c2
5 изменённых файлов: 641 добавлений и 343 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -7,114 +7,141 @@
#ifndef mozilla_dom_RemoteWorkerChild_h
#define mozilla_dom_RemoteWorkerChild_h
#include "mozilla/dom/PRemoteWorkerChild.h"
#include "mozilla/DataMutex.h"
#include "mozilla/ThreadBound.h"
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsISupportsImpl.h"
#include "nsTArray.h"
#include "mozilla/DataMutex.h"
#include "mozilla/MozPromise.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ThreadBound.h"
#include "mozilla/ThreadSafeWeakPtr.h"
#include "mozilla/dom/PRemoteWorkerChild.h"
#include "mozilla/dom/ServiceWorkerOpArgs.h"
class nsISerialEventTarget;
class nsIConsoleReportCollector;
namespace mozilla {
namespace dom {
class ErrorValue;
class RemoteWorkerData;
class WeakWorkerRef;
class WorkerErrorReport;
class WorkerPrivate;
class OptionalMessagePortIdentifier;
class RemoteWorkerChild final : public PRemoteWorkerChild {
class RemoteWorkerChild final
: public SupportsThreadSafeWeakPtr<RemoteWorkerChild>,
public PRemoteWorkerChild {
friend class PRemoteWorkerChild;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteWorkerChild)
MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(RemoteWorkerChild)
RemoteWorkerChild();
MOZ_DECLARE_REFCOUNTED_TYPENAME(RemoteWorkerChild)
explicit RemoteWorkerChild(const RemoteWorkerData& aData);
~RemoteWorkerChild();
nsISerialEventTarget* GetOwningEventTarget() const;
void ExecWorker(const RemoteWorkerData& aData);
void InitializeOnWorker(WorkerPrivate* aWorkerPrivate);
void ShutdownOnWorker();
void AddPortIdentifier(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const MessagePortIdentifier& aPortIdentifier);
void ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
bool aIsErrorEvent);
void CloseWorkerOnMainThread();
void FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter);
void AddPortIdentifier(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const MessagePortIdentifier& aPortIdentifier);
RefPtr<GenericNonExclusivePromise> GetTerminationPromise();
void CloseWorkerOnMainThread();
private:
class InitializeWorkerRunnable;
~RemoteWorkerChild();
class Op;
class SharedWorkerOp;
void ActorDestroy(ActorDestroyReason aWhy) override;
struct Pending {
nsTArray<RefPtr<Op>> mPendingOps;
};
mozilla::ipc::IPCResult RecvExecOp(const RemoteWorkerOp& aOp);
struct PendingTerminated {};
// This member is a function template because DataMutex<SharedData>::AutoLock
// is private, yet it must be passed by const reference into ExecuteOperation.
// There should only be one instantiation of this template.
template <typename T>
mozilla::ipc::IPCResult ExecuteOperation(const RemoteWorkerOp&,
const T& aLock);
struct Running {
~Running();
void RecvExecOpOnMainThread(const RemoteWorkerOp& aOp);
RefPtr<WorkerPrivate> mWorkerPrivate;
RefPtr<WeakWorkerRef> mWorkerRef;
};
nsresult ExecWorkerOnMainThread(const RemoteWorkerData& aData);
struct Terminated {};
using State = Variant<Pending, Running, PendingTerminated, Terminated>;
DataMutex<State> mState;
class Op {
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual ~Op() = default;
virtual bool MaybeStart(RemoteWorkerChild* aOwner, State& aState) = 0;
virtual void Cancel() = 0;
};
void ActorDestroy(ActorDestroyReason) override;
mozilla::ipc::IPCResult RecvExecOp(RemoteWorkerOp&& aOp);
nsresult ExecWorkerOnMainThread(RemoteWorkerData&& aData);
void InitializeOnWorker(already_AddRefed<WorkerPrivate> aWorkerPrivate);
void ShutdownOnWorker();
void CreationSucceededOnAnyThread();
void CreationFailedOnAnyThread();
void CreationSucceededOrFailedOnAnyThread(bool aDidCreationSucceed);
void CloseWorkerOnMainThread(State& aState);
void ErrorPropagation(const ErrorValue& aValue);
void ErrorPropagationDispatch(nsresult aError);
void CreationSucceededOnAnyThread();
void TransitionStateToPendingTerminated(State& aState);
void CreationSucceeded();
void TransitionStateToRunning(already_AddRefed<WorkerPrivate> aWorkerPrivate,
already_AddRefed<WeakWorkerRef> aWorkerRef);
void CreationFailedOnAnyThread();
void TransitionStateToTerminated();
void CreationFailed();
void TransitionStateToTerminated(State& aState);
void WorkerTerminated();
void CancelAllPendingOps(State& aState);
void MaybeStartOp(RefPtr<Op>&& aOp);
MozPromiseHolder<GenericNonExclusivePromise> mTerminationPromise;
const bool mIsServiceWorker;
const nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
// Touched on main-thread only.
nsTArray<uint64_t> mWindowIDs;
RefPtr<WeakWorkerRef> mWorkerRef;
bool mIPCActive;
enum WorkerState {
// CreationSucceeded/CreationFailed not called yet.
ePending,
// The worker is not created yet, but we want to terminate as soon as
// possible.
ePendingTerminated,
// Worker up and running.
eRunning,
// Worker terminated.
eTerminated,
};
struct SharedData {
SharedData();
RefPtr<WorkerPrivate> mWorkerPrivate;
WorkerState mWorkerState;
};
DataMutex<SharedData> mSharedData;
// Touched only on the owning thread (Worker Launcher).
struct LauncherBoundData {
nsTArray<RemoteWorkerOp> mPendingOps;
bool mIPCActive = true;
};
ThreadBound<LauncherBoundData> mLauncherData;

Просмотреть файл

@ -136,7 +136,8 @@ IPCResult RemoteWorkerParent::RecvClose() {
mController->WorkerTerminated();
}
Unused << Send__delete__(this);
MaybeSendDelete();
return IPC_OK();
}

Просмотреть файл

@ -66,7 +66,6 @@ struct RemoteWorkerData
StorageAccess storageAccess;
bool isSharedWorker;
OptionalServiceWorkerData serviceWorkerData;
};

Просмотреть файл

@ -325,7 +325,7 @@ bool BackgroundChildImpl::DeallocPPendingIPCBlobChild(
dom::PRemoteWorkerChild* BackgroundChildImpl::AllocPRemoteWorkerChild(
const RemoteWorkerData& aData) {
RefPtr<dom::RemoteWorkerChild> agent = new dom::RemoteWorkerChild();
RefPtr<dom::RemoteWorkerChild> agent = new dom::RemoteWorkerChild(aData);
return agent.forget().take();
}