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 "base/process_util.h"
13 #include "base/task.h"
14 #include "FileDescriptor.h"
15 #include "GeckoProfiler.h"
16 #include "InputStreamUtils.h"
17 #include "mozilla/Assertions.h"
18 #include "mozilla/Atomics.h"
19 #include "mozilla/ClearOnShutdown.h"
20 #include "mozilla/DebugOnly.h"
21 #include "mozilla/MozPromise.h"
22 #include "mozilla/Services.h"
23 #include "mozilla/SpinEventLoopUntil.h"
24 #include "mozilla/StaticPtr.h"
25 #include "mozilla/Unused.h"
26 #include "mozilla/dom/ContentChild.h"
27 #include "mozilla/dom/ContentParent.h"
28 #include "mozilla/dom/File.h"
29 #include "mozilla/dom/WorkerPrivate.h"
30 #include "mozilla/dom/WorkerRef.h"
31 #include "mozilla/ipc/Endpoint.h"
32 #include "mozilla/ipc/ProtocolTypes.h"
33 #include "mozilla/net/SocketProcessChild.h"
34 #include "mozilla/net/SocketProcessBridgeChild.h"
36 #include "nsIEventTarget.h"
37 #include "nsIObserver.h"
38 #include "nsIObserverService.h"
39 #include "nsIRunnable.h"
40 #include "nsISupportsImpl.h"
41 #include "nsIThread.h"
44 #include "nsThreadUtils.h"
45 #include "nsTraceRefcnt.h"
46 #include "nsXULAppAPI.h"
47 #include "nsXPCOMPrivate.h"
52 #ifdef RELEASE_OR_BETA
53 # define THREADSAFETY_ASSERT MOZ_ASSERT
55 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
58 #define CRASH_IN_CHILD_PROCESS(_msg) \
60 if (XRE_IsParentProcess()) { \
61 MOZ_ASSERT(false, _msg); \
67 using namespace mozilla
;
68 using namespace mozilla::dom
;
69 using namespace mozilla::ipc
;
70 using namespace mozilla::net
;
76 // -----------------------------------------------------------------------------
78 // -----------------------------------------------------------------------------
80 void AssertIsInMainProcess() { MOZ_ASSERT(XRE_IsParentProcess()); }
82 void AssertIsInMainOrSocketProcess() {
83 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
86 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
88 void AssertIsNotOnMainThread() { THREADSAFETY_ASSERT(!NS_IsMainThread()); }
90 // -----------------------------------------------------------------------------
91 // ParentImpl Declaration
92 // -----------------------------------------------------------------------------
94 class ParentImpl final
: public BackgroundParentImpl
{
95 friend class mozilla::ipc::BackgroundParent
;
98 class ShutdownObserver
;
99 class CreateActorHelper
;
101 struct MOZ_STACK_CLASS TimerCallbackClosure
{
103 nsTArray
<ParentImpl
*>* mLiveActors
;
105 TimerCallbackClosure(nsIThread
* aThread
, nsTArray
<ParentImpl
*>* aLiveActors
)
106 : mThread(aThread
), mLiveActors(aLiveActors
) {
107 AssertIsInMainOrSocketProcess();
108 AssertIsOnMainThread();
110 MOZ_ASSERT(aLiveActors
);
114 // The length of time we will wait at shutdown for all actors to clean
115 // themselves up before forcing them to be destroyed.
116 static const uint32_t kShutdownTimerDelayMS
= 10000;
118 // This is only modified on the main thread. It is null if the thread does not
119 // exist or is shutting down.
120 static StaticRefPtr
<nsIThread
> sBackgroundThread
;
122 // This is created and destroyed on the main thread but only modified on the
123 // background thread. It is specific to each instance of sBackgroundThread.
124 static nsTArray
<ParentImpl
*>* sLiveActorsForBackgroundThread
;
126 // This is only modified on the main thread.
127 static StaticRefPtr
<nsITimer
> sShutdownTimer
;
129 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
130 // work during shutdown.
131 static Atomic
<PRThread
*> sBackgroundPRThread
;
133 // This is only modified on the main thread. It maintains a count of live
134 // actors so that the background thread can be shut down when it is no longer
136 static uint64_t sLiveActorCount
;
138 // This is only modified on the main thread. It is true after the shutdown
139 // observer is registered and is never unset thereafter.
140 static bool sShutdownObserverRegistered
;
142 // This is only modified on the main thread. It prevents us from trying to
143 // create the background thread after application shutdown has started.
144 static bool sShutdownHasStarted
;
146 // Only touched on the main thread, null if this is a same-process actor.
147 RefPtr
<ContentParent
> mContent
;
149 // Set when the actor is opened successfully and used to handle shutdown
150 // hangs. Only touched on the background thread.
151 nsTArray
<ParentImpl
*>* mLiveActorArray
;
153 // Set at construction to indicate whether this parent actor corresponds to a
154 // child actor in another process or to a child actor from a different thread
155 // in the same process.
156 const bool mIsOtherProcessActor
;
158 // Set after ActorDestroy has been called. Only touched on the background
160 bool mActorDestroyed
;
163 static already_AddRefed
<ChildImpl
> CreateActorForSameProcess(
164 nsIEventTarget
* aMainEventTarget
);
166 static bool IsOnBackgroundThread() {
167 return PR_GetCurrentThread() == sBackgroundPRThread
;
170 static void AssertIsOnBackgroundThread() {
171 THREADSAFETY_ASSERT(IsOnBackgroundThread());
174 // `ParentImpl` instances are created and need to be deleted on the main
175 // thread, despite IPC controlling them on a background thread. Use
176 // `_WITH_DELETE_ON_MAIN_THREAD` to force destruction to occur on the desired
178 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(ParentImpl
,
184 // Forwarded from BackgroundParent.
185 static bool IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
);
187 // Forwarded from BackgroundParent.
188 static already_AddRefed
<ContentParent
> GetContentParent(
189 PBackgroundParent
* aBackgroundActor
);
191 // Forwarded from BackgroundParent.
192 static intptr_t GetRawContentParentForComparison(
193 PBackgroundParent
* aBackgroundActor
);
195 // Forwarded from BackgroundParent.
196 static uint64_t GetChildID(PBackgroundParent
* aBackgroundActor
);
198 // Forwarded from BackgroundParent.
199 static bool GetLiveActorArray(PBackgroundParent
* aBackgroundActor
,
200 nsTArray
<PBackgroundParent
*>& aLiveActorArray
);
202 // Forwarded from BackgroundParent.
203 static bool Alloc(ContentParent
* aContent
,
204 Endpoint
<PBackgroundParent
>&& aEndpoint
);
206 static bool CreateBackgroundThread();
208 static void ShutdownBackgroundThread();
210 static void ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
);
212 // For same-process actors.
214 : mLiveActorArray(nullptr),
215 mIsOtherProcessActor(false),
216 mActorDestroyed(false) {
217 AssertIsInMainProcess();
218 AssertIsOnMainThread();
221 // For other-process actors.
222 // NOTE: ParentImpl could be used in 3 cases below.
223 // 1. Between parent process and content process.
224 // 2. Between socket process and content process.
225 // 3. Between parent process and socket process.
226 // |mContent| should be not null for case 1. For case 2 and 3, it's null.
227 explicit ParentImpl(ContentParent
* aContent
)
228 : mContent(aContent
),
229 mLiveActorArray(nullptr),
230 mIsOtherProcessActor(true),
231 mActorDestroyed(false) {
232 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
233 AssertIsOnMainThread();
237 AssertIsInMainOrSocketProcess();
238 AssertIsOnMainThread();
239 MOZ_ASSERT(!mContent
);
242 void MainThreadActorDestroy();
244 void SetLiveActorArray(nsTArray
<ParentImpl
*>* aLiveActorArray
) {
245 AssertIsInMainOrSocketProcess();
246 AssertIsOnBackgroundThread();
247 MOZ_ASSERT(aLiveActorArray
);
248 MOZ_ASSERT(!aLiveActorArray
->Contains(this));
249 MOZ_ASSERT(!mLiveActorArray
);
250 MOZ_ASSERT(mIsOtherProcessActor
);
252 mLiveActorArray
= aLiveActorArray
;
253 mLiveActorArray
->AppendElement(this);
256 // These methods are only called by IPDL.
257 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
260 // -----------------------------------------------------------------------------
261 // ChildImpl Declaration
262 // -----------------------------------------------------------------------------
264 class ChildImpl final
: public BackgroundChildImpl
{
265 friend class mozilla::ipc::BackgroundChild
;
266 friend class mozilla::ipc::BackgroundChildImpl
;
268 typedef base::ProcessId ProcessId
;
269 typedef mozilla::ipc::Transport Transport
;
271 class ShutdownObserver
;
274 class SendInitBackgroundRunnable
;
276 struct ThreadLocalInfo
{
284 RefPtr
<ChildImpl
> mActor
;
285 RefPtr
<SendInitBackgroundRunnable
> mSendInitBackgroundRunnable
;
286 UniquePtr
<BackgroundChildImpl::ThreadLocal
> mConsumerThreadLocal
;
293 // A thread-local index that is not valid.
294 static constexpr unsigned int kBadThreadLocalIndex
=
295 static_cast<unsigned int>(-1);
297 // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
298 // also provides some common functions for creating PBackground IPC actor.
299 class ThreadInfoWrapper final
{
300 friend class ChildImpl
;
303 using ActorCreateFunc
= void (*)(ThreadLocalInfo
*, unsigned int,
304 nsIEventTarget
*, ChildImpl
**);
306 constexpr explicit ThreadInfoWrapper(ActorCreateFunc aFunc
)
307 : mThreadLocalIndex(kBadThreadLocalIndex
),
308 mMainThreadInfo(nullptr),
309 mCreateActorFunc(aFunc
) {}
312 MOZ_ASSERT(mThreadLocalIndex
== kBadThreadLocalIndex
,
313 "ThreadInfoWrapper::Startup() called more than once!");
316 PR_NewThreadPrivateIndex(&mThreadLocalIndex
, ThreadLocalDestructor
);
317 MOZ_RELEASE_ASSERT(status
== PR_SUCCESS
,
318 "PR_NewThreadPrivateIndex failed!");
320 MOZ_ASSERT(mThreadLocalIndex
!= kBadThreadLocalIndex
);
324 if (sShutdownHasStarted
) {
325 MOZ_ASSERT_IF(mThreadLocalIndex
!= kBadThreadLocalIndex
,
326 !PR_GetThreadPrivate(mThreadLocalIndex
));
330 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
334 ThreadLocalInfo
* threadLocalInfo
;
337 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(mThreadLocalIndex
));
338 MOZ_ASSERT(!threadLocalInfo
);
341 threadLocalInfo
= mMainThreadInfo
;
342 if (threadLocalInfo
) {
344 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
345 threadLocalInfo
->mClosed
= true;
348 ThreadLocalDestructor(threadLocalInfo
);
349 mMainThreadInfo
= nullptr;
353 void CloseForCurrentThread() {
354 MOZ_ASSERT(!NS_IsMainThread());
356 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
360 auto threadLocalInfo
=
361 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(mThreadLocalIndex
));
363 if (!threadLocalInfo
) {
368 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
369 threadLocalInfo
->mClosed
= true;
372 // Clearing the thread local will synchronously close the actor.
373 DebugOnly
<PRStatus
> status
=
374 PR_SetThreadPrivate(mThreadLocalIndex
, nullptr);
375 MOZ_ASSERT(status
== PR_SUCCESS
);
378 PBackgroundChild
* GetOrCreateForCurrentThread(
379 nsIEventTarget
* aMainEventTarget
) {
380 MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget
);
382 MOZ_ASSERT(mThreadLocalIndex
!= kBadThreadLocalIndex
,
383 "BackgroundChild::Startup() was never called!");
385 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted
) {
389 auto threadLocalInfo
= NS_IsMainThread()
391 : static_cast<ThreadLocalInfo
*>(
392 PR_GetThreadPrivate(mThreadLocalIndex
));
394 if (!threadLocalInfo
) {
395 auto newInfo
= MakeUnique
<ThreadLocalInfo
>();
397 if (NS_IsMainThread()) {
398 mMainThreadInfo
= newInfo
.get();
400 if (PR_SetThreadPrivate(mThreadLocalIndex
, newInfo
.get()) !=
402 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
407 threadLocalInfo
= newInfo
.release();
410 PBackgroundChild
* bgChild
=
411 GetFromThreadInfo(aMainEventTarget
, threadLocalInfo
);
416 RefPtr
<ChildImpl
> actor
;
417 mCreateActorFunc(threadLocalInfo
, mThreadLocalIndex
, aMainEventTarget
,
418 getter_AddRefs(actor
));
423 // This is only modified on the main thread. It is the thread-local index
424 // that we use to store the BackgroundChild for each thread.
425 unsigned int mThreadLocalIndex
;
427 // On the main thread, we store TLS in this global instead of in
428 // mThreadLocalIndex. That way, cooperative main threads all share the same
430 ThreadLocalInfo
* mMainThreadInfo
;
431 ActorCreateFunc mCreateActorFunc
;
434 // For PBackground between parent and content process.
435 static ThreadInfoWrapper sParentAndContentProcessThreadInfo
;
437 // For PBackground between socket and content process.
438 static ThreadInfoWrapper sSocketAndContentProcessThreadInfo
;
440 // For PBackground between socket and parent process.
441 static ThreadInfoWrapper sSocketAndParentProcessThreadInfo
;
443 // This is only modified on the main thread. It prevents us from trying to
444 // create the background thread after application shutdown has started.
445 static bool sShutdownHasStarted
;
447 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
448 nsISerialEventTarget
* mOwningEventTarget
;
453 bool mActorDestroyed
;
457 static void Shutdown();
459 void AssertIsOnOwningThread() {
460 THREADSAFETY_ASSERT(mOwningEventTarget
);
462 #ifdef RELEASE_OR_BETA
463 DebugOnly
<bool> current
;
468 NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)));
469 THREADSAFETY_ASSERT(current
);
472 void AssertActorDestroyed() {
473 MOZ_ASSERT(mActorDestroyed
, "ChildImpl::ActorDestroy not called in time");
477 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
478 : mOwningEventTarget(GetCurrentSerialEventTarget())
482 mActorWasAlive(false),
483 mActorDestroyed(false)
486 AssertIsOnOwningThread();
489 void SetActorAlive() {
490 AssertIsOnOwningThread();
491 MOZ_ASSERT(!mActorWasAlive
);
492 MOZ_ASSERT(!mActorDestroyed
);
495 mActorWasAlive
= true;
499 NS_INLINE_DECL_REFCOUNTING(ChildImpl
, override
)
502 // Forwarded from BackgroundChild.
503 static void Startup();
505 // Forwarded from BackgroundChild.
506 static PBackgroundChild
* GetForCurrentThread();
508 // Helper function for getting PBackgroundChild from thread info.
509 static PBackgroundChild
* GetFromThreadInfo(nsIEventTarget
* aMainEventTarget
,
510 ThreadLocalInfo
* aThreadLocalInfo
);
512 // Forwarded from BackgroundChild.
513 static PBackgroundChild
* GetOrCreateForCurrentThread(
514 nsIEventTarget
* aMainEventTarget
);
516 // Forwarded from BackgroundChild.
517 static PBackgroundChild
* GetOrCreateSocketActorForCurrentThread(
518 nsIEventTarget
* aMainEventTarget
);
520 // Forwarded from BackgroundChild.
521 static PBackgroundChild
* GetOrCreateForSocketParentBridgeForCurrentThread(
522 nsIEventTarget
* aMainEventTarget
);
524 static void CloseForCurrentThread();
526 // Forwarded from BackgroundChildImpl.
527 static BackgroundChildImpl::ThreadLocal
* GetThreadLocalForCurrentThread();
529 static void ThreadLocalDestructor(void* aThreadLocal
);
531 // This class is reference counted.
532 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive
, mActorDestroyed
); }
534 // Only called by IPDL.
535 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
538 // -----------------------------------------------------------------------------
539 // ParentImpl Helper Declarations
540 // -----------------------------------------------------------------------------
542 class ParentImpl::ShutdownObserver final
: public nsIObserver
{
544 ShutdownObserver() { AssertIsOnMainThread(); }
550 ~ShutdownObserver() { AssertIsOnMainThread(); }
553 class ParentImpl::CreateActorHelper final
: public Runnable
{
554 mozilla::Monitor mMonitor
;
555 RefPtr
<ParentImpl
> mParentActor
;
556 nsCOMPtr
<nsIThread
> mThread
;
557 nsresult mMainThreadResultCode
;
561 explicit CreateActorHelper()
562 : Runnable("Background::ParentImpl::CreateActorHelper"),
563 mMonitor("CreateActorHelper::mMonitor"),
564 mMainThreadResultCode(NS_OK
),
566 AssertIsInMainOrSocketProcess();
567 AssertIsNotOnMainThread();
570 nsresult
BlockAndGetResults(nsIEventTarget
* aMainEventTarget
,
571 RefPtr
<ParentImpl
>& aParentActor
,
572 nsCOMPtr
<nsIThread
>& aThread
);
575 ~CreateActorHelper() { AssertIsInMainOrSocketProcess(); }
577 nsresult
RunOnMainThread();
582 // -----------------------------------------------------------------------------
583 // ChildImpl Helper Declarations
584 // -----------------------------------------------------------------------------
586 class ChildImpl::ShutdownObserver final
: public nsIObserver
{
588 ShutdownObserver() { AssertIsOnMainThread(); }
594 ~ShutdownObserver() { AssertIsOnMainThread(); }
597 class ChildImpl::SendInitBackgroundRunnable final
: public DiscardableRunnable
{
598 nsCOMPtr
<nsISerialEventTarget
> mOwningEventTarget
;
599 RefPtr
<StrongWorkerRef
> mWorkerRef
;
600 Endpoint
<PBackgroundParent
> mParent
;
601 mozilla::Mutex mMutex
;
602 bool mSentInitBackground
;
603 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)> mSendInitfunc
;
604 unsigned int mThreadLocalIndex
;
607 static already_AddRefed
<SendInitBackgroundRunnable
> Create(
608 Endpoint
<PBackgroundParent
>&& aParent
,
609 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)>&& aFunc
,
610 unsigned int aThreadLocalIndex
);
612 void ClearEventTarget() {
613 mWorkerRef
= nullptr;
615 mozilla::MutexAutoLock
lock(mMutex
);
616 mOwningEventTarget
= nullptr;
620 explicit SendInitBackgroundRunnable(
621 Endpoint
<PBackgroundParent
>&& aParent
,
622 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)>&& aFunc
,
623 unsigned int aThreadLocalIndex
)
624 : DiscardableRunnable(
625 "Background::ChildImpl::SendInitBackgroundRunnable"),
626 mOwningEventTarget(GetCurrentSerialEventTarget()),
627 mParent(std::move(aParent
)),
628 mMutex("SendInitBackgroundRunnable::mMutex"),
629 mSentInitBackground(false),
630 mSendInitfunc(std::move(aFunc
)),
631 mThreadLocalIndex(aThreadLocalIndex
) {}
633 ~SendInitBackgroundRunnable() = default;
643 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
647 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
652 } // namespace mozilla
654 // -----------------------------------------------------------------------------
655 // BackgroundParent Public Methods
656 // -----------------------------------------------------------------------------
659 bool BackgroundParent::IsOtherProcessActor(
660 PBackgroundParent
* aBackgroundActor
) {
661 return ParentImpl::IsOtherProcessActor(aBackgroundActor
);
665 already_AddRefed
<ContentParent
> BackgroundParent::GetContentParent(
666 PBackgroundParent
* aBackgroundActor
) {
667 return ParentImpl::GetContentParent(aBackgroundActor
);
671 intptr_t BackgroundParent::GetRawContentParentForComparison(
672 PBackgroundParent
* aBackgroundActor
) {
673 return ParentImpl::GetRawContentParentForComparison(aBackgroundActor
);
677 uint64_t BackgroundParent::GetChildID(PBackgroundParent
* aBackgroundActor
) {
678 return ParentImpl::GetChildID(aBackgroundActor
);
682 bool BackgroundParent::GetLiveActorArray(
683 PBackgroundParent
* aBackgroundActor
,
684 nsTArray
<PBackgroundParent
*>& aLiveActorArray
) {
685 return ParentImpl::GetLiveActorArray(aBackgroundActor
, aLiveActorArray
);
689 bool BackgroundParent::Alloc(ContentParent
* aContent
,
690 Endpoint
<PBackgroundParent
>&& aEndpoint
) {
691 return ParentImpl::Alloc(aContent
, std::move(aEndpoint
));
694 // -----------------------------------------------------------------------------
695 // BackgroundChild Public Methods
696 // -----------------------------------------------------------------------------
699 void BackgroundChild::Startup() { ChildImpl::Startup(); }
702 PBackgroundChild
* BackgroundChild::GetForCurrentThread() {
703 return ChildImpl::GetForCurrentThread();
707 PBackgroundChild
* BackgroundChild::GetOrCreateForCurrentThread(
708 nsIEventTarget
* aMainEventTarget
) {
709 return ChildImpl::GetOrCreateForCurrentThread(aMainEventTarget
);
713 PBackgroundChild
* BackgroundChild::GetOrCreateSocketActorForCurrentThread(
714 nsIEventTarget
* aMainEventTarget
) {
715 return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget
);
720 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread(
721 nsIEventTarget
* aMainEventTarget
) {
722 return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
727 void BackgroundChild::CloseForCurrentThread() {
728 ChildImpl::CloseForCurrentThread();
731 // -----------------------------------------------------------------------------
732 // BackgroundChildImpl Public Methods
733 // -----------------------------------------------------------------------------
736 BackgroundChildImpl::ThreadLocal
*
737 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
738 return ChildImpl::GetThreadLocalForCurrentThread();
741 // -----------------------------------------------------------------------------
742 // ParentImpl Static Members
743 // -----------------------------------------------------------------------------
745 StaticRefPtr
<nsIThread
> ParentImpl::sBackgroundThread
;
747 nsTArray
<ParentImpl
*>* ParentImpl::sLiveActorsForBackgroundThread
;
749 StaticRefPtr
<nsITimer
> ParentImpl::sShutdownTimer
;
751 Atomic
<PRThread
*> ParentImpl::sBackgroundPRThread
;
753 uint64_t ParentImpl::sLiveActorCount
= 0;
755 bool ParentImpl::sShutdownObserverRegistered
= false;
757 bool ParentImpl::sShutdownHasStarted
= false;
759 // -----------------------------------------------------------------------------
760 // ChildImpl Static Members
761 // -----------------------------------------------------------------------------
763 static void ParentContentActorCreateFunc(
764 ChildImpl::ThreadLocalInfo
* aThreadLocalInfo
,
765 unsigned int aThreadLocalIndex
, nsIEventTarget
* aMainEventTarget
,
766 ChildImpl
** aOutput
) {
767 if (XRE_IsParentProcess()) {
768 RefPtr
<ChildImpl
> strongActor
=
769 ParentImpl::CreateActorForSameProcess(aMainEventTarget
);
770 if (NS_WARN_IF(!strongActor
)) {
774 aThreadLocalInfo
->mActor
= strongActor
;
775 strongActor
.forget(aOutput
);
779 RefPtr
<ContentChild
> content
= ContentChild::GetSingleton();
782 if (content
->IsShuttingDown()) {
783 // The transport for ContentChild is shut down and can't be used to open
788 Endpoint
<PBackgroundParent
> parent
;
789 Endpoint
<PBackgroundChild
> child
;
791 rv
= PBackground::CreateEndpoints(content
->OtherPid(),
792 base::GetCurrentProcId(), &parent
, &child
);
794 NS_WARNING("Failed to create top level actor!");
798 RefPtr
<ChildImpl::SendInitBackgroundRunnable
> runnable
;
799 if (!NS_IsMainThread()) {
800 runnable
= ChildImpl::SendInitBackgroundRunnable::Create(
802 [](Endpoint
<PBackgroundParent
>&& aParent
) {
803 RefPtr
<ContentChild
> content
= ContentChild::GetSingleton();
806 if (!content
->SendInitBackground(std::move(aParent
))) {
807 NS_WARNING("Failed to create top level actor!");
816 RefPtr
<ChildImpl
> strongActor
= new ChildImpl();
818 if (!child
.Bind(strongActor
)) {
819 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
824 strongActor
->SetActorAlive();
826 if (NS_IsMainThread()) {
827 if (!content
->SendInitBackground(std::move(parent
))) {
828 NS_WARNING("Failed to create top level actor!");
832 if (aMainEventTarget
) {
834 aMainEventTarget
->Dispatch(runnable
, NS_DISPATCH_NORMAL
));
836 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
));
839 aThreadLocalInfo
->mSendInitBackgroundRunnable
= runnable
;
842 aThreadLocalInfo
->mActor
= strongActor
;
843 strongActor
.forget(aOutput
);
846 ChildImpl::ThreadInfoWrapper
ChildImpl::sParentAndContentProcessThreadInfo(
847 ParentContentActorCreateFunc
);
849 static void SocketContentActorCreateFunc(
850 ChildImpl::ThreadLocalInfo
* aThreadLocalInfo
,
851 unsigned int aThreadLocalIndex
, nsIEventTarget
* aMainEventTarget
,
852 ChildImpl
** aOutput
) {
853 RefPtr
<SocketProcessBridgeChild
> bridgeChild
=
854 SocketProcessBridgeChild::GetSingleton();
856 if (!bridgeChild
|| bridgeChild
->IsShuttingDown()) {
857 // The transport for SocketProcessBridgeChild is shut down
858 // and can't be used to open PBackground.
862 Endpoint
<PBackgroundParent
> parent
;
863 Endpoint
<PBackgroundChild
> child
;
865 rv
= PBackground::CreateEndpoints(bridgeChild
->SocketProcessPid(),
866 base::GetCurrentProcId(), &parent
, &child
);
868 NS_WARNING("Failed to create top level actor!");
872 RefPtr
<ChildImpl::SendInitBackgroundRunnable
> runnable
;
873 if (!NS_IsMainThread()) {
874 runnable
= ChildImpl::SendInitBackgroundRunnable::Create(
876 [](Endpoint
<PBackgroundParent
>&& aParent
) {
877 RefPtr
<SocketProcessBridgeChild
> bridgeChild
=
878 SocketProcessBridgeChild::GetSingleton();
880 if (!bridgeChild
->SendInitBackground(std::move(aParent
))) {
881 NS_WARNING("Failed to create top level actor!");
890 RefPtr
<ChildImpl
> strongActor
= new ChildImpl();
892 if (!child
.Bind(strongActor
)) {
893 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
898 strongActor
->SetActorAlive();
900 if (NS_IsMainThread()) {
901 if (!bridgeChild
->SendInitBackground(std::move(parent
))) {
902 NS_WARNING("Failed to create top level actor!");
903 // Need to close the IPC channel before ChildImpl getting deleted.
904 strongActor
->Close();
905 strongActor
->AssertActorDestroyed();
909 if (aMainEventTarget
) {
911 aMainEventTarget
->Dispatch(runnable
, NS_DISPATCH_NORMAL
));
913 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
));
916 aThreadLocalInfo
->mSendInitBackgroundRunnable
= runnable
;
919 aThreadLocalInfo
->mActor
= strongActor
;
920 strongActor
.forget(aOutput
);
923 ChildImpl::ThreadInfoWrapper
ChildImpl::sSocketAndContentProcessThreadInfo(
924 SocketContentActorCreateFunc
);
926 static void SocketParentActorCreateFunc(
927 ChildImpl::ThreadLocalInfo
* aThreadLocalInfo
,
928 unsigned int aThreadLocalIndex
, nsIEventTarget
* aMainEventTarget
,
929 ChildImpl
** aOutput
) {
930 SocketProcessChild
* socketChild
= SocketProcessChild::GetSingleton();
932 if (!socketChild
|| socketChild
->IsShuttingDown()) {
936 Endpoint
<PBackgroundParent
> parent
;
937 Endpoint
<PBackgroundChild
> child
;
939 rv
= PBackground::CreateEndpoints(socketChild
->OtherPid(),
940 base::GetCurrentProcId(), &parent
, &child
);
942 NS_WARNING("Failed to create top level actor!");
946 RefPtr
<ChildImpl::SendInitBackgroundRunnable
> runnable
;
947 if (!NS_IsMainThread()) {
948 runnable
= ChildImpl::SendInitBackgroundRunnable::Create(
950 [](Endpoint
<PBackgroundParent
>&& aParent
) {
951 SocketProcessChild
* socketChild
= SocketProcessChild::GetSingleton();
952 MOZ_ASSERT(socketChild
);
954 if (!socketChild
->SendInitBackground(std::move(aParent
))) {
955 MOZ_CRASH("Failed to create top level actor!");
964 RefPtr
<ChildImpl
> strongActor
= new ChildImpl();
966 if (!child
.Bind(strongActor
)) {
967 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
971 strongActor
->SetActorAlive();
973 if (NS_IsMainThread()) {
974 if (!socketChild
->SendInitBackground(std::move(parent
))) {
975 NS_WARNING("Failed to create top level actor!");
979 if (aMainEventTarget
) {
981 aMainEventTarget
->Dispatch(runnable
, NS_DISPATCH_NORMAL
));
983 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
));
986 aThreadLocalInfo
->mSendInitBackgroundRunnable
= runnable
;
989 aThreadLocalInfo
->mActor
= strongActor
;
990 strongActor
.forget(aOutput
);
993 ChildImpl::ThreadInfoWrapper
ChildImpl::sSocketAndParentProcessThreadInfo(
994 SocketParentActorCreateFunc
);
996 bool ChildImpl::sShutdownHasStarted
= false;
998 // -----------------------------------------------------------------------------
999 // ParentImpl Implementation
1000 // -----------------------------------------------------------------------------
1003 bool ParentImpl::IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
) {
1004 AssertIsOnBackgroundThread();
1005 MOZ_ASSERT(aBackgroundActor
);
1007 return static_cast<ParentImpl
*>(aBackgroundActor
)->mIsOtherProcessActor
;
1011 already_AddRefed
<ContentParent
> ParentImpl::GetContentParent(
1012 PBackgroundParent
* aBackgroundActor
) {
1013 AssertIsOnBackgroundThread();
1014 MOZ_ASSERT(aBackgroundActor
);
1016 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
1017 if (actor
->mActorDestroyed
) {
1018 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1022 if (actor
->mContent
) {
1023 // We need to hand out a reference to our ContentParent but we also need to
1024 // keep the one we have. We can't call AddRef here because ContentParent is
1025 // not threadsafe so instead we dispatch a runnable to the main thread to do
1026 // it for us. This is safe since we are guaranteed that our AddRef runnable
1027 // will run before the reference we hand out can be released, and the
1028 // ContentParent can't die as long as the existing reference is maintained.
1029 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
1030 "ContentParent::AddRef", actor
->mContent
, &ContentParent::AddRef
)));
1033 return already_AddRefed
<ContentParent
>(actor
->mContent
.get());
1037 intptr_t ParentImpl::GetRawContentParentForComparison(
1038 PBackgroundParent
* aBackgroundActor
) {
1039 AssertIsOnBackgroundThread();
1040 MOZ_ASSERT(aBackgroundActor
);
1042 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
1043 if (actor
->mActorDestroyed
) {
1045 "GetRawContentParentForComparison called after ActorDestroy was "
1047 return intptr_t(-1);
1050 return intptr_t(static_cast<ContentParent
*>(actor
->mContent
.get()));
1054 uint64_t ParentImpl::GetChildID(PBackgroundParent
* aBackgroundActor
) {
1055 AssertIsOnBackgroundThread();
1056 MOZ_ASSERT(aBackgroundActor
);
1058 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
1059 if (actor
->mActorDestroyed
) {
1060 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1064 if (actor
->mContent
) {
1065 return actor
->mContent
->ChildID();
1072 bool ParentImpl::GetLiveActorArray(
1073 PBackgroundParent
* aBackgroundActor
,
1074 nsTArray
<PBackgroundParent
*>& aLiveActorArray
) {
1075 AssertIsOnBackgroundThread();
1076 MOZ_ASSERT(aBackgroundActor
);
1077 MOZ_ASSERT(aLiveActorArray
.IsEmpty());
1079 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
1080 if (actor
->mActorDestroyed
) {
1082 "GetLiveActorArray called after ActorDestroy was called!");
1086 if (!actor
->mLiveActorArray
) {
1090 for (ParentImpl
* liveActor
: *actor
->mLiveActorArray
) {
1091 aLiveActorArray
.AppendElement(liveActor
);
1098 bool ParentImpl::Alloc(ContentParent
* aContent
,
1099 Endpoint
<PBackgroundParent
>&& aEndpoint
) {
1100 AssertIsInMainOrSocketProcess();
1101 AssertIsOnMainThread();
1102 MOZ_ASSERT(aEndpoint
.IsValid());
1104 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
1105 NS_WARNING("Failed to create background thread!");
1109 MOZ_ASSERT(sLiveActorsForBackgroundThread
);
1113 RefPtr
<ParentImpl
> actor
= new ParentImpl(aContent
);
1115 if (NS_FAILED(sBackgroundThread
->Dispatch(NS_NewRunnableFunction(
1116 "Background::ParentImpl::ConnectActorRunnable",
1117 [actor
= std::move(actor
), endpoint
= std::move(aEndpoint
),
1118 liveActorArray
= sLiveActorsForBackgroundThread
]() mutable {
1119 MOZ_ASSERT(endpoint
.IsValid());
1120 MOZ_ASSERT(liveActorArray
);
1121 // Transfer ownership to this thread. If Open() fails then we will
1122 // release this reference in Destroy.
1123 ParentImpl
* actorTmp
;
1124 actor
.forget(&actorTmp
);
1126 if (!endpoint
.Bind(actorTmp
)) {
1127 actorTmp
->Destroy();
1131 actorTmp
->SetLiveActorArray(liveActorArray
);
1133 NS_WARNING("Failed to dispatch connect runnable!");
1135 MOZ_ASSERT(sLiveActorCount
);
1143 already_AddRefed
<ChildImpl
> ParentImpl::CreateActorForSameProcess(
1144 nsIEventTarget
* aMainEventTarget
) {
1145 AssertIsInMainProcess();
1147 RefPtr
<ParentImpl
> parentActor
;
1148 nsCOMPtr
<nsIThread
> backgroundThread
;
1150 if (NS_IsMainThread()) {
1151 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
1152 NS_WARNING("Failed to create background thread!");
1156 MOZ_ASSERT(!sShutdownHasStarted
);
1160 parentActor
= new ParentImpl();
1161 backgroundThread
= sBackgroundThread
.get();
1163 RefPtr
<CreateActorHelper
> helper
= new CreateActorHelper();
1165 nsresult rv
= helper
->BlockAndGetResults(aMainEventTarget
, parentActor
,
1167 if (NS_WARN_IF(NS_FAILED(rv
))) {
1172 RefPtr
<ChildImpl
> childActor
= new ChildImpl();
1174 MessageChannel
* parentChannel
= parentActor
->GetIPCChannel();
1175 MOZ_ASSERT(parentChannel
);
1177 if (!childActor
->Open(parentChannel
, backgroundThread
, ChildSide
)) {
1178 NS_WARNING("Failed to open ChildImpl!");
1180 // Can't release it here, we will release this reference in Destroy.
1182 parentActor
.forget(&actor
);
1189 childActor
->SetActorAlive();
1191 // Make sure the parent knows it is same process.
1192 parentActor
->SetOtherProcessId(base::GetCurrentProcId());
1194 // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
1195 Unused
<< parentActor
.forget();
1197 return childActor
.forget();
1201 bool ParentImpl::CreateBackgroundThread() {
1202 AssertIsInMainOrSocketProcess();
1203 AssertIsOnMainThread();
1204 MOZ_ASSERT(!sBackgroundThread
);
1205 MOZ_ASSERT(!sLiveActorsForBackgroundThread
);
1207 if (sShutdownHasStarted
) {
1209 "Trying to create background thread after shutdown has "
1214 nsCOMPtr
<nsITimer
> newShutdownTimer
;
1216 if (!sShutdownTimer
) {
1217 newShutdownTimer
= NS_NewTimer();
1218 if (!newShutdownTimer
) {
1223 if (!sShutdownObserverRegistered
) {
1224 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1225 if (NS_WARN_IF(!obs
)) {
1229 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
1231 nsresult rv
= obs
->AddObserver(
1232 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
1233 if (NS_WARN_IF(NS_FAILED(rv
))) {
1237 sShutdownObserverRegistered
= true;
1240 nsCOMPtr
<nsIThread
> thread
;
1241 if (NS_FAILED(NS_NewNamedThread(
1242 "IPDL Background", getter_AddRefs(thread
),
1243 NS_NewRunnableFunction(
1244 "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
1245 DebugOnly
<PRThread
*> oldBackgroundThread
=
1246 sBackgroundPRThread
.exchange(PR_GetCurrentThread());
1248 MOZ_ASSERT_IF(oldBackgroundThread
,
1249 PR_GetCurrentThread() != oldBackgroundThread
);
1251 NS_WARNING("NS_NewNamedThread failed!");
1255 sBackgroundThread
= thread
.forget();
1257 sLiveActorsForBackgroundThread
= new nsTArray
<ParentImpl
*>(1);
1259 if (!sShutdownTimer
) {
1260 MOZ_ASSERT(newShutdownTimer
);
1261 sShutdownTimer
= newShutdownTimer
;
1268 void ParentImpl::ShutdownBackgroundThread() {
1269 AssertIsInMainOrSocketProcess();
1270 AssertIsOnMainThread();
1271 MOZ_ASSERT(sShutdownHasStarted
);
1272 MOZ_ASSERT_IF(!sBackgroundThread
, !sLiveActorCount
);
1273 MOZ_ASSERT_IF(sBackgroundThread
, sShutdownTimer
);
1275 nsCOMPtr
<nsITimer
> shutdownTimer
= sShutdownTimer
.get();
1276 sShutdownTimer
= nullptr;
1278 if (sBackgroundThread
) {
1279 nsCOMPtr
<nsIThread
> thread
= sBackgroundThread
.get();
1280 sBackgroundThread
= nullptr;
1282 UniquePtr
<nsTArray
<ParentImpl
*>> liveActors(sLiveActorsForBackgroundThread
);
1283 sLiveActorsForBackgroundThread
= nullptr;
1285 MOZ_ASSERT_IF(!sShutdownHasStarted
, !sLiveActorCount
);
1287 if (sLiveActorCount
) {
1288 // We need to spin the event loop while we wait for all the actors to be
1289 // cleaned up. We also set a timeout to force-kill any hanging actors.
1290 TimerCallbackClosure
closure(thread
, liveActors
.get());
1292 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->InitWithNamedFuncCallback(
1293 &ShutdownTimerCallback
, &closure
, kShutdownTimerDelayMS
,
1294 nsITimer::TYPE_ONE_SHOT
, "ParentImpl::ShutdownTimerCallback"));
1296 SpinEventLoopUntil([&]() { return !sLiveActorCount
; });
1298 MOZ_ASSERT(liveActors
->IsEmpty());
1300 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->Cancel());
1303 // Dispatch this runnable to unregister the PR thread from the profiler.
1304 MOZ_ALWAYS_SUCCEEDS(thread
->Dispatch(NS_NewRunnableFunction(
1305 "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
1306 // It is possible that another background thread was created while
1307 // this thread was shutting down. In that case we can't assert
1308 // anything about sBackgroundPRThread and we should not modify it
1310 sBackgroundPRThread
.compareExchange(PR_GetCurrentThread(), nullptr);
1313 MOZ_ALWAYS_SUCCEEDS(thread
->Shutdown());
1318 void ParentImpl::ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
) {
1319 AssertIsInMainOrSocketProcess();
1320 AssertIsOnMainThread();
1321 MOZ_ASSERT(sShutdownHasStarted
);
1322 MOZ_ASSERT(sLiveActorCount
);
1324 auto closure
= static_cast<TimerCallbackClosure
*>(aClosure
);
1325 MOZ_ASSERT(closure
);
1327 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1331 InvokeAsync(closure
->mThread
, __func__
,
1332 [liveActors
= closure
->mLiveActors
]() {
1333 MOZ_ASSERT(liveActors
);
1335 if (!liveActors
->IsEmpty()) {
1336 // Copy the array since calling Close() could mutate the
1338 nsTArray
<ParentImpl
*> actorsToClose(liveActors
->Clone());
1339 for (ParentImpl
* actor
: actorsToClose
) {
1343 return GenericPromise::CreateAndResolve(true, __func__
);
1345 ->Then(GetCurrentSerialEventTarget(), __func__
, []() {
1346 MOZ_ASSERT(sLiveActorCount
);
1351 void ParentImpl::Destroy() {
1352 // May be called on any thread!
1354 AssertIsInMainOrSocketProcess();
1356 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1357 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1358 &ParentImpl::MainThreadActorDestroy
)));
1361 void ParentImpl::MainThreadActorDestroy() {
1362 AssertIsInMainOrSocketProcess();
1363 AssertIsOnMainThread();
1364 MOZ_ASSERT_IF(!mIsOtherProcessActor
, !mContent
);
1368 MOZ_ASSERT(sLiveActorCount
);
1371 // This may be the last reference!
1375 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1376 AssertIsInMainOrSocketProcess();
1377 AssertIsOnBackgroundThread();
1378 MOZ_ASSERT(!mActorDestroyed
);
1379 MOZ_ASSERT_IF(mIsOtherProcessActor
, mLiveActorArray
);
1381 BackgroundParentImpl::ActorDestroy(aWhy
);
1383 mActorDestroyed
= true;
1385 if (mLiveActorArray
) {
1386 MOZ_ALWAYS_TRUE(mLiveActorArray
->RemoveElement(this));
1387 mLiveActorArray
= nullptr;
1390 // This is tricky. We should be able to call Destroy() here directly because
1391 // we're not going to touch 'this' or our MessageChannel any longer on this
1392 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1393 // it runs it will destroy 'this' and our associated MessageChannel. However,
1394 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1395 // racing with the main thread we must ensure that the MessageChannel lives
1396 // long enough to be cleared in this call stack.
1398 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1399 "ParentImpl::Destroy", this, &ParentImpl::Destroy
)));
1402 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver
, nsIObserver
)
1405 ParentImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1406 const char16_t
* aData
) {
1407 AssertIsInMainOrSocketProcess();
1408 AssertIsOnMainThread();
1409 MOZ_ASSERT(!sShutdownHasStarted
);
1410 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1412 sShutdownHasStarted
= true;
1414 // Do this first before calling (and spinning the event loop in)
1415 // ShutdownBackgroundThread().
1416 ChildImpl::Shutdown();
1418 ShutdownBackgroundThread();
1423 nsresult
ParentImpl::CreateActorHelper::BlockAndGetResults(
1424 nsIEventTarget
* aMainEventTarget
, RefPtr
<ParentImpl
>& aParentActor
,
1425 nsCOMPtr
<nsIThread
>& aThread
) {
1426 AssertIsNotOnMainThread();
1428 if (aMainEventTarget
) {
1429 MOZ_ALWAYS_SUCCEEDS(aMainEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
1431 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1434 mozilla::MonitorAutoLock
lock(mMonitor
);
1439 if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode
))) {
1440 return mMainThreadResultCode
;
1443 aParentActor
= std::move(mParentActor
);
1444 aThread
= std::move(mThread
);
1448 nsresult
ParentImpl::CreateActorHelper::RunOnMainThread() {
1449 AssertIsOnMainThread();
1451 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
1452 NS_WARNING("Failed to create background thread!");
1453 return NS_ERROR_FAILURE
;
1456 MOZ_ASSERT(!sShutdownHasStarted
);
1460 mParentActor
= new ParentImpl();
1461 mThread
= sBackgroundThread
;
1467 ParentImpl::CreateActorHelper::Run() {
1468 AssertIsOnMainThread();
1470 nsresult rv
= RunOnMainThread();
1471 if (NS_WARN_IF(NS_FAILED(rv
))) {
1472 mMainThreadResultCode
= rv
;
1475 mozilla::MonitorAutoLock
lock(mMonitor
);
1476 MOZ_ASSERT(mWaiting
);
1484 // -----------------------------------------------------------------------------
1485 // ChildImpl Implementation
1486 // -----------------------------------------------------------------------------
1489 void ChildImpl::Startup() {
1490 // This happens on the main thread but before XPCOM has started so we can't
1491 // assert that we're being called on the main thread here.
1493 sParentAndContentProcessThreadInfo
.Startup();
1494 sSocketAndContentProcessThreadInfo
.Startup();
1495 sSocketAndParentProcessThreadInfo
.Startup();
1497 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1498 MOZ_RELEASE_ASSERT(observerService
);
1500 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
1502 nsresult rv
= observerService
->AddObserver(
1503 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
1504 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
1508 void ChildImpl::Shutdown() {
1509 AssertIsOnMainThread();
1511 sParentAndContentProcessThreadInfo
.Shutdown();
1512 sSocketAndContentProcessThreadInfo
.Shutdown();
1513 sSocketAndParentProcessThreadInfo
.Shutdown();
1515 sShutdownHasStarted
= true;
1519 PBackgroundChild
* ChildImpl::GetForCurrentThread() {
1520 MOZ_ASSERT(sParentAndContentProcessThreadInfo
.mThreadLocalIndex
!=
1521 kBadThreadLocalIndex
);
1523 auto threadLocalInfo
=
1525 ? sParentAndContentProcessThreadInfo
.mMainThreadInfo
1526 : static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(
1527 sParentAndContentProcessThreadInfo
.mThreadLocalIndex
));
1529 if (!threadLocalInfo
) {
1533 return threadLocalInfo
->mActor
;
1537 PBackgroundChild
* ChildImpl::GetFromThreadInfo(
1538 nsIEventTarget
* aMainEventTarget
, ThreadLocalInfo
* aThreadLocalInfo
) {
1539 MOZ_ASSERT(aThreadLocalInfo
);
1541 if (aThreadLocalInfo
->mActor
) {
1542 RefPtr
<SendInitBackgroundRunnable
>& runnable
=
1543 aThreadLocalInfo
->mSendInitBackgroundRunnable
;
1545 if (aMainEventTarget
&& runnable
) {
1546 // The SendInitBackgroundRunnable was already dispatched to the main
1547 // thread to finish initialization of a new background child actor.
1548 // However, the caller passed a custom main event target which indicates
1549 // that synchronous blocking of the main thread is happening (done by
1550 // creating a nested event target and spinning the event loop).
1551 // It can happen that the SendInitBackgroundRunnable didn't have a chance
1552 // to run before the synchronous blocking has occured. Unblocking of the
1553 // main thread can depend on an IPC message received on this thread, so
1554 // we have to dispatch the SendInitBackgroundRunnable to the custom main
1555 // event target too, otherwise IPC will be only queueing messages on this
1556 // thread. The runnable will run twice in the end, but that's a harmless
1557 // race between the main and nested event queue of the main thread.
1558 // There's a guard in the runnable implementation for calling
1559 // SendInitBackground only once.
1561 MOZ_ALWAYS_SUCCEEDS(
1562 aMainEventTarget
->Dispatch(runnable
, NS_DISPATCH_NORMAL
));
1565 return aThreadLocalInfo
->mActor
;
1572 PBackgroundChild
* ChildImpl::GetOrCreateForCurrentThread(
1573 nsIEventTarget
* aMainEventTarget
) {
1574 return sParentAndContentProcessThreadInfo
.GetOrCreateForCurrentThread(
1579 PBackgroundChild
* ChildImpl::GetOrCreateSocketActorForCurrentThread(
1580 nsIEventTarget
* aMainEventTarget
) {
1581 return sSocketAndContentProcessThreadInfo
.GetOrCreateForCurrentThread(
1586 PBackgroundChild
* ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
1587 nsIEventTarget
* aMainEventTarget
) {
1588 return sSocketAndParentProcessThreadInfo
.GetOrCreateForCurrentThread(
1593 void ChildImpl::CloseForCurrentThread() {
1594 MOZ_ASSERT(!NS_IsMainThread(),
1595 "PBackground for the main thread should be shut down via "
1596 "ChildImpl::Shutdown().");
1598 sParentAndContentProcessThreadInfo
.CloseForCurrentThread();
1599 sSocketAndContentProcessThreadInfo
.CloseForCurrentThread();
1600 sSocketAndParentProcessThreadInfo
.CloseForCurrentThread();
1604 BackgroundChildImpl::ThreadLocal
* ChildImpl::GetThreadLocalForCurrentThread() {
1605 MOZ_ASSERT(sParentAndContentProcessThreadInfo
.mThreadLocalIndex
!=
1606 kBadThreadLocalIndex
,
1607 "BackgroundChild::Startup() was never called!");
1609 auto threadLocalInfo
=
1611 ? sParentAndContentProcessThreadInfo
.mMainThreadInfo
1612 : static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(
1613 sParentAndContentProcessThreadInfo
.mThreadLocalIndex
));
1615 if (!threadLocalInfo
) {
1619 if (!threadLocalInfo
->mConsumerThreadLocal
) {
1620 threadLocalInfo
->mConsumerThreadLocal
=
1621 MakeUnique
<BackgroundChildImpl::ThreadLocal
>();
1624 return threadLocalInfo
->mConsumerThreadLocal
.get();
1628 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal
) {
1629 auto threadLocalInfo
= static_cast<ThreadLocalInfo
*>(aThreadLocal
);
1631 if (threadLocalInfo
) {
1632 MOZ_ASSERT(threadLocalInfo
->mClosed
);
1634 if (threadLocalInfo
->mActor
) {
1635 threadLocalInfo
->mActor
->Close();
1636 threadLocalInfo
->mActor
->AssertActorDestroyed();
1639 if (threadLocalInfo
->mSendInitBackgroundRunnable
) {
1640 threadLocalInfo
->mSendInitBackgroundRunnable
->ClearEventTarget();
1643 delete threadLocalInfo
;
1647 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1648 AssertIsOnOwningThread();
1651 MOZ_ASSERT(!mActorDestroyed
);
1652 mActorDestroyed
= true;
1655 BackgroundChildImpl::ActorDestroy(aWhy
);
1658 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver
, nsIObserver
)
1661 ChildImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1662 const char16_t
* aData
) {
1663 AssertIsOnMainThread();
1664 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1666 ChildImpl::Shutdown();
1672 already_AddRefed
<ChildImpl::SendInitBackgroundRunnable
>
1673 ChildImpl::SendInitBackgroundRunnable::Create(
1674 Endpoint
<PBackgroundParent
>&& aParent
,
1675 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)>&& aFunc
,
1676 unsigned int aThreadLocalIndex
) {
1677 MOZ_ASSERT(!NS_IsMainThread());
1679 RefPtr
<SendInitBackgroundRunnable
> runnable
= new SendInitBackgroundRunnable(
1680 std::move(aParent
), std::move(aFunc
), aThreadLocalIndex
);
1682 WorkerPrivate
* workerPrivate
= mozilla::dom::GetCurrentThreadWorkerPrivate();
1683 if (!workerPrivate
) {
1684 return runnable
.forget();
1687 workerPrivate
->AssertIsOnWorkerThread();
1689 runnable
->mWorkerRef
= StrongWorkerRef::Create(
1690 workerPrivate
, "ChildImpl::SendInitBackgroundRunnable");
1691 if (NS_WARN_IF(!runnable
->mWorkerRef
)) {
1695 return runnable
.forget();
1699 ChildImpl::SendInitBackgroundRunnable::Run() {
1700 if (NS_IsMainThread()) {
1701 if (mSentInitBackground
) {
1705 mSentInitBackground
= true;
1707 mSendInitfunc(std::move(mParent
));
1709 nsCOMPtr
<nsISerialEventTarget
> owningEventTarget
;
1711 mozilla::MutexAutoLock
lock(mMutex
);
1712 owningEventTarget
= mOwningEventTarget
;
1715 if (!owningEventTarget
) {
1719 nsresult rv
= owningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
);
1720 if (NS_WARN_IF(NS_FAILED(rv
))) {
1729 auto threadLocalInfo
=
1730 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(mThreadLocalIndex
));
1732 if (!threadLocalInfo
) {
1736 threadLocalInfo
->mSendInitBackgroundRunnable
= nullptr;