diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 2bcb979f7afc..01f134cddc2e 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3738,8 +3738,8 @@ ContentParent::GetInterface(const nsIID& aIID, void** aResult) { } mozilla::ipc::IPCResult ContentParent::RecvInitBackground( - Endpoint&& aEndpoint) { - if (!BackgroundParent::Alloc(this, std::move(aEndpoint))) { + Endpoint&& aEndpoint) { + if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint))) { NS_WARNING("BackgroundParent::Alloc failed"); } diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 842e23a891c5..7f3cd69c1ade 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -917,7 +917,7 @@ class ContentParent final const nsACString& aContentProcessType); mozilla::ipc::IPCResult RecvInitBackground( - Endpoint&& aEndpoint); + Endpoint&& aEndpoint); mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport); mozilla::ipc::IPCResult RecvAddPerformanceMetrics( diff --git a/dom/ipc/ContentProcess.cpp b/dom/ipc/ContentProcess.cpp index 3ffeccb06270..f9c3ee788b65 100644 --- a/dom/ipc/ContentProcess.cpp +++ b/dom/ipc/ContentProcess.cpp @@ -171,6 +171,7 @@ bool ContentProcess::Init(int aArgc, char* aArgv[]) { // Do this as early as possible to get the parent process to initialize the // background thread since we'll likely need database information very soon. mozilla::ipc::BackgroundChild::Startup(); + mozilla::ipc::BackgroundChild::InitContentStarter(&mContent); return true; } diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 7516fa729366..cb09e6d0af0f 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -4,7 +4,7 @@ * 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 protocol PBackground; +include protocol PBackgroundStarter; include protocol PBrowser; include protocol PCompositorManager; include protocol PContentPermissionRequest; @@ -1021,7 +1021,7 @@ parent: async RemoveFromBFCache(MaybeDiscardedBrowsingContext aContext); - async InitBackground(Endpoint aEndpoint); + async InitBackground(Endpoint aEndpoint); async CreateGMPService(); diff --git a/dom/localstorage/LSObject.cpp b/dom/localstorage/LSObject.cpp index 9d0a9895d4e9..2a3cbf8335db 100644 --- a/dom/localstorage/LSObject.cpp +++ b/dom/localstorage/LSObject.cpp @@ -517,8 +517,7 @@ LSRequestChild* LSObject::StartRequest(nsIEventTarget* aMainEventTarget, mozilla::ipc::PBackgroundChild* backgroundActor = XRE_IsParentProcess() - ? mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread( - aMainEventTarget) + ? mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread() : mozilla::ipc::BackgroundChild::GetForCurrentThread(); if (NS_WARN_IF(!backgroundActor)) { return nullptr; diff --git a/ipc/glue/BackgroundChild.h b/ipc/glue/BackgroundChild.h index 9828447ae39e..b85b6d3ca39e 100644 --- a/ipc/glue/BackgroundChild.h +++ b/ipc/glue/BackgroundChild.h @@ -16,6 +16,7 @@ namespace mozilla { namespace dom { class BlobImpl; +class ContentChild; class ContentParent; class ContentProcess; @@ -24,12 +25,14 @@ class ContentProcess; namespace net { class SocketProcessChild; +class SocketProcessBridgeChild; } // namespace net namespace ipc { class PBackgroundChild; +class PBackgroundStarterChild; // This class allows access to the PBackground protocol. PBackground allows // communication between any thread (in the parent or a child process) and a @@ -53,6 +56,10 @@ class PBackgroundChild; // // The PBackgroundChild actor and all its sub-protocol actors will be // automatically destroyed when its designated thread completes. +// +// Init{Content,Socket,SocketBridge}Starter must be called on the main thread +// with an actor bridging to the relevant target process type before these +// methods can be used. class BackgroundChild final { friend class mozilla::dom::ContentParent; friend class mozilla::dom::ContentProcess; @@ -65,19 +72,26 @@ class BackgroundChild final { static PBackgroundChild* GetForCurrentThread(); // See above. - static PBackgroundChild* GetOrCreateForCurrentThread( - nsIEventTarget* aMainEventTarget = nullptr); + static PBackgroundChild* GetOrCreateForCurrentThread(); + + // See above. + static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(); + + // See above. + static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(); // See above. static void CloseForCurrentThread(); // See above. - static PBackgroundChild* GetOrCreateSocketActorForCurrentThread( - nsIEventTarget* aMainEventTarget = nullptr); + static void InitContentStarter(mozilla::dom::ContentChild* aContent); // See above. - static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread( - nsIEventTarget* aMainEventTarget = nullptr); + static void InitSocketStarter(mozilla::net::SocketProcessChild* aSocket); + + // See above. + static void InitSocketBridgeStarter( + mozilla::net::SocketProcessBridgeChild* aSocketBridge); private: // Only called by this class's friends. diff --git a/ipc/glue/BackgroundImpl.cpp b/ipc/glue/BackgroundImpl.cpp index a3313f7d6a22..5daef682289b 100644 --- a/ipc/glue/BackgroundImpl.cpp +++ b/ipc/glue/BackgroundImpl.cpp @@ -9,6 +9,7 @@ #include "BackgroundChildImpl.h" #include "BackgroundParentImpl.h" +#include "MainThreadUtils.h" #include "base/process_util.h" #include "base/task.h" #include "FileDescriptor.h" @@ -28,7 +29,10 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRef.h" +#include "mozilla/ipc/BackgroundStarterChild.h" +#include "mozilla/ipc/BackgroundStarterParent.h" #include "mozilla/ipc/Endpoint.h" +#include "mozilla/ipc/PBackgroundStarter.h" #include "mozilla/ipc/ProtocolTypes.h" #include "mozilla/net/SocketProcessChild.h" #include "mozilla/net/SocketProcessBridgeChild.h" @@ -77,32 +81,30 @@ class ChildImpl; // Utility Functions // ----------------------------------------------------------------------------- -void AssertIsInMainProcess() { MOZ_ASSERT(XRE_IsParentProcess()); } - void AssertIsInMainOrSocketProcess() { MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess()); } void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); } -void AssertIsNotOnMainThread() { THREADSAFETY_ASSERT(!NS_IsMainThread()); } - // ----------------------------------------------------------------------------- // ParentImpl Declaration // ----------------------------------------------------------------------------- class ParentImpl final : public BackgroundParentImpl { + friend class ChildImpl; friend class mozilla::ipc::BackgroundParent; + friend class mozilla::ipc::BackgroundStarterParent; private: class ShutdownObserver; - class CreateActorHelper; struct MOZ_STACK_CLASS TimerCallbackClosure { nsIThread* mThread; - nsTArray* mLiveActors; + nsTArray* mLiveActors; - TimerCallbackClosure(nsIThread* aThread, nsTArray* aLiveActors) + TimerCallbackClosure(nsIThread* aThread, + nsTArray* aLiveActors) : mThread(aThread), mLiveActors(aLiveActors) { AssertIsInMainOrSocketProcess(); AssertIsOnMainThread(); @@ -121,7 +123,7 @@ class ParentImpl final : public BackgroundParentImpl { // This is created and destroyed on the main thread but only modified on the // background thread. It is specific to each instance of sBackgroundThread. - static nsTArray* sLiveActorsForBackgroundThread; + static nsTArray* sLiveActorsForBackgroundThread; // This is only modified on the main thread. static StaticRefPtr sShutdownTimer; @@ -130,10 +132,11 @@ class ParentImpl final : public BackgroundParentImpl { // work during shutdown. static Atomic sBackgroundPRThread; - // This is only modified on the main thread. It maintains a count of live - // actors so that the background thread can be shut down when it is no longer - // needed. - static uint64_t sLiveActorCount; + // Maintains a count of live actors so that the background thread can be shut + // down when it is no longer needed. + // May be incremented on either the background thread (by an existing actor) + // or on the main thread, but must be decremented on the main thread. + static Atomic sLiveActorCount; // This is only modified on the main thread. It is true after the shutdown // observer is registered and is never unset thereafter. @@ -148,7 +151,7 @@ class ParentImpl final : public BackgroundParentImpl { // Set when the actor is opened successfully and used to handle shutdown // hangs. Only touched on the background thread. - nsTArray* mLiveActorArray; + nsTArray* mLiveActorArray; // Set at construction to indicate whether this parent actor corresponds to a // child actor in another process or to a child actor from a different thread @@ -160,9 +163,6 @@ class ParentImpl final : public BackgroundParentImpl { bool mActorDestroyed; public: - static already_AddRefed CreateActorForSameProcess( - nsIEventTarget* aMainEventTarget); - static bool IsOnBackgroundThread() { return PR_GetCurrentThread() == sBackgroundPRThread; } @@ -171,10 +171,9 @@ class ParentImpl final : public BackgroundParentImpl { THREADSAFETY_ASSERT(IsOnBackgroundThread()); } - // `ParentImpl` instances are created and need to be deleted on the main - // thread, despite IPC controlling them on a background thread. Use - // `_WITH_DELETE_ON_MAIN_THREAD` to force destruction to occur on the desired - // thread. + // `ParentImpl` instances need to be deleted on the main thread, despite IPC + // controlling them on a background thread. Use `_WITH_DELETE_ON_MAIN_THREAD` + // to force destruction to occur on the desired thread. NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(ParentImpl, override) @@ -196,12 +195,9 @@ class ParentImpl final : public BackgroundParentImpl { static uint64_t GetChildID(PBackgroundParent* aBackgroundActor); // Forwarded from BackgroundParent. - static bool GetLiveActorArray(PBackgroundParent* aBackgroundActor, - nsTArray& aLiveActorArray); - - // Forwarded from BackgroundParent. - static bool Alloc(ContentParent* aContent, - Endpoint&& aEndpoint); + static bool AllocStarter(ContentParent* aContent, + Endpoint&& aEndpoint, + bool aCrossProcess = true); static bool CreateBackgroundThread(); @@ -209,28 +205,20 @@ class ParentImpl final : public BackgroundParentImpl { static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure); - // For same-process actors. - ParentImpl() - : mLiveActorArray(nullptr), - mIsOtherProcessActor(false), - mActorDestroyed(false) { - AssertIsInMainProcess(); - AssertIsOnMainThread(); - } - - // For other-process actors. - // NOTE: ParentImpl could be used in 3 cases below. - // 1. Between parent process and content process. - // 2. Between socket process and content process. - // 3. Between parent process and socket process. - // |mContent| should be not null for case 1. For case 2 and 3, it's null. - explicit ParentImpl(ContentParent* aContent) - : mContent(aContent), + // NOTE: ParentImpl could be used in 4 cases below. + // 1. Within the parent process. + // 2. Between parent process and content process. + // 3. Between socket process and content process. + // 4. Between parent process and socket process. + // |aContent| should be not null for case 2. For cases 1, 3 and 4, it's null. + explicit ParentImpl(already_AddRefed&& aContent, + bool aIsOtherProcessActor) + : mContent(std::move(aContent)), mLiveActorArray(nullptr), - mIsOtherProcessActor(true), + mIsOtherProcessActor(aIsOtherProcessActor), mActorDestroyed(false) { MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess()); - AssertIsOnMainThread(); + MOZ_ASSERT_IF(!aIsOtherProcessActor, XRE_IsParentProcess()); } ~ParentImpl() { @@ -241,7 +229,7 @@ class ParentImpl final : public BackgroundParentImpl { void MainThreadActorDestroy(); - void SetLiveActorArray(nsTArray* aLiveActorArray) { + void SetLiveActorArray(nsTArray* aLiveActorArray) { AssertIsInMainOrSocketProcess(); AssertIsOnBackgroundThread(); MOZ_ASSERT(aLiveActorArray); @@ -264,6 +252,7 @@ class ParentImpl final : public BackgroundParentImpl { class ChildImpl final : public BackgroundChildImpl { friend class mozilla::ipc::BackgroundChild; friend class mozilla::ipc::BackgroundChildImpl; + friend class mozilla::ipc::BackgroundStarterChild; typedef base::ProcessId ProcessId; typedef mozilla::ipc::Transport Transport; @@ -271,8 +260,6 @@ class ChildImpl final : public BackgroundChildImpl { class ShutdownObserver; public: - class SendInitBackgroundRunnable; - struct ThreadLocalInfo { ThreadLocalInfo() #ifdef DEBUG @@ -282,7 +269,6 @@ class ChildImpl final : public BackgroundChildImpl { } RefPtr mActor; - RefPtr mSendInitBackgroundRunnable; UniquePtr mConsumerThreadLocal; #ifdef DEBUG bool mClosed; @@ -303,10 +289,7 @@ class ChildImpl final : public BackgroundChildImpl { using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int, nsIEventTarget*, ChildImpl**); - constexpr explicit ThreadInfoWrapper(ActorCreateFunc aFunc) - : mThreadLocalIndex(kBadThreadLocalIndex), - mMainThreadInfo(nullptr), - mCreateActorFunc(aFunc) {} + ThreadInfoWrapper() = default; void Startup() { MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex, @@ -331,6 +314,24 @@ class ChildImpl final : public BackgroundChildImpl { return; } + nsCOMPtr starterQueue; + { + auto lock = mStarterInfo.Lock(); + starterQueue = lock->mTaskQueue.forget(); + lock->mOtherPid = base::kInvalidProcessId; + } + + if (starterQueue) { + starterQueue->Dispatch( + NS_NewRunnableFunction("PBackgroundStarterChild Close", [this] { + MOZ_ASSERT(mStarter); + if (mStarter) { + mStarter->Close(); + } + mStarter = nullptr; + })); + } + ThreadLocalInfo* threadLocalInfo; #ifdef DEBUG threadLocalInfo = @@ -350,6 +351,40 @@ class ChildImpl final : public BackgroundChildImpl { } } + template + void InitStarter(Actor* aActor) { + AssertIsOnMainThread(); + + // Create a pair of endpoints and send them to the other process. + Endpoint parent; + Endpoint child; + MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints( + aActor->OtherPid(), base::GetCurrentProcId(), &parent, &child)); + MOZ_ALWAYS_TRUE(aActor->SendInitBackground(std::move(parent))); + + InitStarter(std::move(child)); + } + + void InitStarter(Endpoint&& aEndpoint) { + AssertIsOnMainThread(); + + base::ProcessId otherPid = aEndpoint.OtherPid(); + nsCOMPtr taskQueue; + MOZ_ALWAYS_SUCCEEDS(NS_CreateBackgroundTaskQueue( + "PBackgroundStarter Queue", getter_AddRefs(taskQueue))); + taskQueue->Dispatch(NS_NewRunnableFunction( + "PBackgroundStarterChild Init", + [this, endpoint = std::move(aEndpoint)]() mutable { + mStarter = new BackgroundStarterChild(); + MOZ_ALWAYS_TRUE(endpoint.Bind(mStarter)); + })); + + auto lock = mStarterInfo.Lock(); + MOZ_RELEASE_ASSERT(!lock->mTaskQueue); + lock->mTaskQueue = taskQueue; + lock->mOtherPid = otherPid; + } + void CloseForCurrentThread() { MOZ_ASSERT(!NS_IsMainThread()); @@ -357,7 +392,7 @@ class ChildImpl final : public BackgroundChildImpl { return; } - auto threadLocalInfo = + auto* threadLocalInfo = static_cast(PR_GetThreadPrivate(mThreadLocalIndex)); if (!threadLocalInfo) { @@ -375,10 +410,7 @@ class ChildImpl final : public BackgroundChildImpl { MOZ_ASSERT(status == PR_SUCCESS); } - PBackgroundChild* GetOrCreateForCurrentThread( - nsIEventTarget* aMainEventTarget) { - MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget); - + PBackgroundChild* GetOrCreateForCurrentThread() { // Processes can be told to do final CC's during shutdown even though // they never finished starting (and thus call this), because they // hadn't gotten far enough to call Startup() before shutdown began. @@ -390,10 +422,10 @@ class ChildImpl final : public BackgroundChildImpl { return nullptr; } - auto threadLocalInfo = NS_IsMainThread() - ? mMainThreadInfo - : static_cast( - PR_GetThreadPrivate(mThreadLocalIndex)); + auto* threadLocalInfo = NS_IsMainThread() + ? mMainThreadInfo + : static_cast( + PR_GetThreadPrivate(mThreadLocalIndex)); if (!threadLocalInfo) { auto newInfo = MakeUnique(); @@ -411,28 +443,75 @@ class ChildImpl final : public BackgroundChildImpl { threadLocalInfo = newInfo.release(); } - PBackgroundChild* bgChild = - GetFromThreadInfo(aMainEventTarget, threadLocalInfo); - if (bgChild) { - return bgChild; + if (threadLocalInfo->mActor) { + return threadLocalInfo->mActor; } - RefPtr actor; - mCreateActorFunc(threadLocalInfo, mThreadLocalIndex, aMainEventTarget, - getter_AddRefs(actor)); - return actor; + base::ProcessId otherPid = base::kInvalidProcessId; + nsCOMPtr starterQueue; + { + auto lock = mStarterInfo.Lock(); + otherPid = lock->mOtherPid; + starterQueue = lock->mTaskQueue; + } + + if (!starterQueue) { + CRASH_IN_CHILD_PROCESS("No BackgroundStarterChild"); + return nullptr; + } + + Endpoint parent; + Endpoint child; + nsresult rv; + rv = PBackground::CreateEndpoints(otherPid, base::GetCurrentProcId(), + &parent, &child); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to create top level actor!"); + return nullptr; + } + + RefPtr strongActor = new ChildImpl(); + if (!child.Bind(strongActor)) { + CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!"); + return nullptr; + } + strongActor->SetActorAlive(); + threadLocalInfo->mActor = strongActor; + + // Dispatch to the background task queue to create the relevant actor in + // the remote process. + starterQueue->Dispatch(NS_NewRunnableFunction( + "PBackground GetOrCreateForCurrentThread", + [this, endpoint = std::move(parent)]() mutable { + if (!mStarter || + !mStarter->SendInitBackground(std::move(endpoint))) { + NS_WARNING("Failed to create toplevel actor"); + } + })); + return strongActor; } private: // This is only modified on the main thread. It is the thread-local index // that we use to store the BackgroundChild for each thread. - unsigned int mThreadLocalIndex; + unsigned int mThreadLocalIndex = kBadThreadLocalIndex; // On the main thread, we store TLS in this global instead of in // mThreadLocalIndex. That way, cooperative main threads all share the same // thread info. - ThreadLocalInfo* mMainThreadInfo; - ActorCreateFunc mCreateActorFunc; + ThreadLocalInfo* mMainThreadInfo = nullptr; + + // Only modified on the starter task queue. + StaticRefPtr mStarter; + + // The starter task queue and other process ID which will be used to launch + // processes of this type. Only modified on the main thread, but may be read + // by any thread wanting to start background actors. + struct StarterInfo { + base::ProcessId mOtherPid = base::kInvalidProcessId; + StaticRefPtr mTaskQueue; + }; + StaticDataMutex mStarterInfo{"mStarterInfo"}; }; // For PBackground between parent and content process. @@ -509,27 +588,30 @@ class ChildImpl final : public BackgroundChildImpl { // Forwarded from BackgroundChild. static PBackgroundChild* GetForCurrentThread(); - // Helper function for getting PBackgroundChild from thread info. - static PBackgroundChild* GetFromThreadInfo(nsIEventTarget* aMainEventTarget, - ThreadLocalInfo* aThreadLocalInfo); + // Forwarded from BackgroundChild. + static PBackgroundChild* GetOrCreateForCurrentThread(); // Forwarded from BackgroundChild. - static PBackgroundChild* GetOrCreateForCurrentThread( - nsIEventTarget* aMainEventTarget); + static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(); // Forwarded from BackgroundChild. - static PBackgroundChild* GetOrCreateSocketActorForCurrentThread( - nsIEventTarget* aMainEventTarget); - - // Forwarded from BackgroundChild. - static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread( - nsIEventTarget* aMainEventTarget); + static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(); static void CloseForCurrentThread(); // Forwarded from BackgroundChildImpl. static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread(); + // Forwarded from BackgroundChild. + static void InitContentStarter(mozilla::dom::ContentChild* aContent); + + // Forwarded from BackgroundChild. + static void InitSocketStarter(mozilla::net::SocketProcessChild* aSocket); + + // Forwarded from BackgroundChild. + static void InitSocketBridgeStarter( + mozilla::net::SocketProcessBridgeChild* aSocketBridge); + static void ThreadLocalDestructor(void* aThreadLocal); // This class is reference counted. @@ -554,35 +636,6 @@ class ParentImpl::ShutdownObserver final : public nsIObserver { ~ShutdownObserver() { AssertIsOnMainThread(); } }; -class ParentImpl::CreateActorHelper final : public Runnable { - mozilla::Monitor mMonitor; - RefPtr mParentActor; - nsCOMPtr mThread; - nsresult mMainThreadResultCode; - bool mWaiting; - - public: - explicit CreateActorHelper() - : Runnable("Background::ParentImpl::CreateActorHelper"), - mMonitor("CreateActorHelper::mMonitor"), - mMainThreadResultCode(NS_OK), - mWaiting(true) { - AssertIsInMainOrSocketProcess(); - AssertIsNotOnMainThread(); - } - - nsresult BlockAndGetResults(nsIEventTarget* aMainEventTarget, - RefPtr& aParentActor, - nsCOMPtr& aThread); - - private: - ~CreateActorHelper() { AssertIsInMainOrSocketProcess(); } - - nsresult RunOnMainThread(); - - NS_DECL_NSIRUNNABLE -}; - // ----------------------------------------------------------------------------- // ChildImpl Helper Declarations // ----------------------------------------------------------------------------- @@ -598,47 +651,6 @@ class ChildImpl::ShutdownObserver final : public nsIObserver { ~ShutdownObserver() { AssertIsOnMainThread(); } }; -class ChildImpl::SendInitBackgroundRunnable final : public DiscardableRunnable { - nsCOMPtr mOwningEventTarget; - RefPtr mWorkerRef; - Endpoint mParent; - mozilla::Mutex mMutex; - bool mSentInitBackground; - std::function&& aParent)> mSendInitfunc; - unsigned int mThreadLocalIndex; - - public: - static already_AddRefed Create( - Endpoint&& aParent, - std::function&& aParent)>&& aFunc, - unsigned int aThreadLocalIndex); - - void ClearEventTarget() { - mWorkerRef = nullptr; - - mozilla::MutexAutoLock lock(mMutex); - mOwningEventTarget = nullptr; - } - - private: - explicit SendInitBackgroundRunnable( - Endpoint&& aParent, - std::function&& aParent)>&& aFunc, - unsigned int aThreadLocalIndex) - : DiscardableRunnable( - "Background::ChildImpl::SendInitBackgroundRunnable"), - mOwningEventTarget(GetCurrentSerialEventTarget()), - mParent(std::move(aParent)), - mMutex("SendInitBackgroundRunnable::mMutex"), - mSentInitBackground(false), - mSendInitfunc(std::move(aFunc)), - mThreadLocalIndex(aThreadLocalIndex) {} - - ~SendInitBackgroundRunnable() = default; - - NS_DECL_NSIRUNNABLE -}; - } // namespace namespace mozilla { @@ -683,16 +695,9 @@ uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) { } // static -bool BackgroundParent::GetLiveActorArray( - PBackgroundParent* aBackgroundActor, - nsTArray& aLiveActorArray) { - return ParentImpl::GetLiveActorArray(aBackgroundActor, aLiveActorArray); -} - -// static -bool BackgroundParent::Alloc(ContentParent* aContent, - Endpoint&& aEndpoint) { - return ParentImpl::Alloc(aContent, std::move(aEndpoint)); +bool BackgroundParent::AllocStarter( + ContentParent* aContent, Endpoint&& aEndpoint) { + return ParentImpl::AllocStarter(aContent, std::move(aEndpoint)); } // ----------------------------------------------------------------------------- @@ -708,23 +713,19 @@ PBackgroundChild* BackgroundChild::GetForCurrentThread() { } // static -PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread( - nsIEventTarget* aMainEventTarget) { - return ChildImpl::GetOrCreateForCurrentThread(aMainEventTarget); +PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread() { + return ChildImpl::GetOrCreateForCurrentThread(); } // static -PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread( - nsIEventTarget* aMainEventTarget) { - return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget); +PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread() { + return ChildImpl::GetOrCreateSocketActorForCurrentThread(); } // static PBackgroundChild* -BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread( - nsIEventTarget* aMainEventTarget) { - return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread( - aMainEventTarget); +BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread() { + return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(); } // static @@ -732,6 +733,22 @@ void BackgroundChild::CloseForCurrentThread() { ChildImpl::CloseForCurrentThread(); } +// static +void BackgroundChild::InitContentStarter(ContentChild* aContent) { + ChildImpl::InitContentStarter(aContent); +} + +// static +void BackgroundChild::InitSocketStarter(net::SocketProcessChild* aSocket) { + ChildImpl::InitSocketStarter(aSocket); +} + +// static +void BackgroundChild::InitSocketBridgeStarter( + net::SocketProcessBridgeChild* aSocketBridge) { + ChildImpl::InitSocketBridgeStarter(aSocketBridge); +} + // ----------------------------------------------------------------------------- // BackgroundChildImpl Public Methods // ----------------------------------------------------------------------------- @@ -748,13 +765,13 @@ BackgroundChildImpl::GetThreadLocalForCurrentThread() { StaticRefPtr ParentImpl::sBackgroundThread; -nsTArray* ParentImpl::sLiveActorsForBackgroundThread; +nsTArray* ParentImpl::sLiveActorsForBackgroundThread; StaticRefPtr ParentImpl::sShutdownTimer; Atomic ParentImpl::sBackgroundPRThread; -uint64_t ParentImpl::sLiveActorCount = 0; +Atomic ParentImpl::sLiveActorCount; bool ParentImpl::sShutdownObserverRegistered = false; @@ -764,238 +781,11 @@ bool ParentImpl::sShutdownHasStarted = false; // ChildImpl Static Members // ----------------------------------------------------------------------------- -static void ParentContentActorCreateFunc( - ChildImpl::ThreadLocalInfo* aThreadLocalInfo, - unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget, - ChildImpl** aOutput) { - if (XRE_IsParentProcess()) { - RefPtr strongActor = - ParentImpl::CreateActorForSameProcess(aMainEventTarget); - if (NS_WARN_IF(!strongActor)) { - return; - } +ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo; - aThreadLocalInfo->mActor = strongActor; - strongActor.forget(aOutput); - return; - } +ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo; - RefPtr content = ContentChild::GetSingleton(); - MOZ_ASSERT(content); - - if (content->IsShuttingDown()) { - // The transport for ContentChild is shut down and can't be used to open - // PBackground. - return; - } - - Endpoint parent; - Endpoint child; - nsresult rv; - rv = PBackground::CreateEndpoints(content->OtherPid(), - base::GetCurrentProcId(), &parent, &child); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to create top level actor!"); - return; - } - - RefPtr runnable; - if (!NS_IsMainThread()) { - runnable = ChildImpl::SendInitBackgroundRunnable::Create( - std::move(parent), - [](Endpoint&& aParent) { - RefPtr content = ContentChild::GetSingleton(); - MOZ_ASSERT(content); - - if (!content->SendInitBackground(std::move(aParent))) { - NS_WARNING("Failed to create top level actor!"); - } - }, - aThreadLocalIndex); - if (!runnable) { - return; - } - } - - RefPtr strongActor = new ChildImpl(); - - if (!child.Bind(strongActor)) { - CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!"); - - return; - } - - strongActor->SetActorAlive(); - - if (NS_IsMainThread()) { - if (!content->SendInitBackground(std::move(parent))) { - NS_WARNING("Failed to create top level actor!"); - return; - } - } else { - if (aMainEventTarget) { - MOZ_ALWAYS_SUCCEEDS( - aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)); - } else { - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); - } - - aThreadLocalInfo->mSendInitBackgroundRunnable = runnable; - } - - aThreadLocalInfo->mActor = strongActor; - strongActor.forget(aOutput); -} - -ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo( - ParentContentActorCreateFunc); - -static void SocketContentActorCreateFunc( - ChildImpl::ThreadLocalInfo* aThreadLocalInfo, - unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget, - ChildImpl** aOutput) { - RefPtr bridgeChild = - SocketProcessBridgeChild::GetSingleton(); - - if (!bridgeChild || bridgeChild->IsShuttingDown()) { - // The transport for SocketProcessBridgeChild is shut down - // and can't be used to open PBackground. - return; - } - - Endpoint parent; - Endpoint child; - nsresult rv; - rv = PBackground::CreateEndpoints(bridgeChild->SocketProcessPid(), - base::GetCurrentProcId(), &parent, &child); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to create top level actor!"); - return; - } - - RefPtr runnable; - if (!NS_IsMainThread()) { - runnable = ChildImpl::SendInitBackgroundRunnable::Create( - std::move(parent), - [](Endpoint&& aParent) { - RefPtr bridgeChild = - SocketProcessBridgeChild::GetSingleton(); - - if (!bridgeChild->SendInitBackground(std::move(aParent))) { - NS_WARNING("Failed to create top level actor!"); - } - }, - aThreadLocalIndex); - if (!runnable) { - return; - } - } - - RefPtr strongActor = new ChildImpl(); - - if (!child.Bind(strongActor)) { - CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!"); - - return; - } - - strongActor->SetActorAlive(); - - if (NS_IsMainThread()) { - if (!bridgeChild->SendInitBackground(std::move(parent))) { - NS_WARNING("Failed to create top level actor!"); - // Need to close the IPC channel before ChildImpl getting deleted. - strongActor->Close(); - strongActor->AssertActorDestroyed(); - return; - } - } else { - if (aMainEventTarget) { - MOZ_ALWAYS_SUCCEEDS( - aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)); - } else { - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); - } - - aThreadLocalInfo->mSendInitBackgroundRunnable = runnable; - } - - aThreadLocalInfo->mActor = strongActor; - strongActor.forget(aOutput); -} - -ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo( - SocketContentActorCreateFunc); - -static void SocketParentActorCreateFunc( - ChildImpl::ThreadLocalInfo* aThreadLocalInfo, - unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget, - ChildImpl** aOutput) { - SocketProcessChild* socketChild = SocketProcessChild::GetSingleton(); - - if (!socketChild || socketChild->IsShuttingDown()) { - return; - } - - Endpoint parent; - Endpoint child; - nsresult rv; - rv = PBackground::CreateEndpoints(socketChild->OtherPid(), - base::GetCurrentProcId(), &parent, &child); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to create top level actor!"); - return; - } - - RefPtr runnable; - if (!NS_IsMainThread()) { - runnable = ChildImpl::SendInitBackgroundRunnable::Create( - std::move(parent), - [](Endpoint&& aParent) { - SocketProcessChild* socketChild = SocketProcessChild::GetSingleton(); - MOZ_ASSERT(socketChild); - - if (!socketChild->SendInitBackground(std::move(aParent))) { - MOZ_CRASH("Failed to create top level actor!"); - } - }, - aThreadLocalIndex); - if (!runnable) { - return; - } - } - - RefPtr strongActor = new ChildImpl(); - - if (!child.Bind(strongActor)) { - CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!"); - return; - } - - strongActor->SetActorAlive(); - - if (NS_IsMainThread()) { - if (!socketChild->SendInitBackground(std::move(parent))) { - NS_WARNING("Failed to create top level actor!"); - return; - } - } else { - if (aMainEventTarget) { - MOZ_ALWAYS_SUCCEEDS( - aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)); - } else { - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); - } - - aThreadLocalInfo->mSendInitBackgroundRunnable = runnable; - } - - aThreadLocalInfo->mActor = strongActor; - strongActor.forget(aOutput); -} - -ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo( - SocketParentActorCreateFunc); +ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo; bool ChildImpl::sShutdownHasStarted = false; @@ -1030,6 +820,8 @@ already_AddRefed ParentImpl::GetContentParent( // it for us. This is safe since we are guaranteed that our AddRef runnable // will run before the reference we hand out can be released, and the // ContentParent can't die as long as the existing reference is maintained. + // + // XXX: Why can't we use `nsMainThreadPtrHandle` here instead? MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod( "ContentParent::AddRef", actor->mContent, &ContentParent::AddRef))); } @@ -1073,36 +865,12 @@ uint64_t ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor) { } // static -bool ParentImpl::GetLiveActorArray( - PBackgroundParent* aBackgroundActor, - nsTArray& aLiveActorArray) { - AssertIsOnBackgroundThread(); - MOZ_ASSERT(aBackgroundActor); - MOZ_ASSERT(aLiveActorArray.IsEmpty()); - - auto actor = static_cast(aBackgroundActor); - if (actor->mActorDestroyed) { - MOZ_ASSERT(false, - "GetLiveActorArray called after ActorDestroy was called!"); - return false; - } - - if (!actor->mLiveActorArray) { - return true; - } - - for (ParentImpl* liveActor : *actor->mLiveActorArray) { - aLiveActorArray.AppendElement(liveActor); - } - - return true; -} - -// static -bool ParentImpl::Alloc(ContentParent* aContent, - Endpoint&& aEndpoint) { +bool ParentImpl::AllocStarter(ContentParent* aContent, + Endpoint&& aEndpoint, + bool aCrossProcess) { AssertIsInMainOrSocketProcess(); AssertIsOnMainThread(); + MOZ_ASSERT(aEndpoint.IsValid()); if (!sBackgroundThread && !CreateBackgroundThread()) { @@ -1110,29 +878,18 @@ bool ParentImpl::Alloc(ContentParent* aContent, return false; } - MOZ_ASSERT(sLiveActorsForBackgroundThread); - sLiveActorCount++; - RefPtr actor = new ParentImpl(aContent); + RefPtr actor = + new BackgroundStarterParent(aContent, aCrossProcess); if (NS_FAILED(sBackgroundThread->Dispatch(NS_NewRunnableFunction( - "Background::ParentImpl::ConnectActorRunnable", + "BackgroundStarterParent::ConnectActorRunnable", [actor = std::move(actor), endpoint = std::move(aEndpoint), liveActorArray = sLiveActorsForBackgroundThread]() mutable { MOZ_ASSERT(endpoint.IsValid()); - MOZ_ASSERT(liveActorArray); - // Transfer ownership to this thread. If Open() fails then we will - // release this reference in Destroy. - ParentImpl* actorTmp; - actor.forget(&actorTmp); - - if (!endpoint.Bind(actorTmp)) { - actorTmp->Destroy(); - return; - } - - actorTmp->SetLiveActorArray(liveActorArray); + MOZ_ALWAYS_TRUE(endpoint.Bind(actor)); + actor->SetLiveActorArray(liveActorArray); })))) { NS_WARNING("Failed to dispatch connect runnable!"); @@ -1143,64 +900,6 @@ bool ParentImpl::Alloc(ContentParent* aContent, return true; } -// static -already_AddRefed ParentImpl::CreateActorForSameProcess( - nsIEventTarget* aMainEventTarget) { - AssertIsInMainProcess(); - - RefPtr parentActor; - nsCOMPtr backgroundThread; - - if (NS_IsMainThread()) { - if (!sBackgroundThread && !CreateBackgroundThread()) { - NS_WARNING("Failed to create background thread!"); - return nullptr; - } - - MOZ_ASSERT(!sShutdownHasStarted); - - sLiveActorCount++; - - parentActor = new ParentImpl(); - backgroundThread = sBackgroundThread.get(); - } else { - RefPtr helper = new CreateActorHelper(); - - nsresult rv = helper->BlockAndGetResults(aMainEventTarget, parentActor, - backgroundThread); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - } - - RefPtr childActor = new ChildImpl(); - - MessageChannel* parentChannel = parentActor->GetIPCChannel(); - MOZ_ASSERT(parentChannel); - - if (!childActor->Open(parentChannel, backgroundThread, ChildSide)) { - NS_WARNING("Failed to open ChildImpl!"); - - // Can't release it here, we will release this reference in Destroy. - ParentImpl* actor; - parentActor.forget(&actor); - - actor->Destroy(); - - return nullptr; - } - - childActor->SetActorAlive(); - - // Make sure the parent knows it is same process. - parentActor->SetOtherProcessId(base::GetCurrentProcId()); - - // Now that Open() has succeeded transfer the ownership of the actors to IPDL. - Unused << parentActor.forget(); - - return childActor.forget(); -} - // static bool ParentImpl::CreateBackgroundThread() { AssertIsInMainOrSocketProcess(); @@ -1258,7 +957,7 @@ bool ParentImpl::CreateBackgroundThread() { sBackgroundThread = thread.forget(); - sLiveActorsForBackgroundThread = new nsTArray(1); + sLiveActorsForBackgroundThread = new nsTArray(1); if (!sShutdownTimer) { MOZ_ASSERT(newShutdownTimer); @@ -1283,7 +982,8 @@ void ParentImpl::ShutdownBackgroundThread() { nsCOMPtr thread = sBackgroundThread.get(); sBackgroundThread = nullptr; - UniquePtr> liveActors(sLiveActorsForBackgroundThread); + UniquePtr> liveActors( + sLiveActorsForBackgroundThread); sLiveActorsForBackgroundThread = nullptr; MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount); @@ -1333,20 +1033,21 @@ void ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) { // finished. sLiveActorCount++; - InvokeAsync(closure->mThread, __func__, - [liveActors = closure->mLiveActors]() { - MOZ_ASSERT(liveActors); + InvokeAsync( + closure->mThread, __func__, + [liveActors = closure->mLiveActors]() { + MOZ_ASSERT(liveActors); - if (!liveActors->IsEmpty()) { - // Copy the array since calling Close() could mutate the - // actual array. - nsTArray actorsToClose(liveActors->Clone()); - for (ParentImpl* actor : actorsToClose) { - actor->Close(); - } - } - return GenericPromise::CreateAndResolve(true, __func__); - }) + if (!liveActors->IsEmpty()) { + // Copy the array since calling Close() could mutate the + // actual array. + nsTArray actorsToClose(liveActors->Clone()); + for (IToplevelProtocol* actor : actorsToClose) { + actor->Close(); + } + } + return GenericPromise::CreateAndResolve(true, __func__); + }) ->Then(GetCurrentSerialEventTarget(), __func__, []() { MOZ_ASSERT(sLiveActorCount); sLiveActorCount--; @@ -1425,65 +1126,85 @@ ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic, return NS_OK; } -nsresult ParentImpl::CreateActorHelper::BlockAndGetResults( - nsIEventTarget* aMainEventTarget, RefPtr& aParentActor, - nsCOMPtr& aThread) { - AssertIsNotOnMainThread(); - - if (aMainEventTarget) { - MOZ_ALWAYS_SUCCEEDS(aMainEventTarget->Dispatch(this, NS_DISPATCH_NORMAL)); - } else { - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this)); - } - - mozilla::MonitorAutoLock lock(mMonitor); - while (mWaiting) { - lock.Wait(); - } - - if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) { - return mMainThreadResultCode; - } - - aParentActor = std::move(mParentActor); - aThread = std::move(mThread); - return NS_OK; +BackgroundStarterParent::BackgroundStarterParent(ContentParent* aContent, + bool aCrossProcess) + : mCrossProcess(aCrossProcess), mContent(aContent) { + AssertIsOnMainThread(); + AssertIsInMainOrSocketProcess(); + MOZ_ASSERT_IF(!mCrossProcess, !mContent); + MOZ_ASSERT_IF(!mCrossProcess, XRE_IsParentProcess()); } -nsresult ParentImpl::CreateActorHelper::RunOnMainThread() { - AssertIsOnMainThread(); +void BackgroundStarterParent::SetLiveActorArray( + nsTArray* aLiveActorArray) { + AssertIsInMainOrSocketProcess(); + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aLiveActorArray); + MOZ_ASSERT(!aLiveActorArray->Contains(this)); + MOZ_ASSERT(!mLiveActorArray); + MOZ_ASSERT_IF(!mCrossProcess, OtherPid() == base::GetCurrentProcId()); - if (!sBackgroundThread && !CreateBackgroundThread()) { - NS_WARNING("Failed to create background thread!"); - return NS_ERROR_FAILURE; - } - - MOZ_ASSERT(!sShutdownHasStarted); - - sLiveActorCount++; - - mParentActor = new ParentImpl(); - mThread = sBackgroundThread; - - return NS_OK; + mLiveActorArray = aLiveActorArray; + mLiveActorArray->AppendElement(this); } -NS_IMETHODIMP -ParentImpl::CreateActorHelper::Run() { - AssertIsOnMainThread(); +IPCResult BackgroundStarterParent::RecvInitBackground( + Endpoint&& aEndpoint) { + AssertIsOnBackgroundThread(); - nsresult rv = RunOnMainThread(); - if (NS_WARN_IF(NS_FAILED(rv))) { - mMainThreadResultCode = rv; + if (!aEndpoint.IsValid()) { + return IPC_FAIL(this, + "Cannot initialize PBackground with invalid endpoint"); } - mozilla::MonitorAutoLock lock(mMonitor); - MOZ_ASSERT(mWaiting); + if (mContent) { + // We need to hand out a reference to our ContentParent for the new + // ParentImpl actor, but we also need to keep the one we have. We can't call + // AddRef here because ContentParent is not threadsafe so instead we + // dispatch a runnable to the main thread to do it for us. This is safe + // since we are guaranteed that our AddRef runnable will run before the + // reference we hand out can be released, and the ContentParent can't die as + // long as the existing reference is maintained. + // + // XXX: Why can't we use `nsMainThreadPtrHandle` here? + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod( + "ContentParent::AddRef", mContent, &ContentParent::AddRef))); + } - mWaiting = false; - lock.Notify(); + ParentImpl* actor = new ParentImpl( + already_AddRefed(mContent.get()), mCrossProcess); - return NS_OK; + // Take a reference on this thread. If Open() fails then we will release this + // reference in Destroy. + NS_ADDREF(actor); + + ParentImpl::sLiveActorCount++; + + if (!aEndpoint.Bind(actor)) { + actor->Destroy(); + return IPC_OK(); + } + + if (mCrossProcess) { + actor->SetLiveActorArray(mLiveActorArray); + } + return IPC_OK(); +} + +void BackgroundStarterParent::ActorDestroy(ActorDestroyReason aReason) { + AssertIsOnBackgroundThread(); + + if (mLiveActorArray) { + MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this)); + mLiveActorArray = nullptr; + } + + // Make sure to decrement `sLiveActorCount` on the main thread. + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NS_NewRunnableFunction( + "BackgroundStarterParent::MainThreadDestroy", [self = RefPtr{this}] { + self->mContent = nullptr; + ParentImpl::sLiveActorCount--; + }))); } // ----------------------------------------------------------------------------- @@ -1507,6 +1228,19 @@ void ChildImpl::Startup() { nsresult rv = observerService->AddObserver( observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); + + // Initialize a starter actor to allow starting PBackground within the parent + // process. + if (XRE_IsParentProcess()) { + Endpoint parent; + Endpoint child; + MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints( + base::GetCurrentProcId(), base::GetCurrentProcId(), &parent, &child)); + + MOZ_ALWAYS_TRUE(ParentImpl::AllocStarter(nullptr, std::move(parent), + /* aCrossProcess */ false)); + sParentAndContentProcessThreadInfo.InitStarter(std::move(child)); + } } // static @@ -1539,59 +1273,19 @@ PBackgroundChild* ChildImpl::GetForCurrentThread() { } /* static */ -PBackgroundChild* ChildImpl::GetFromThreadInfo( - nsIEventTarget* aMainEventTarget, ThreadLocalInfo* aThreadLocalInfo) { - MOZ_ASSERT(aThreadLocalInfo); - - if (aThreadLocalInfo->mActor) { - RefPtr& runnable = - aThreadLocalInfo->mSendInitBackgroundRunnable; - - if (aMainEventTarget && runnable) { - // The SendInitBackgroundRunnable was already dispatched to the main - // thread to finish initialization of a new background child actor. - // However, the caller passed a custom main event target which indicates - // that synchronous blocking of the main thread is happening (done by - // creating a nested event target and spinning the event loop). - // It can happen that the SendInitBackgroundRunnable didn't have a chance - // to run before the synchronous blocking has occured. Unblocking of the - // main thread can depend on an IPC message received on this thread, so - // we have to dispatch the SendInitBackgroundRunnable to the custom main - // event target too, otherwise IPC will be only queueing messages on this - // thread. The runnable will run twice in the end, but that's a harmless - // race between the main and nested event queue of the main thread. - // There's a guard in the runnable implementation for calling - // SendInitBackground only once. - - MOZ_ALWAYS_SUCCEEDS( - aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)); - } - - return aThreadLocalInfo->mActor; - } - - return nullptr; +PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread() { + return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread(); } /* static */ -PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread( - nsIEventTarget* aMainEventTarget) { - return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread( - aMainEventTarget); +PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread() { + return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread(); } /* static */ -PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread( - nsIEventTarget* aMainEventTarget) { - return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread( - aMainEventTarget); -} - -/* static */ -PBackgroundChild* ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread( - nsIEventTarget* aMainEventTarget) { - return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread( - aMainEventTarget); +PBackgroundChild* +ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread() { + return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread(); } // static @@ -1629,6 +1323,22 @@ BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() { return threadLocalInfo->mConsumerThreadLocal.get(); } +// static +void ChildImpl::InitContentStarter(mozilla::dom::ContentChild* aContent) { + sParentAndContentProcessThreadInfo.InitStarter(aContent); +} + +// static +void ChildImpl::InitSocketStarter(mozilla::net::SocketProcessChild* aSocket) { + sSocketAndParentProcessThreadInfo.InitStarter(aSocket); +} + +// static +void ChildImpl::InitSocketBridgeStarter( + mozilla::net::SocketProcessBridgeChild* aSocketBridge) { + sSocketAndContentProcessThreadInfo.InitStarter(aSocketBridge); +} + // static void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) { auto threadLocalInfo = static_cast(aThreadLocal); @@ -1641,10 +1351,6 @@ void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) { threadLocalInfo->mActor->AssertActorDestroyed(); } - if (threadLocalInfo->mSendInitBackgroundRunnable) { - threadLocalInfo->mSendInitBackgroundRunnable->ClearEventTarget(); - } - delete threadLocalInfo; } } @@ -1672,73 +1378,3 @@ ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic, return NS_OK; } - -// static -already_AddRefed -ChildImpl::SendInitBackgroundRunnable::Create( - Endpoint&& aParent, - std::function&& aParent)>&& aFunc, - unsigned int aThreadLocalIndex) { - MOZ_ASSERT(!NS_IsMainThread()); - - RefPtr runnable = new SendInitBackgroundRunnable( - std::move(aParent), std::move(aFunc), aThreadLocalIndex); - - WorkerPrivate* workerPrivate = mozilla::dom::GetCurrentThreadWorkerPrivate(); - if (!workerPrivate) { - return runnable.forget(); - } - - workerPrivate->AssertIsOnWorkerThread(); - - runnable->mWorkerRef = StrongWorkerRef::Create( - workerPrivate, "ChildImpl::SendInitBackgroundRunnable"); - if (NS_WARN_IF(!runnable->mWorkerRef)) { - return nullptr; - } - - return runnable.forget(); -} - -NS_IMETHODIMP -ChildImpl::SendInitBackgroundRunnable::Run() { - if (NS_IsMainThread()) { - if (mSentInitBackground) { - return NS_OK; - } - - mSentInitBackground = true; - - mSendInitfunc(std::move(mParent)); - - nsCOMPtr owningEventTarget; - { - mozilla::MutexAutoLock lock(mMutex); - owningEventTarget = mOwningEventTarget; - } - - if (!owningEventTarget) { - return NS_OK; - } - - nsresult rv = owningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - return NS_OK; - } - - ClearEventTarget(); - - auto threadLocalInfo = - static_cast(PR_GetThreadPrivate(mThreadLocalIndex)); - - if (!threadLocalInfo) { - return NS_OK; - } - - threadLocalInfo->mSendInitBackgroundRunnable = nullptr; - - return NS_OK; -} diff --git a/ipc/glue/BackgroundParent.h b/ipc/glue/BackgroundParent.h index 1955aabcb6ed..cf85da5f72a7 100644 --- a/ipc/glue/BackgroundParent.h +++ b/ipc/glue/BackgroundParent.h @@ -37,7 +37,9 @@ class ContentParent; namespace ipc { +class BackgroundStarterParent; class PBackgroundParent; +class PBackgroundStarterParent; template class Endpoint; @@ -45,14 +47,15 @@ class Endpoint; // This class is not designed for public consumption beyond the few static // member functions. class BackgroundParent final { + friend class mozilla::ipc::BackgroundStarterParent; friend class mozilla::dom::ContentParent; + friend class mozilla::net::SocketProcessBridgeParent; + friend class mozilla::net::SocketProcessParent; typedef base::ProcessId ProcessId; typedef mozilla::dom::BlobImpl BlobImpl; typedef mozilla::dom::ContentParent ContentParent; typedef mozilla::ipc::Transport Transport; - friend class mozilla::net::SocketProcessBridgeParent; - friend class mozilla::net::SocketProcessParent; public: // This function allows the caller to determine if the given parent actor @@ -81,17 +84,14 @@ class BackgroundParent final { static uint64_t GetChildID(PBackgroundParent* aBackgroundActor); - static bool GetLiveActorArray(PBackgroundParent* aBackgroundActor, - nsTArray& aLiveActorArray); - private: // Only called by ContentParent for cross-process actors. - static bool Alloc(ContentParent* aContent, - Endpoint&& aEndpoint); + static bool AllocStarter(ContentParent* aContent, + Endpoint&& aEndpoint); // Called by SocketProcessBridgeParent and SocketProcessParent for // cross-process actors. - static bool Alloc(Endpoint&& aEndpoint); + static bool AllocStarter(Endpoint&& aEndpoint); }; // Implemented in BackgroundImpl.cpp. diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index 41a2f78cfa5a..37cb7576f57f 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -125,7 +125,6 @@ using mozilla::dom::ContentParent; BackgroundParentImpl::BackgroundParentImpl() { AssertIsInMainOrSocketProcess(); - AssertIsOnMainThread(); MOZ_COUNT_CTOR(mozilla::ipc::BackgroundParentImpl); } diff --git a/ipc/glue/BackgroundStarterChild.h b/ipc/glue/BackgroundStarterChild.h new file mode 100644 index 000000000000..34f3bcb47988 --- /dev/null +++ b/ipc/glue/BackgroundStarterChild.h @@ -0,0 +1,26 @@ +/* -*- 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/. */ + +#ifndef mozilla_ipc_BackgroundStarterChild_h +#define mozilla_ipc_BackgroundStarterChild_h + +#include "mozilla/ipc/PBackgroundStarterChild.h" +#include "mozilla/dom/ContentChild.h" + +namespace mozilla::ipc { + +class BackgroundStarterChild final : public PBackgroundStarterChild { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundStarterChild, override) + + private: + friend class PBackgroundStarterChild; + ~BackgroundStarterChild() = default; +}; + +} // namespace mozilla::ipc + +#endif // mozilla_ipc_BackgroundStarterChild_h diff --git a/ipc/glue/BackgroundStarterParent.h b/ipc/glue/BackgroundStarterParent.h new file mode 100644 index 000000000000..3e38c4e2ad08 --- /dev/null +++ b/ipc/glue/BackgroundStarterParent.h @@ -0,0 +1,48 @@ +/* -*- 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/. */ + +#ifndef mozilla_ipc_BackgroundStarterParent_h +#define mozilla_ipc_BackgroundStarterParent_h + +#include "mozilla/ipc/PBackgroundStarterParent.h" +#include "mozilla/dom/ContentParent.h" +#include "nsISupportsImpl.h" + +namespace mozilla::ipc { + +class BackgroundStarterParent final : public PBackgroundStarterParent { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD( + BackgroundStarterParent, override) + + // Implemented in BackgroundImpl.cpp + BackgroundStarterParent(mozilla::dom::ContentParent* aContent, + bool aCrossProcess); + + void SetLiveActorArray(nsTArray* aLiveActorArray); + + private: + friend class PBackgroundStarterParent; + ~BackgroundStarterParent() = default; + + // Implemented in BackgroundImpl.cpp + void ActorDestroy(ActorDestroyReason aReason) override; + + // Implemented in BackgroundImpl.cpp + IPCResult RecvInitBackground(Endpoint&& aEndpoint); + + const bool mCrossProcess; + + RefPtr mContent; + + // Set when the actor is opened successfully and used to handle shutdown + // hangs. Only touched on the background thread. + nsTArray* mLiveActorArray = nullptr; +}; + +} // namespace mozilla::ipc + +#endif // mozilla_ipc_BackgroundStarterParent_h diff --git a/ipc/glue/PBackgroundStarter.ipdl b/ipc/glue/PBackgroundStarter.ipdl new file mode 100644 index 000000000000..1f43c4a9d7fb --- /dev/null +++ b/ipc/glue/PBackgroundStarter.ipdl @@ -0,0 +1,18 @@ +/* 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 protocol PBackground; + +namespace mozilla { +namespace ipc { + +[RefCounted, NeedsOtherPid] +async protocol PBackgroundStarter +{ +parent: + async InitBackground(Endpoint aEndpoint); +}; + +} // namespace ipc +} // namespace mozilla diff --git a/ipc/glue/moz.build b/ipc/glue/moz.build index e7c2e89c595e..be496fe2588b 100644 --- a/ipc/glue/moz.build +++ b/ipc/glue/moz.build @@ -13,6 +13,8 @@ EXPORTS.mozilla.ipc += [ "AutoTransportDescriptor.h", "BackgroundChild.h", "BackgroundParent.h", + "BackgroundStarterChild.h", + "BackgroundStarterParent.h", "BackgroundUtils.h", "BrowserProcessSubThread.h", "ByteBuf.h", @@ -226,6 +228,7 @@ IPDL_SOURCES = [ "IPCStream.ipdlh", "PBackground.ipdl", "PBackgroundSharedTypes.ipdlh", + "PBackgroundStarter.ipdl", "PBackgroundTest.ipdl", "PChildToParentStream.ipdl", "PFileDescriptorSet.ipdl", diff --git a/netwerk/ipc/PSocketProcess.ipdl b/netwerk/ipc/PSocketProcess.ipdl index 7a98d3052c6c..e99bf8a2f929 100644 --- a/netwerk/ipc/PSocketProcess.ipdl +++ b/netwerk/ipc/PSocketProcess.ipdl @@ -13,7 +13,7 @@ include protocol PFileDescriptorSet; include protocol PChildToParentStream; include protocol PParentToChildStream; include protocol PInputChannelThrottleQueue; -include protocol PBackground; +include protocol PBackgroundStarter; include protocol PAltService; include protocol PAltSvcTransaction; include protocol PTRRService; @@ -126,7 +126,7 @@ parent: PRTime aTimestamp, uint64_t aExtraSizeData, nsCString aExtraStringData); - async InitBackground(Endpoint aEndpoint); + async InitBackground(Endpoint aEndpoint); async PAltService(); sync GetTLSClientCert(nsCString aHostName, OriginAttributes aOriginAttributes, diff --git a/netwerk/ipc/PSocketProcessBridge.ipdl b/netwerk/ipc/PSocketProcessBridge.ipdl index b5540e059538..2b9637b41a05 100644 --- a/netwerk/ipc/PSocketProcessBridge.ipdl +++ b/netwerk/ipc/PSocketProcessBridge.ipdl @@ -4,7 +4,7 @@ * 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 protocol PBackground; +include protocol PBackgroundStarter; namespace mozilla { namespace net { @@ -22,7 +22,7 @@ sync protocol PSocketProcessBridge { parent: - async InitBackground(Endpoint aEndpoint); + async InitBackground(Endpoint aEndpoint); both: async Test(); }; diff --git a/netwerk/ipc/SocketProcessBridgeChild.cpp b/netwerk/ipc/SocketProcessBridgeChild.cpp index 4059aaec7460..08f16f2e4b2f 100644 --- a/netwerk/ipc/SocketProcessBridgeChild.cpp +++ b/netwerk/ipc/SocketProcessBridgeChild.cpp @@ -33,6 +33,8 @@ bool SocketProcessBridgeChild::Create( sSocketProcessBridgeChild = new SocketProcessBridgeChild(std::move(aEndpoint)); if (sSocketProcessBridgeChild->Inited()) { + mozilla::ipc::BackgroundChild::InitSocketBridgeStarter( + sSocketProcessBridgeChild); return true; } diff --git a/netwerk/ipc/SocketProcessBridgeParent.cpp b/netwerk/ipc/SocketProcessBridgeParent.cpp index f28fa9892509..4b88e97f5aad 100644 --- a/netwerk/ipc/SocketProcessBridgeParent.cpp +++ b/netwerk/ipc/SocketProcessBridgeParent.cpp @@ -37,9 +37,9 @@ mozilla::ipc::IPCResult SocketProcessBridgeParent::RecvTest() { } mozilla::ipc::IPCResult SocketProcessBridgeParent::RecvInitBackground( - Endpoint&& aEndpoint) { + Endpoint&& aEndpoint) { LOG(("SocketProcessBridgeParent::RecvInitBackground mId=%d\n", mId)); - if (!ipc::BackgroundParent::Alloc(nullptr, std::move(aEndpoint))) { + if (!ipc::BackgroundParent::AllocStarter(nullptr, std::move(aEndpoint))) { return IPC_FAIL(this, "BackgroundParent::Alloc failed"); } diff --git a/netwerk/ipc/SocketProcessBridgeParent.h b/netwerk/ipc/SocketProcessBridgeParent.h index f35559d46459..c8b9f469c63c 100644 --- a/netwerk/ipc/SocketProcessBridgeParent.h +++ b/netwerk/ipc/SocketProcessBridgeParent.h @@ -24,7 +24,7 @@ class SocketProcessBridgeParent final : public PSocketProcessBridgeParent { mozilla::ipc::IPCResult RecvTest(); mozilla::ipc::IPCResult RecvInitBackground( - Endpoint&& aEndpoint); + Endpoint&& aEndpoint); void ActorDestroy(ActorDestroyReason aWhy) override; void DeferredDestroy(); diff --git a/netwerk/ipc/SocketProcessChild.cpp b/netwerk/ipc/SocketProcessChild.cpp index 4c0d0fc59a2c..5558dcb140a6 100644 --- a/netwerk/ipc/SocketProcessChild.cpp +++ b/netwerk/ipc/SocketProcessChild.cpp @@ -147,6 +147,8 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid, } BackgroundChild::Startup(); + BackgroundChild::InitSocketStarter(this); + SetThisProcessName("Socket Process"); #if defined(XP_MACOSX) // Close all current connections to the WindowServer. This ensures that the diff --git a/netwerk/ipc/SocketProcessParent.cpp b/netwerk/ipc/SocketProcessParent.cpp index e4476547163d..50f887f2d596 100644 --- a/netwerk/ipc/SocketProcessParent.cpp +++ b/netwerk/ipc/SocketProcessParent.cpp @@ -296,9 +296,9 @@ mozilla::ipc::IPCResult SocketProcessParent::RecvObserveHttpActivity( } mozilla::ipc::IPCResult SocketProcessParent::RecvInitBackground( - Endpoint&& aEndpoint) { + Endpoint&& aEndpoint) { LOG(("SocketProcessParent::RecvInitBackground\n")); - if (!ipc::BackgroundParent::Alloc(nullptr, std::move(aEndpoint))) { + if (!ipc::BackgroundParent::AllocStarter(nullptr, std::move(aEndpoint))) { return IPC_FAIL(this, "BackgroundParent::Alloc failed"); } diff --git a/netwerk/ipc/SocketProcessParent.h b/netwerk/ipc/SocketProcessParent.h index 14bdeca8134f..29870694e619 100644 --- a/netwerk/ipc/SocketProcessParent.h +++ b/netwerk/ipc/SocketProcessParent.h @@ -90,7 +90,7 @@ class SocketProcessParent final const uint64_t& aExtraSizeData, const nsCString& aExtraStringData); mozilla::ipc::IPCResult RecvInitBackground( - Endpoint&& aEndpoint); + Endpoint&& aEndpoint); already_AddRefed AllocPAltServiceParent();