RemoteWorkerChild.h (7463B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_RemoteWorkerChild_h 8 #define mozilla_dom_RemoteWorkerChild_h 9 10 #include "mozilla/DataMutex.h" 11 #include "mozilla/MozPromise.h" 12 #include "mozilla/RefPtr.h" 13 #include "mozilla/ThreadBound.h" 14 #include "mozilla/dom/PRemoteWorkerChild.h" 15 #include "mozilla/dom/PRemoteWorkerNonLifeCycleOpControllerChild.h" 16 #include "mozilla/dom/RemoteWorkerOp.h" 17 #include "mozilla/dom/ServiceWorkerOpArgs.h" 18 #include "mozilla/dom/SharedWorkerOpArgs.h" 19 #include "nsCOMPtr.h" 20 #include "nsISupportsImpl.h" 21 #include "nsTArray.h" 22 23 class nsISerialEventTarget; 24 class nsIConsoleReportCollector; 25 26 namespace mozilla::dom { 27 28 using remoteworker::RemoteWorkerState; 29 30 class ErrorValue; 31 class FetchEventOpProxyChild; 32 class RemoteWorkerData; 33 class RemoteWorkerServiceKeepAlive; 34 class ServiceWorkerOp; 35 class SharedWorkerOp; 36 class UniqueMessagePortId; 37 class WeakWorkerRef; 38 class WorkerErrorReport; 39 class WorkerPrivate; 40 41 /** 42 * Background-managed "Worker Launcher"-thread-resident created via the 43 * RemoteWorkerManager to actually spawn the worker. Currently, the worker will 44 * be spawned from the main thread due to nsIPrincipal not being able to be 45 * created on background threads and other ownership invariants, most of which 46 * can be relaxed in the future. 47 */ 48 class RemoteWorkerChild final : public PRemoteWorkerChild { 49 friend class FetchEventOpProxyChild; 50 friend class PRemoteWorkerChild; 51 friend class ServiceWorkerOp; 52 friend class SharedWorkerOp; 53 54 ~RemoteWorkerChild(); 55 56 public: 57 // Note that all IPC-using methods must only be invoked on the 58 // RemoteWorkerService thread which the inherited 59 // IProtocol::GetActorEventTarget() will return for us. 60 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteWorkerChild, final) 61 62 explicit RemoteWorkerChild(const RemoteWorkerData& aData); 63 64 void ExecWorker( 65 const RemoteWorkerData& aData, 66 mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&& 67 aChildEp); 68 69 void ErrorPropagationOnMainThread(const WorkerErrorReport* aReport, 70 bool aIsErrorEvent); 71 72 void CSPViolationPropagationOnMainThread(const nsAString& aJSON); 73 74 void NotifyLock(bool aCreated); 75 76 void NotifyWebTransport(bool aCreated); 77 78 void FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter); 79 80 RefPtr<GenericNonExclusivePromise> GetTerminationPromise(); 81 82 RefPtr<GenericPromise> MaybeSendSetServiceWorkerSkipWaitingFlag(); 83 84 const nsTArray<uint64_t>& WindowIDs() const { return mWindowIDs; } 85 86 void SetIsThawing(const bool aIsThawing) { mIsThawing = aIsThawing; } 87 bool IsThawing() const { return mIsThawing; } 88 void PendRemoteWorkerOp(RefPtr<RemoteWorkerOp> aOp); 89 void RunAllPendingOpsOnMainThread(); 90 91 private: 92 class InitializeWorkerRunnable; 93 94 // The state of the WorkerPrivate as perceived by the owner on the main 95 // thread. All state transitions now happen on the main thread, but the 96 // Worker Launcher thread will consult the state and will directly append ops 97 // to the Pending queue 98 DataMutex<RemoteWorkerState> mState; 99 100 const RefPtr<RemoteWorkerServiceKeepAlive> mServiceKeepAlive; 101 102 void ActorDestroy(ActorDestroyReason) override; 103 104 mozilla::ipc::IPCResult RecvExecOp(SharedWorkerOpArgs&& aOpArgs); 105 106 mozilla::ipc::IPCResult RecvExecServiceWorkerOp( 107 ServiceWorkerOpArgs&& aArgs, ExecServiceWorkerOpResolver&& aResolve); 108 109 already_AddRefed<PFetchEventOpProxyChild> AllocPFetchEventOpProxyChild( 110 const ParentToChildServiceWorkerFetchEventOpArgs& aArgs); 111 112 mozilla::ipc::IPCResult RecvPFetchEventOpProxyConstructor( 113 PFetchEventOpProxyChild* aActor, 114 const ParentToChildServiceWorkerFetchEventOpArgs& aArgs) override; 115 116 nsresult ExecWorkerOnMainThread( 117 RemoteWorkerData&& aData, 118 mozilla::ipc::Endpoint<PRemoteWorkerNonLifeCycleOpControllerChild>&& 119 aChildEp); 120 121 void ExceptionalErrorTransitionDuringExecWorker(); 122 123 void RequestWorkerCancellation(); 124 125 void InitializeOnWorker(); 126 127 void CreationSucceededOnAnyThread(); 128 129 void CreationFailedOnAnyThread(); 130 131 void CreationSucceededOrFailedOnAnyThread(bool aDidCreationSucceed); 132 133 // Cancels the worker if it has been started and ensures that we transition 134 // to the Terminated state once the worker has been terminated or we have 135 // ensured that it will never start. 136 void CloseWorkerOnMainThread(); 137 138 void ErrorPropagation(const ErrorValue& aValue); 139 140 void ErrorPropagationDispatch(nsresult aError); 141 142 // When the WorkerPrivate Cancellation lambda is invoked, it's possible that 143 // we have not yet advanced to running from pending, so we could be in either 144 // state. This method is expected to be called by the Workers' cancellation 145 // lambda and will obtain the lock and call the 146 // TransitionStateFromPendingToCanceled if appropriate. Otherwise it will 147 // directly move from the running state to the canceled state which does not 148 // require additional cleanup. 149 void OnWorkerCancellationTransitionStateFromPendingOrRunningToCanceled(); 150 // A helper used by the above method by the worker cancellation lambda if the 151 // the worker hasn't started running, or in exceptional cases where we bail 152 // out of the ExecWorker method early. The caller must be holding the lock 153 // (in order to pass in the state). 154 void TransitionStateFromPendingToCanceled(RemoteWorkerState& aState); 155 void TransitionStateFromCanceledToKilled(); 156 157 void TransitionStateToRunning(); 158 159 void TransitionStateToTerminated(); 160 161 void TransitionStateToTerminated(RemoteWorkerState& aState); 162 163 void CancelAllPendingOps(RemoteWorkerState& aState); 164 165 void MaybeStartOp(RefPtr<RemoteWorkerOp>&& aOp); 166 167 const bool mIsServiceWorker; 168 169 // Touched on main-thread only. 170 nsTArray<uint64_t> mWindowIDs; 171 172 struct LauncherBoundData { 173 MozPromiseHolder<GenericNonExclusivePromise> mTerminationPromise; 174 // Flag to ensure we report creation at most once. This could be cleaned up 175 // further. 176 bool mDidSendCreated = false; 177 }; 178 179 ThreadBound<LauncherBoundData> mLauncherData; 180 181 // Thaw operation holds mState.lock. It means other operations will be blocked 182 // until mState.lock is released. However, Thaw operation is blocked by 183 // RemoteWorkerDebugger registration that needs WorkerLauncher thread to send 184 // IPC to continue the registration on the parent process. If a RemoteWorkerOp 185 // is received on WorkerLauncher thread when the RemoteWorker is thawing, a 186 // deadlock could be happen between WorkerLauncher thread and RemoteWorker's 187 // parent thread. So mIsThawing and mPendingOps are introduced to avoid the 188 // deadlock by pending the operations when RemoteWorker is thawing. 189 // 190 // Note that these could be removed once RemoteWorkerChild off-main-thread 191 // done since the RemoteWorker's parent thread will be WorkerLauncher thread. 192 // And it means when executing WorkerPrivate::Thaw on WorkerLauncher thread, 193 // it is impossible to handle the IPC callback on WorkerLauncher thread at the 194 // same time. 195 Atomic<bool> mIsThawing{false}; 196 DataMutex<nsTArray<RefPtr<RemoteWorkerOp>>> mPendingOps; 197 }; 198 199 } // namespace mozilla::dom 200 201 #endif // mozilla_dom_RemoteWorkerChild_h