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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "BackgroundChild.h"
8 #include "BackgroundParent.h"
10 #include "BackgroundChildImpl.h"
11 #include "BackgroundParentImpl.h"
12 #include "MainThreadUtils.h"
13 #include "base/process_util.h"
14 #include "base/task.h"
15 #include "FileDescriptor.h"
16 #include "GeckoProfiler.h"
17 #include "InputStreamUtils.h"
18 #include "mozilla/Assertions.h"
19 #include "mozilla/Atomics.h"
20 #include "mozilla/ClearOnShutdown.h"
21 #include "mozilla/DebugOnly.h"
22 #include "mozilla/MozPromise.h"
23 #include "mozilla/Services.h"
24 #include "mozilla/SpinEventLoopUntil.h"
25 #include "mozilla/StaticPtr.h"
26 #include "mozilla/Unused.h"
27 #include "mozilla/dom/ContentChild.h"
28 #include "mozilla/dom/ContentParent.h"
29 #include "mozilla/dom/File.h"
30 #include "mozilla/dom/WorkerPrivate.h"
31 #include "mozilla/dom/WorkerRef.h"
32 #include "mozilla/ipc/BackgroundStarterChild.h"
33 #include "mozilla/ipc/BackgroundStarterParent.h"
34 #include "mozilla/ipc/Endpoint.h"
35 #include "mozilla/ipc/PBackgroundStarter.h"
36 #include "mozilla/ipc/ProtocolTypes.h"
37 #include "mozilla/net/SocketProcessChild.h"
38 #include "mozilla/net/SocketProcessBridgeChild.h"
40 #include "nsIEventTarget.h"
41 #include "nsIObserver.h"
42 #include "nsIObserverService.h"
43 #include "nsIRunnable.h"
44 #include "nsISupportsImpl.h"
45 #include "nsIThread.h"
48 #include "nsThreadUtils.h"
49 #include "nsTraceRefcnt.h"
50 #include "nsXULAppAPI.h"
51 #include "nsXPCOMPrivate.h"
56 #ifdef RELEASE_OR_BETA
57 # define THREADSAFETY_ASSERT MOZ_ASSERT
59 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
62 #define CRASH_IN_CHILD_PROCESS(_msg) \
64 if (XRE_IsParentProcess()) { \
65 MOZ_ASSERT(false, _msg); \
71 using namespace mozilla
;
72 using namespace mozilla::dom
;
73 using namespace mozilla::ipc
;
74 using namespace mozilla::net
;
80 // -----------------------------------------------------------------------------
82 // -----------------------------------------------------------------------------
84 void AssertIsInMainOrSocketProcess() {
85 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
88 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
90 // -----------------------------------------------------------------------------
91 // ParentImpl Declaration
92 // -----------------------------------------------------------------------------
94 class ParentImpl final
: public BackgroundParentImpl
{
95 friend class ChildImpl
;
96 friend class mozilla::ipc::BackgroundParent
;
97 friend class mozilla::ipc::BackgroundStarterParent
;
100 class ShutdownObserver
;
102 struct MOZ_STACK_CLASS TimerCallbackClosure
{
104 nsTArray
<IToplevelProtocol
*>* mLiveActors
;
106 TimerCallbackClosure(nsIThread
* aThread
,
107 nsTArray
<IToplevelProtocol
*>* aLiveActors
)
108 : mThread(aThread
), mLiveActors(aLiveActors
) {
109 AssertIsInMainOrSocketProcess();
110 AssertIsOnMainThread();
112 MOZ_ASSERT(aLiveActors
);
116 // The length of time we will wait at shutdown for all actors to clean
117 // themselves up before forcing them to be destroyed.
118 static const uint32_t kShutdownTimerDelayMS
= 10000;
120 // This is only modified on the main thread. It is null if the thread does not
121 // exist or is shutting down.
122 static StaticRefPtr
<nsIThread
> sBackgroundThread
;
124 // This is created and destroyed on the main thread but only modified on the
125 // background thread. It is specific to each instance of sBackgroundThread.
126 static nsTArray
<IToplevelProtocol
*>* sLiveActorsForBackgroundThread
;
128 // This is only modified on the main thread.
129 static StaticRefPtr
<nsITimer
> sShutdownTimer
;
131 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
132 // work during shutdown.
133 static Atomic
<PRThread
*> sBackgroundPRThread
;
135 // Maintains a count of live actors so that the background thread can be shut
136 // down when it is no longer needed.
137 // May be incremented on either the background thread (by an existing actor)
138 // or on the main thread, but must be decremented on the main thread.
139 static Atomic
<uint64_t> sLiveActorCount
;
141 // This is only modified on the main thread. It is true after the shutdown
142 // observer is registered and is never unset thereafter.
143 static bool sShutdownObserverRegistered
;
145 // This is only modified on the main thread. It prevents us from trying to
146 // create the background thread after application shutdown has started.
147 static bool sShutdownHasStarted
;
149 // null if this is a same-process or socket process actor.
150 const RefPtr
<ThreadsafeContentParentHandle
> mContent
;
152 // Set when the actor is opened successfully and used to handle shutdown
153 // hangs. Only touched on the background thread.
154 nsTArray
<IToplevelProtocol
*>* mLiveActorArray
;
156 // Set at construction to indicate whether this parent actor corresponds to a
157 // child actor in another process or to a child actor from a different thread
158 // in the same process.
159 const bool mIsOtherProcessActor
;
161 // Set after ActorDestroy has been called. Only touched on the background
163 bool mActorDestroyed
;
166 static bool IsOnBackgroundThread() {
167 return PR_GetCurrentThread() == sBackgroundPRThread
;
170 static void AssertIsOnBackgroundThread() {
171 THREADSAFETY_ASSERT(IsOnBackgroundThread());
174 // `ParentImpl` instances need to be deleted on the main thread, despite IPC
175 // controlling them on a background thread. Use `_WITH_DELETE_ON_MAIN_THREAD`
176 // to force destruction to occur on the desired thread.
177 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(ParentImpl
,
183 // Forwarded from BackgroundParent.
184 static bool IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
);
186 // Forwarded from BackgroundParent.
187 static ThreadsafeContentParentHandle
* GetContentParentHandle(
188 PBackgroundParent
* aBackgroundActor
);
190 // Forwarded from BackgroundParent.
191 static uint64_t GetChildID(PBackgroundParent
* aBackgroundActor
);
193 // Forwarded from BackgroundParent.
194 static bool AllocStarter(ContentParent
* aContent
,
195 Endpoint
<PBackgroundStarterParent
>&& aEndpoint
,
196 bool aCrossProcess
= true);
198 static bool CreateBackgroundThread();
200 static void ShutdownBackgroundThread();
202 static void ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
);
204 // NOTE: ParentImpl could be used in 4 cases below.
205 // 1. Within the parent process.
206 // 2. Between parent process and content process.
207 // 3. Between socket process and content process.
208 // 4. Between parent process and socket process.
209 // |aContent| should be not null for case 2. For cases 1, 3 and 4, it's null.
210 explicit ParentImpl(ThreadsafeContentParentHandle
* aContent
,
211 bool aIsOtherProcessActor
)
212 : mContent(aContent
),
213 mLiveActorArray(nullptr),
214 mIsOtherProcessActor(aIsOtherProcessActor
),
215 mActorDestroyed(false) {
216 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
217 MOZ_ASSERT_IF(!aIsOtherProcessActor
, XRE_IsParentProcess());
221 AssertIsInMainOrSocketProcess();
222 AssertIsOnMainThread();
225 void MainThreadActorDestroy();
227 void SetLiveActorArray(nsTArray
<IToplevelProtocol
*>* aLiveActorArray
) {
228 AssertIsInMainOrSocketProcess();
229 AssertIsOnBackgroundThread();
230 MOZ_ASSERT(aLiveActorArray
);
231 MOZ_ASSERT(!aLiveActorArray
->Contains(this));
232 MOZ_ASSERT(!mLiveActorArray
);
233 MOZ_ASSERT(mIsOtherProcessActor
);
235 mLiveActorArray
= aLiveActorArray
;
236 mLiveActorArray
->AppendElement(this);
239 // These methods are only called by IPDL.
240 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
243 // -----------------------------------------------------------------------------
244 // ChildImpl Declaration
245 // -----------------------------------------------------------------------------
247 class ChildImpl final
: public BackgroundChildImpl
{
248 friend class mozilla::ipc::BackgroundChild
;
249 friend class mozilla::ipc::BackgroundChildImpl
;
250 friend class mozilla::ipc::BackgroundStarterChild
;
252 typedef base::ProcessId ProcessId
;
254 class ShutdownObserver
;
257 struct ThreadLocalInfo
{
265 RefPtr
<ChildImpl
> mActor
;
266 UniquePtr
<BackgroundChildImpl::ThreadLocal
> mConsumerThreadLocal
;
273 // A thread-local index that is not valid.
274 static constexpr unsigned int kBadThreadLocalIndex
=
275 static_cast<unsigned int>(-1);
277 // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
278 // also provides some common functions for creating PBackground IPC actor.
279 class ThreadInfoWrapper final
{
280 friend class ChildImpl
;
283 using ActorCreateFunc
= void (*)(ThreadLocalInfo
*, unsigned int,
284 nsIEventTarget
*, ChildImpl
**);
286 ThreadInfoWrapper() = default;
289 MOZ_ASSERT(mThreadLocalIndex
== kBadThreadLocalIndex
,
290 "ThreadInfoWrapper::Startup() called more than once!");
293 PR_NewThreadPrivateIndex(&mThreadLocalIndex
, ThreadLocalDestructor
);
294 MOZ_RELEASE_ASSERT(status
== PR_SUCCESS
,
295 "PR_NewThreadPrivateIndex failed!");
297 MOZ_ASSERT(mThreadLocalIndex
!= kBadThreadLocalIndex
);
301 if (sShutdownHasStarted
) {
302 MOZ_ASSERT_IF(mThreadLocalIndex
!= kBadThreadLocalIndex
,
303 !PR_GetThreadPrivate(mThreadLocalIndex
));
307 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
311 RefPtr
<BackgroundStarterChild
> starter
;
313 auto lock
= mStarter
.Lock();
314 starter
= lock
->forget();
317 CloseStarter(starter
);
320 ThreadLocalInfo
* threadLocalInfo
;
323 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(mThreadLocalIndex
));
324 MOZ_ASSERT(!threadLocalInfo
);
327 threadLocalInfo
= mMainThreadInfo
;
328 if (threadLocalInfo
) {
330 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
331 threadLocalInfo
->mClosed
= true;
334 ThreadLocalDestructor(threadLocalInfo
);
335 mMainThreadInfo
= nullptr;
339 template <typename Actor
>
340 void InitStarter(Actor
* aActor
) {
341 AssertIsOnMainThread();
343 // Create a pair of endpoints and send them to the other process.
344 Endpoint
<PBackgroundStarterParent
> parent
;
345 Endpoint
<PBackgroundStarterChild
> child
;
346 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
347 aActor
->OtherPid(), base::GetCurrentProcId(), &parent
, &child
));
348 MOZ_ALWAYS_TRUE(aActor
->SendInitBackground(std::move(parent
)));
350 InitStarter(std::move(child
));
353 void InitStarter(Endpoint
<PBackgroundStarterChild
>&& aEndpoint
) {
354 AssertIsOnMainThread();
356 base::ProcessId otherPid
= aEndpoint
.OtherPid();
358 nsCOMPtr
<nsISerialEventTarget
> taskQueue
;
359 MOZ_ALWAYS_SUCCEEDS(NS_CreateBackgroundTaskQueue(
360 "PBackgroundStarter Queue", getter_AddRefs(taskQueue
)));
362 RefPtr
<BackgroundStarterChild
> starter
=
363 new BackgroundStarterChild(otherPid
, taskQueue
);
365 taskQueue
->Dispatch(NS_NewRunnableFunction(
366 "PBackgroundStarterChild Init",
367 [starter
, endpoint
= std::move(aEndpoint
)]() mutable {
368 MOZ_ALWAYS_TRUE(endpoint
.Bind(starter
));
371 // Swap in the newly initialized `BackgroundStarterChild`, and close the
372 // previous one if we're replacing an existing PBackgroundStarterChild
374 RefPtr
<BackgroundStarterChild
> prevStarter
;
376 auto lock
= mStarter
.Lock();
377 prevStarter
= lock
->forget();
378 *lock
= starter
.forget();
381 CloseStarter(prevStarter
);
385 void CloseForCurrentThread() {
386 MOZ_ASSERT(!NS_IsMainThread());
388 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
392 auto* threadLocalInfo
=
393 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(mThreadLocalIndex
));
395 if (!threadLocalInfo
) {
400 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
401 threadLocalInfo
->mClosed
= true;
404 // Clearing the thread local will synchronously close the actor.
405 DebugOnly
<PRStatus
> status
=
406 PR_SetThreadPrivate(mThreadLocalIndex
, nullptr);
407 MOZ_ASSERT(status
== PR_SUCCESS
);
410 PBackgroundChild
* GetOrCreateForCurrentThread() {
411 // Processes can be told to do final CC's during shutdown even though
412 // they never finished starting (and thus call this), because they
413 // hadn't gotten far enough to call Startup() before shutdown began.
414 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
415 NS_ERROR("BackgroundChild::Startup() was never called");
418 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted
) {
422 auto* threadLocalInfo
= NS_IsMainThread()
424 : static_cast<ThreadLocalInfo
*>(
425 PR_GetThreadPrivate(mThreadLocalIndex
));
427 if (!threadLocalInfo
) {
428 auto newInfo
= MakeUnique
<ThreadLocalInfo
>();
430 if (NS_IsMainThread()) {
431 mMainThreadInfo
= newInfo
.get();
433 if (PR_SetThreadPrivate(mThreadLocalIndex
, newInfo
.get()) !=
435 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
440 threadLocalInfo
= newInfo
.release();
443 if (threadLocalInfo
->mActor
) {
444 return threadLocalInfo
->mActor
;
447 RefPtr
<BackgroundStarterChild
> starter
;
449 auto lock
= mStarter
.Lock();
453 CRASH_IN_CHILD_PROCESS("No BackgroundStarterChild");
457 Endpoint
<PBackgroundParent
> parent
;
458 Endpoint
<PBackgroundChild
> child
;
460 rv
= PBackground::CreateEndpoints(
461 starter
->mOtherPid
, base::GetCurrentProcId(), &parent
, &child
);
463 NS_WARNING("Failed to create top level actor!");
467 RefPtr
<ChildImpl
> strongActor
= new ChildImpl();
468 if (!child
.Bind(strongActor
)) {
469 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
472 strongActor
->SetActorAlive();
473 threadLocalInfo
->mActor
= strongActor
;
475 // Dispatch to the background task queue to create the relevant actor in
476 // the remote process.
477 starter
->mTaskQueue
->Dispatch(NS_NewRunnableFunction(
478 "PBackground GetOrCreateForCurrentThread",
479 [starter
, endpoint
= std::move(parent
)]() mutable {
480 if (!starter
->SendInitBackground(std::move(endpoint
))) {
481 NS_WARNING("Failed to create toplevel actor");
488 static void CloseStarter(BackgroundStarterChild
* aStarter
) {
489 aStarter
->mTaskQueue
->Dispatch(NS_NewRunnableFunction(
490 "PBackgroundStarterChild Close",
491 [starter
= RefPtr
{aStarter
}] { starter
->Close(); }));
494 // This is only modified on the main thread. It is the thread-local index
495 // that we use to store the BackgroundChild for each thread.
496 unsigned int mThreadLocalIndex
= kBadThreadLocalIndex
;
498 // On the main thread, we store TLS in this global instead of in
499 // mThreadLocalIndex. That way, cooperative main threads all share the same
501 ThreadLocalInfo
* mMainThreadInfo
= nullptr;
503 // The starter which will be used to launch PBackground instances of this
504 // type. Only modified on the main thread, but may be read by any thread
505 // wanting to start background actors.
506 StaticDataMutex
<StaticRefPtr
<BackgroundStarterChild
>> mStarter
{"mStarter"};
509 // For PBackground between parent and content process.
510 static ThreadInfoWrapper sParentAndContentProcessThreadInfo
;
512 // For PBackground between socket and content process.
513 static ThreadInfoWrapper sSocketAndContentProcessThreadInfo
;
515 // For PBackground between socket and parent process.
516 static ThreadInfoWrapper sSocketAndParentProcessThreadInfo
;
518 // This is only modified on the main thread. It prevents us from trying to
519 // create the background thread after application shutdown has started.
520 static bool sShutdownHasStarted
;
522 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
523 nsISerialEventTarget
* mOwningEventTarget
;
528 bool mActorDestroyed
;
532 static void Shutdown();
534 void AssertIsOnOwningThread() {
535 THREADSAFETY_ASSERT(mOwningEventTarget
);
537 #ifdef RELEASE_OR_BETA
538 DebugOnly
<bool> current
;
543 NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)));
544 THREADSAFETY_ASSERT(current
);
547 void AssertActorDestroyed() {
548 MOZ_ASSERT(mActorDestroyed
, "ChildImpl::ActorDestroy not called in time");
552 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
553 : mOwningEventTarget(GetCurrentSerialEventTarget())
557 mActorWasAlive(false),
558 mActorDestroyed(false)
561 AssertIsOnOwningThread();
564 void SetActorAlive() {
565 AssertIsOnOwningThread();
566 MOZ_ASSERT(!mActorWasAlive
);
567 MOZ_ASSERT(!mActorDestroyed
);
570 mActorWasAlive
= true;
574 NS_INLINE_DECL_REFCOUNTING(ChildImpl
, override
)
577 // Forwarded from BackgroundChild.
578 static void Startup();
580 // Forwarded from BackgroundChild.
581 static PBackgroundChild
* GetForCurrentThread();
583 // Forwarded from BackgroundChild.
584 static PBackgroundChild
* GetOrCreateForCurrentThread();
586 // Forwarded from BackgroundChild.
587 static PBackgroundChild
* GetOrCreateSocketActorForCurrentThread();
589 // Forwarded from BackgroundChild.
590 static PBackgroundChild
* GetOrCreateForSocketParentBridgeForCurrentThread();
592 static void CloseForCurrentThread();
594 // Forwarded from BackgroundChildImpl.
595 static BackgroundChildImpl::ThreadLocal
* GetThreadLocalForCurrentThread();
597 // Forwarded from BackgroundChild.
598 static void InitContentStarter(mozilla::dom::ContentChild
* aContent
);
600 // Forwarded from BackgroundChild.
601 static void InitSocketStarter(mozilla::net::SocketProcessChild
* aSocket
);
603 // Forwarded from BackgroundChild.
604 static void InitSocketBridgeStarter(
605 mozilla::net::SocketProcessBridgeChild
* aSocketBridge
);
607 static void ThreadLocalDestructor(void* aThreadLocal
);
609 // This class is reference counted.
610 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive
, mActorDestroyed
); }
612 // Only called by IPDL.
613 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
616 // -----------------------------------------------------------------------------
617 // ParentImpl Helper Declarations
618 // -----------------------------------------------------------------------------
620 class ParentImpl::ShutdownObserver final
: public nsIObserver
{
622 ShutdownObserver() { AssertIsOnMainThread(); }
628 ~ShutdownObserver() { AssertIsOnMainThread(); }
631 // -----------------------------------------------------------------------------
632 // ChildImpl Helper Declarations
633 // -----------------------------------------------------------------------------
635 class ChildImpl::ShutdownObserver final
: public nsIObserver
{
637 ShutdownObserver() { AssertIsOnMainThread(); }
643 ~ShutdownObserver() { AssertIsOnMainThread(); }
651 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
655 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
660 } // namespace mozilla
662 // -----------------------------------------------------------------------------
663 // BackgroundParent Public Methods
664 // -----------------------------------------------------------------------------
667 bool BackgroundParent::IsOtherProcessActor(
668 PBackgroundParent
* aBackgroundActor
) {
669 return ParentImpl::IsOtherProcessActor(aBackgroundActor
);
673 ThreadsafeContentParentHandle
* BackgroundParent::GetContentParentHandle(
674 PBackgroundParent
* aBackgroundActor
) {
675 return ParentImpl::GetContentParentHandle(aBackgroundActor
);
679 uint64_t BackgroundParent::GetChildID(PBackgroundParent
* aBackgroundActor
) {
680 return ParentImpl::GetChildID(aBackgroundActor
);
684 bool BackgroundParent::AllocStarter(
685 ContentParent
* aContent
, Endpoint
<PBackgroundStarterParent
>&& aEndpoint
) {
686 return ParentImpl::AllocStarter(aContent
, std::move(aEndpoint
));
689 // -----------------------------------------------------------------------------
690 // BackgroundChild Public Methods
691 // -----------------------------------------------------------------------------
694 void BackgroundChild::Startup() { ChildImpl::Startup(); }
697 PBackgroundChild
* BackgroundChild::GetForCurrentThread() {
698 return ChildImpl::GetForCurrentThread();
702 PBackgroundChild
* BackgroundChild::GetOrCreateForCurrentThread() {
703 return ChildImpl::GetOrCreateForCurrentThread();
707 PBackgroundChild
* BackgroundChild::GetOrCreateSocketActorForCurrentThread() {
708 return ChildImpl::GetOrCreateSocketActorForCurrentThread();
713 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread() {
714 return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread();
718 void BackgroundChild::CloseForCurrentThread() {
719 ChildImpl::CloseForCurrentThread();
723 void BackgroundChild::InitContentStarter(ContentChild
* aContent
) {
724 ChildImpl::InitContentStarter(aContent
);
728 void BackgroundChild::InitSocketStarter(net::SocketProcessChild
* aSocket
) {
729 ChildImpl::InitSocketStarter(aSocket
);
733 void BackgroundChild::InitSocketBridgeStarter(
734 net::SocketProcessBridgeChild
* aSocketBridge
) {
735 ChildImpl::InitSocketBridgeStarter(aSocketBridge
);
738 // -----------------------------------------------------------------------------
739 // BackgroundChildImpl Public Methods
740 // -----------------------------------------------------------------------------
743 BackgroundChildImpl::ThreadLocal
*
744 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
745 return ChildImpl::GetThreadLocalForCurrentThread();
748 // -----------------------------------------------------------------------------
749 // ParentImpl Static Members
750 // -----------------------------------------------------------------------------
752 StaticRefPtr
<nsIThread
> ParentImpl::sBackgroundThread
;
754 nsTArray
<IToplevelProtocol
*>* ParentImpl::sLiveActorsForBackgroundThread
;
756 StaticRefPtr
<nsITimer
> ParentImpl::sShutdownTimer
;
758 Atomic
<PRThread
*> ParentImpl::sBackgroundPRThread
;
760 Atomic
<uint64_t> ParentImpl::sLiveActorCount
;
762 bool ParentImpl::sShutdownObserverRegistered
= false;
764 bool ParentImpl::sShutdownHasStarted
= false;
766 // -----------------------------------------------------------------------------
767 // ChildImpl Static Members
768 // -----------------------------------------------------------------------------
770 ChildImpl::ThreadInfoWrapper
ChildImpl::sParentAndContentProcessThreadInfo
;
772 ChildImpl::ThreadInfoWrapper
ChildImpl::sSocketAndContentProcessThreadInfo
;
774 ChildImpl::ThreadInfoWrapper
ChildImpl::sSocketAndParentProcessThreadInfo
;
776 bool ChildImpl::sShutdownHasStarted
= false;
778 // -----------------------------------------------------------------------------
779 // ParentImpl Implementation
780 // -----------------------------------------------------------------------------
783 bool ParentImpl::IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
) {
784 AssertIsOnBackgroundThread();
785 MOZ_ASSERT(aBackgroundActor
);
787 return static_cast<ParentImpl
*>(aBackgroundActor
)->mIsOtherProcessActor
;
791 ThreadsafeContentParentHandle
* ParentImpl::GetContentParentHandle(
792 PBackgroundParent
* aBackgroundActor
) {
793 AssertIsOnBackgroundThread();
794 MOZ_ASSERT(aBackgroundActor
);
796 return static_cast<ParentImpl
*>(aBackgroundActor
)->mContent
.get();
800 uint64_t ParentImpl::GetChildID(PBackgroundParent
* aBackgroundActor
) {
801 AssertIsOnBackgroundThread();
802 MOZ_ASSERT(aBackgroundActor
);
804 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
805 if (actor
->mContent
) {
806 return actor
->mContent
->ChildID();
813 bool ParentImpl::AllocStarter(ContentParent
* aContent
,
814 Endpoint
<PBackgroundStarterParent
>&& aEndpoint
,
815 bool aCrossProcess
) {
816 AssertIsInMainOrSocketProcess();
817 AssertIsOnMainThread();
819 MOZ_ASSERT(aEndpoint
.IsValid());
821 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
822 NS_WARNING("Failed to create background thread!");
828 RefPtr
<BackgroundStarterParent
> actor
= new BackgroundStarterParent(
829 aContent
? aContent
->ThreadsafeHandle() : nullptr, aCrossProcess
);
831 if (NS_FAILED(sBackgroundThread
->Dispatch(NS_NewRunnableFunction(
832 "BackgroundStarterParent::ConnectActorRunnable",
833 [actor
= std::move(actor
), endpoint
= std::move(aEndpoint
),
834 liveActorArray
= sLiveActorsForBackgroundThread
]() mutable {
835 MOZ_ASSERT(endpoint
.IsValid());
836 MOZ_ALWAYS_TRUE(endpoint
.Bind(actor
));
837 actor
->SetLiveActorArray(liveActorArray
);
839 NS_WARNING("Failed to dispatch connect runnable!");
841 MOZ_ASSERT(sLiveActorCount
);
849 bool ParentImpl::CreateBackgroundThread() {
850 AssertIsInMainOrSocketProcess();
851 AssertIsOnMainThread();
852 MOZ_ASSERT(!sBackgroundThread
);
853 MOZ_ASSERT(!sLiveActorsForBackgroundThread
);
855 if (sShutdownHasStarted
) {
857 "Trying to create background thread after shutdown has "
862 nsCOMPtr
<nsITimer
> newShutdownTimer
;
864 if (!sShutdownTimer
) {
865 newShutdownTimer
= NS_NewTimer();
866 if (!newShutdownTimer
) {
871 if (!sShutdownObserverRegistered
) {
872 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
873 if (NS_WARN_IF(!obs
)) {
877 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
879 nsresult rv
= obs
->AddObserver(
880 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
881 if (NS_WARN_IF(NS_FAILED(rv
))) {
885 sShutdownObserverRegistered
= true;
888 nsCOMPtr
<nsIThread
> thread
;
889 if (NS_FAILED(NS_NewNamedThread(
890 "IPDL Background", getter_AddRefs(thread
),
891 NS_NewRunnableFunction(
892 "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
893 DebugOnly
<PRThread
*> oldBackgroundThread
=
894 sBackgroundPRThread
.exchange(PR_GetCurrentThread());
896 MOZ_ASSERT_IF(oldBackgroundThread
,
897 PR_GetCurrentThread() != oldBackgroundThread
);
899 NS_WARNING("NS_NewNamedThread failed!");
903 sBackgroundThread
= thread
.forget();
905 sLiveActorsForBackgroundThread
= new nsTArray
<IToplevelProtocol
*>(1);
907 if (!sShutdownTimer
) {
908 MOZ_ASSERT(newShutdownTimer
);
909 sShutdownTimer
= newShutdownTimer
;
916 void ParentImpl::ShutdownBackgroundThread() {
917 AssertIsInMainOrSocketProcess();
918 AssertIsOnMainThread();
919 MOZ_ASSERT(sShutdownHasStarted
);
920 MOZ_ASSERT_IF(!sBackgroundThread
, !sLiveActorCount
);
921 MOZ_ASSERT_IF(sBackgroundThread
, sShutdownTimer
);
923 nsCOMPtr
<nsITimer
> shutdownTimer
= sShutdownTimer
.get();
924 sShutdownTimer
= nullptr;
926 if (sBackgroundThread
) {
927 nsCOMPtr
<nsIThread
> thread
= sBackgroundThread
.get();
928 sBackgroundThread
= nullptr;
930 UniquePtr
<nsTArray
<IToplevelProtocol
*>> liveActors(
931 sLiveActorsForBackgroundThread
);
932 sLiveActorsForBackgroundThread
= nullptr;
934 MOZ_ASSERT_IF(!sShutdownHasStarted
, !sLiveActorCount
);
936 if (sLiveActorCount
) {
937 // We need to spin the event loop while we wait for all the actors to be
938 // cleaned up. We also set a timeout to force-kill any hanging actors.
939 TimerCallbackClosure
closure(thread
, liveActors
.get());
941 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->InitWithNamedFuncCallback(
942 &ShutdownTimerCallback
, &closure
, kShutdownTimerDelayMS
,
943 nsITimer::TYPE_ONE_SHOT
, "ParentImpl::ShutdownTimerCallback"));
945 SpinEventLoopUntil("ParentImpl::ShutdownBackgroundThread"_ns
,
946 [&]() { return !sLiveActorCount
; });
948 MOZ_ASSERT(liveActors
->IsEmpty());
950 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->Cancel());
953 // Dispatch this runnable to unregister the PR thread from the profiler.
954 MOZ_ALWAYS_SUCCEEDS(thread
->Dispatch(NS_NewRunnableFunction(
955 "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
956 // It is possible that another background thread was created while
957 // this thread was shutting down. In that case we can't assert
958 // anything about sBackgroundPRThread and we should not modify it
960 sBackgroundPRThread
.compareExchange(PR_GetCurrentThread(), nullptr);
963 MOZ_ALWAYS_SUCCEEDS(thread
->Shutdown());
968 void ParentImpl::ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
) {
969 AssertIsInMainOrSocketProcess();
970 AssertIsOnMainThread();
971 MOZ_ASSERT(sShutdownHasStarted
);
972 MOZ_ASSERT(sLiveActorCount
);
974 auto closure
= static_cast<TimerCallbackClosure
*>(aClosure
);
977 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
982 closure
->mThread
, __func__
,
983 [liveActors
= closure
->mLiveActors
]() {
984 MOZ_ASSERT(liveActors
);
986 if (!liveActors
->IsEmpty()) {
987 // Copy the array since calling Close() could mutate the
989 nsTArray
<IToplevelProtocol
*> actorsToClose(liveActors
->Clone());
990 for (IToplevelProtocol
* actor
: actorsToClose
) {
994 return GenericPromise::CreateAndResolve(true, __func__
);
996 ->Then(GetCurrentSerialEventTarget(), __func__
, []() {
997 MOZ_ASSERT(sLiveActorCount
);
1002 void ParentImpl::Destroy() {
1003 // May be called on any thread!
1005 AssertIsInMainOrSocketProcess();
1007 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1008 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1009 &ParentImpl::MainThreadActorDestroy
)));
1012 void ParentImpl::MainThreadActorDestroy() {
1013 AssertIsInMainOrSocketProcess();
1014 AssertIsOnMainThread();
1015 MOZ_ASSERT_IF(!mIsOtherProcessActor
, !mContent
);
1017 MOZ_ASSERT(sLiveActorCount
);
1020 // This may be the last reference!
1024 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1025 AssertIsInMainOrSocketProcess();
1026 AssertIsOnBackgroundThread();
1027 MOZ_ASSERT(!mActorDestroyed
);
1028 MOZ_ASSERT_IF(mIsOtherProcessActor
, mLiveActorArray
);
1030 BackgroundParentImpl::ActorDestroy(aWhy
);
1032 mActorDestroyed
= true;
1034 if (mLiveActorArray
) {
1035 MOZ_ALWAYS_TRUE(mLiveActorArray
->RemoveElement(this));
1036 mLiveActorArray
= nullptr;
1039 // This is tricky. We should be able to call Destroy() here directly because
1040 // we're not going to touch 'this' or our MessageChannel any longer on this
1041 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1042 // it runs it will destroy 'this' and our associated MessageChannel. However,
1043 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1044 // racing with the main thread we must ensure that the MessageChannel lives
1045 // long enough to be cleared in this call stack.
1047 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1048 "ParentImpl::Destroy", this, &ParentImpl::Destroy
)));
1051 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver
, nsIObserver
)
1054 ParentImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1055 const char16_t
* aData
) {
1056 AssertIsInMainOrSocketProcess();
1057 AssertIsOnMainThread();
1058 MOZ_ASSERT(!sShutdownHasStarted
);
1059 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1061 sShutdownHasStarted
= true;
1063 // Do this first before calling (and spinning the event loop in)
1064 // ShutdownBackgroundThread().
1065 ChildImpl::Shutdown();
1067 ShutdownBackgroundThread();
1072 BackgroundStarterParent::BackgroundStarterParent(
1073 ThreadsafeContentParentHandle
* aContent
, bool aCrossProcess
)
1074 : mCrossProcess(aCrossProcess
), mContent(aContent
) {
1075 AssertIsOnMainThread();
1076 AssertIsInMainOrSocketProcess();
1077 MOZ_ASSERT_IF(!mCrossProcess
, !mContent
);
1078 MOZ_ASSERT_IF(!mCrossProcess
, XRE_IsParentProcess());
1081 void BackgroundStarterParent::SetLiveActorArray(
1082 nsTArray
<IToplevelProtocol
*>* aLiveActorArray
) {
1083 AssertIsInMainOrSocketProcess();
1084 AssertIsOnBackgroundThread();
1085 MOZ_ASSERT(aLiveActorArray
);
1086 MOZ_ASSERT(!aLiveActorArray
->Contains(this));
1087 MOZ_ASSERT(!mLiveActorArray
);
1088 MOZ_ASSERT_IF(!mCrossProcess
, OtherPid() == base::GetCurrentProcId());
1090 mLiveActorArray
= aLiveActorArray
;
1091 mLiveActorArray
->AppendElement(this);
1094 IPCResult
BackgroundStarterParent::RecvInitBackground(
1095 Endpoint
<PBackgroundParent
>&& aEndpoint
) {
1096 AssertIsOnBackgroundThread();
1098 if (!aEndpoint
.IsValid()) {
1099 return IPC_FAIL(this,
1100 "Cannot initialize PBackground with invalid endpoint");
1103 ParentImpl
* actor
= new ParentImpl(mContent
, mCrossProcess
);
1105 // Take a reference on this thread. If Open() fails then we will release this
1106 // reference in Destroy.
1109 ParentImpl::sLiveActorCount
++;
1111 if (!aEndpoint
.Bind(actor
)) {
1116 if (mCrossProcess
) {
1117 actor
->SetLiveActorArray(mLiveActorArray
);
1122 void BackgroundStarterParent::ActorDestroy(ActorDestroyReason aReason
) {
1123 AssertIsOnBackgroundThread();
1125 if (mLiveActorArray
) {
1126 MOZ_ALWAYS_TRUE(mLiveActorArray
->RemoveElement(this));
1127 mLiveActorArray
= nullptr;
1130 // Make sure to decrement `sLiveActorCount` on the main thread.
1131 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1132 NS_NewRunnableFunction("BackgroundStarterParent::MainThreadDestroy",
1133 [] { ParentImpl::sLiveActorCount
--; })));
1136 // -----------------------------------------------------------------------------
1137 // ChildImpl Implementation
1138 // -----------------------------------------------------------------------------
1141 void ChildImpl::Startup() {
1142 // This happens on the main thread but before XPCOM has started so we can't
1143 // assert that we're being called on the main thread here.
1145 sParentAndContentProcessThreadInfo
.Startup();
1146 sSocketAndContentProcessThreadInfo
.Startup();
1147 sSocketAndParentProcessThreadInfo
.Startup();
1149 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1150 MOZ_RELEASE_ASSERT(observerService
);
1152 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
1154 nsresult rv
= observerService
->AddObserver(
1155 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
1156 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
1158 // Initialize a starter actor to allow starting PBackground within the parent
1160 if (XRE_IsParentProcess()) {
1161 Endpoint
<PBackgroundStarterParent
> parent
;
1162 Endpoint
<PBackgroundStarterChild
> child
;
1163 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
1164 base::GetCurrentProcId(), base::GetCurrentProcId(), &parent
, &child
));
1166 MOZ_ALWAYS_TRUE(ParentImpl::AllocStarter(nullptr, std::move(parent
),
1167 /* aCrossProcess */ false));
1168 sParentAndContentProcessThreadInfo
.InitStarter(std::move(child
));
1173 void ChildImpl::Shutdown() {
1174 AssertIsOnMainThread();
1176 sParentAndContentProcessThreadInfo
.Shutdown();
1177 sSocketAndContentProcessThreadInfo
.Shutdown();
1178 sSocketAndParentProcessThreadInfo
.Shutdown();
1180 sShutdownHasStarted
= true;
1184 PBackgroundChild
* ChildImpl::GetForCurrentThread() {
1185 MOZ_ASSERT(sParentAndContentProcessThreadInfo
.mThreadLocalIndex
!=
1186 kBadThreadLocalIndex
);
1188 auto threadLocalInfo
=
1190 ? sParentAndContentProcessThreadInfo
.mMainThreadInfo
1191 : static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(
1192 sParentAndContentProcessThreadInfo
.mThreadLocalIndex
));
1194 if (!threadLocalInfo
) {
1198 return threadLocalInfo
->mActor
;
1202 PBackgroundChild
* ChildImpl::GetOrCreateForCurrentThread() {
1203 return sParentAndContentProcessThreadInfo
.GetOrCreateForCurrentThread();
1207 PBackgroundChild
* ChildImpl::GetOrCreateSocketActorForCurrentThread() {
1208 return sSocketAndContentProcessThreadInfo
.GetOrCreateForCurrentThread();
1213 ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread() {
1214 return sSocketAndParentProcessThreadInfo
.GetOrCreateForCurrentThread();
1218 void ChildImpl::CloseForCurrentThread() {
1219 MOZ_ASSERT(!NS_IsMainThread(),
1220 "PBackground for the main thread should be shut down via "
1221 "ChildImpl::Shutdown().");
1223 sParentAndContentProcessThreadInfo
.CloseForCurrentThread();
1224 sSocketAndContentProcessThreadInfo
.CloseForCurrentThread();
1225 sSocketAndParentProcessThreadInfo
.CloseForCurrentThread();
1229 BackgroundChildImpl::ThreadLocal
* ChildImpl::GetThreadLocalForCurrentThread() {
1230 MOZ_ASSERT(sParentAndContentProcessThreadInfo
.mThreadLocalIndex
!=
1231 kBadThreadLocalIndex
,
1232 "BackgroundChild::Startup() was never called!");
1234 auto threadLocalInfo
=
1236 ? sParentAndContentProcessThreadInfo
.mMainThreadInfo
1237 : static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(
1238 sParentAndContentProcessThreadInfo
.mThreadLocalIndex
));
1240 if (!threadLocalInfo
) {
1244 if (!threadLocalInfo
->mConsumerThreadLocal
) {
1245 threadLocalInfo
->mConsumerThreadLocal
=
1246 MakeUnique
<BackgroundChildImpl::ThreadLocal
>();
1249 return threadLocalInfo
->mConsumerThreadLocal
.get();
1253 void ChildImpl::InitContentStarter(mozilla::dom::ContentChild
* aContent
) {
1254 sParentAndContentProcessThreadInfo
.InitStarter(aContent
);
1258 void ChildImpl::InitSocketStarter(mozilla::net::SocketProcessChild
* aSocket
) {
1259 sSocketAndParentProcessThreadInfo
.InitStarter(aSocket
);
1263 void ChildImpl::InitSocketBridgeStarter(
1264 mozilla::net::SocketProcessBridgeChild
* aSocketBridge
) {
1265 sSocketAndContentProcessThreadInfo
.InitStarter(aSocketBridge
);
1269 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal
) {
1270 auto threadLocalInfo
= static_cast<ThreadLocalInfo
*>(aThreadLocal
);
1272 if (threadLocalInfo
) {
1273 MOZ_ASSERT(threadLocalInfo
->mClosed
);
1275 if (threadLocalInfo
->mActor
) {
1276 threadLocalInfo
->mActor
->Close();
1277 threadLocalInfo
->mActor
->AssertActorDestroyed();
1280 delete threadLocalInfo
;
1284 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1285 AssertIsOnOwningThread();
1288 MOZ_ASSERT(!mActorDestroyed
);
1289 mActorDestroyed
= true;
1292 BackgroundChildImpl::ActorDestroy(aWhy
);
1295 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver
, nsIObserver
)
1298 ChildImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1299 const char16_t
* aData
) {
1300 AssertIsOnMainThread();
1301 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1303 ChildImpl::Shutdown();