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/Services.h"
22 #include "mozilla/StaticPtr.h"
23 #include "mozilla/Unused.h"
24 #include "mozilla/dom/ContentChild.h"
25 #include "mozilla/dom/ContentParent.h"
26 #include "mozilla/dom/File.h"
27 #include "mozilla/dom/WorkerPrivate.h"
28 #include "mozilla/dom/WorkerRef.h"
29 #include "mozilla/ipc/ProtocolTypes.h"
30 #include "mozilla/net/SocketProcessBridgeChild.h"
31 #include "nsAutoPtr.h"
33 #include "nsIEventTarget.h"
34 #include "nsIMutable.h"
35 #include "nsIObserver.h"
36 #include "nsIObserverService.h"
37 #include "nsIRunnable.h"
38 #include "nsISupportsImpl.h"
39 #include "nsIThread.h"
42 #include "nsThreadUtils.h"
43 #include "nsTraceRefcnt.h"
44 #include "nsXULAppAPI.h"
45 #include "nsXPCOMPrivate.h"
50 #ifdef RELEASE_OR_BETA
51 # define THREADSAFETY_ASSERT MOZ_ASSERT
53 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
56 #define CRASH_IN_CHILD_PROCESS(_msg) \
58 if (XRE_IsParentProcess()) { \
59 MOZ_ASSERT(false, _msg); \
65 using namespace mozilla
;
66 using namespace mozilla::dom
;
67 using namespace mozilla::ipc
;
68 using namespace mozilla::net
;
74 // -----------------------------------------------------------------------------
76 // -----------------------------------------------------------------------------
78 void AssertIsInMainProcess() { MOZ_ASSERT(XRE_IsParentProcess()); }
80 void AssertIsInMainOrSocketProcess() {
81 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
84 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
86 void AssertIsNotOnMainThread() { THREADSAFETY_ASSERT(!NS_IsMainThread()); }
88 // -----------------------------------------------------------------------------
89 // ParentImpl Declaration
90 // -----------------------------------------------------------------------------
92 class ParentImpl final
: public BackgroundParentImpl
{
93 friend class mozilla::ipc::BackgroundParent
;
99 class ShutdownObserver
;
100 class RequestMessageLoopRunnable
;
101 class ShutdownBackgroundThreadRunnable
;
102 class ForceCloseBackgroundActorsRunnable
;
103 class ConnectActorRunnable
;
104 class CreateActorHelper
;
106 struct MOZ_STACK_CLASS TimerCallbackClosure
{
108 nsTArray
<ParentImpl
*>* mLiveActors
;
110 TimerCallbackClosure(nsIThread
* aThread
, nsTArray
<ParentImpl
*>* aLiveActors
)
111 : mThread(aThread
), mLiveActors(aLiveActors
) {
112 AssertIsInMainOrSocketProcess();
113 AssertIsOnMainThread();
115 MOZ_ASSERT(aLiveActors
);
119 // The length of time we will wait at shutdown for all actors to clean
120 // themselves up before forcing them to be destroyed.
121 static const uint32_t kShutdownTimerDelayMS
= 10000;
123 // This is only modified on the main thread. It is null if the thread does not
124 // exist or is shutting down.
125 static StaticRefPtr
<nsIThread
> sBackgroundThread
;
127 // This is created and destroyed on the main thread but only modified on the
128 // background thread. It is specific to each instance of sBackgroundThread.
129 static nsTArray
<ParentImpl
*>* sLiveActorsForBackgroundThread
;
131 // This is only modified on the main thread.
132 static StaticRefPtr
<nsITimer
> sShutdownTimer
;
134 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
135 // work during shutdown.
136 static Atomic
<PRThread
*> sBackgroundPRThread
;
138 // This is only modified on the main thread. It is null if the thread does not
139 // exist or is shutting down.
140 static MessageLoop
* sBackgroundThreadMessageLoop
;
142 // This is only modified on the main thread. It maintains a count of live
143 // actors so that the background thread can be shut down when it is no longer
145 static uint64_t sLiveActorCount
;
147 // This is only modified on the main thread. It is true after the shutdown
148 // observer is registered and is never unset thereafter.
149 static bool sShutdownObserverRegistered
;
151 // This is only modified on the main thread. It prevents us from trying to
152 // create the background thread after application shutdown has started.
153 static bool sShutdownHasStarted
;
155 // Only touched on the main thread, null if this is a same-process actor.
156 RefPtr
<ContentParent
> mContent
;
158 // Set when the actor is opened successfully and used to handle shutdown
159 // hangs. Only touched on the background thread.
160 nsTArray
<ParentImpl
*>* mLiveActorArray
;
162 // Set at construction to indicate whether this parent actor corresponds to a
163 // child actor in another process or to a child actor from a different thread
164 // in the same process.
165 const bool mIsOtherProcessActor
;
167 // Set after ActorDestroy has been called. Only touched on the background
169 bool mActorDestroyed
;
172 static already_AddRefed
<ChildImpl
> CreateActorForSameProcess(
173 nsIEventTarget
* aMainEventTarget
);
175 static bool IsOnBackgroundThread() {
176 return PR_GetCurrentThread() == sBackgroundPRThread
;
179 static void AssertIsOnBackgroundThread() {
180 THREADSAFETY_ASSERT(IsOnBackgroundThread());
183 NS_INLINE_DECL_REFCOUNTING(ParentImpl
)
188 // Forwarded from BackgroundParent.
189 static bool IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
);
191 // Forwarded from BackgroundParent.
192 static already_AddRefed
<ContentParent
> GetContentParent(
193 PBackgroundParent
* aBackgroundActor
);
195 // Forwarded from BackgroundParent.
196 static intptr_t GetRawContentParentForComparison(
197 PBackgroundParent
* aBackgroundActor
);
199 // Forwarded from BackgroundParent.
200 static uint64_t GetChildID(PBackgroundParent
* aBackgroundActor
);
202 // Forwarded from BackgroundParent.
203 static bool GetLiveActorArray(PBackgroundParent
* aBackgroundActor
,
204 nsTArray
<PBackgroundParent
*>& aLiveActorArray
);
206 // Forwarded from BackgroundParent.
207 static bool Alloc(ContentParent
* aContent
,
208 Endpoint
<PBackgroundParent
>&& aEndpoint
);
210 static bool CreateBackgroundThread();
212 static void ShutdownBackgroundThread();
214 static void ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
);
216 // For same-process actors.
218 : mLiveActorArray(nullptr),
219 mIsOtherProcessActor(false),
220 mActorDestroyed(false) {
221 AssertIsInMainProcess();
222 AssertIsOnMainThread();
225 // For other-process actors.
226 explicit ParentImpl(ContentParent
* aContent
)
227 : mContent(aContent
),
228 mLiveActorArray(nullptr),
229 mIsOtherProcessActor(true),
230 mActorDestroyed(false) {
231 MOZ_ASSERT((XRE_IsParentProcess() && aContent
) || XRE_IsSocketProcess());
232 AssertIsOnMainThread();
236 AssertIsInMainOrSocketProcess();
237 AssertIsOnMainThread();
238 MOZ_ASSERT(!mContent
);
241 void MainThreadActorDestroy();
243 void SetLiveActorArray(nsTArray
<ParentImpl
*>* aLiveActorArray
) {
244 AssertIsInMainOrSocketProcess();
245 AssertIsOnBackgroundThread();
246 MOZ_ASSERT(aLiveActorArray
);
247 MOZ_ASSERT(!aLiveActorArray
->Contains(this));
248 MOZ_ASSERT(!mLiveActorArray
);
249 MOZ_ASSERT(mIsOtherProcessActor
);
251 mLiveActorArray
= aLiveActorArray
;
252 mLiveActorArray
->AppendElement(this);
255 // These methods are only called by IPDL.
256 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
259 // -----------------------------------------------------------------------------
260 // ChildImpl Declaration
261 // -----------------------------------------------------------------------------
263 class ChildImpl final
: public BackgroundChildImpl
{
264 friend class mozilla::ipc::BackgroundChild
;
265 friend class mozilla::ipc::BackgroundChildImpl
;
267 typedef base::ProcessId ProcessId
;
268 typedef mozilla::ipc::Transport Transport
;
270 class ShutdownObserver
;
271 class SendInitBackgroundRunnable
;
273 // A thread-local index that is not valid.
274 static const unsigned int kBadThreadLocalIndex
=
275 static_cast<unsigned int>(-1);
277 // This is only modified on the main thread. It is the thread-local index that
278 // we use to store the BackgroundChild for each thread.
279 static unsigned int sThreadLocalIndex
;
280 static unsigned int sThreadLocalIndexForSocketProcess
;
282 struct ThreadLocalInfo
{
290 RefPtr
<ChildImpl
> mActor
;
291 RefPtr
<SendInitBackgroundRunnable
> mSendInitBackgroundRunnable
;
292 nsAutoPtr
<BackgroundChildImpl::ThreadLocal
> mConsumerThreadLocal
;
298 // On the main thread, we store TLS in this global instead of in
299 // sThreadLocalIndex. That way, cooperative main threads all share the same
301 static ThreadLocalInfo
* sMainThreadInfo
;
303 static ThreadLocalInfo
* sMainThreadInfoForSocketProcess
;
305 // This is only modified on the main thread. It prevents us from trying to
306 // create the background thread after application shutdown has started.
307 static bool sShutdownHasStarted
;
309 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
310 nsISerialEventTarget
* mOwningEventTarget
;
315 bool mActorDestroyed
;
319 static void Shutdown();
321 static void ShutdownWithThreadLocalIndex(unsigned int aThreadLocalIndex
);
323 void AssertIsOnOwningThread() {
324 THREADSAFETY_ASSERT(mOwningEventTarget
);
326 #ifdef RELEASE_OR_BETA
327 DebugOnly
<bool> current
;
332 NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)));
333 THREADSAFETY_ASSERT(current
);
336 void AssertActorDestroyed() {
337 MOZ_ASSERT(mActorDestroyed
, "ChildImpl::ActorDestroy not called in time");
341 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
342 : mOwningEventTarget(GetCurrentThreadSerialEventTarget())
346 mActorWasAlive(false),
347 mActorDestroyed(false)
350 AssertIsOnOwningThread();
353 void SetActorAlive() {
354 AssertIsOnOwningThread();
355 MOZ_ASSERT(!mActorWasAlive
);
356 MOZ_ASSERT(!mActorDestroyed
);
359 mActorWasAlive
= true;
363 NS_INLINE_DECL_REFCOUNTING(ChildImpl
)
366 // Forwarded from BackgroundChild.
367 static void Startup();
369 // Forwarded from BackgroundChild.
370 static PBackgroundChild
* GetForCurrentThread();
372 // Helper function for getting PBackgroundChild from thread info.
373 static PBackgroundChild
* GetFromThreadInfo(nsIEventTarget
* aMainEventTarget
,
374 ThreadLocalInfo
* aThreadLocalInfo
);
376 // Forwarded from BackgroundChild.
377 static PBackgroundChild
* GetOrCreateForCurrentThread(
378 nsIEventTarget
* aMainEventTarget
);
380 // Forwarded from BackgroundChild.
381 static PBackgroundChild
* GetOrCreateSocketActorForCurrentThread(
382 nsIEventTarget
* aMainEventTarget
);
384 // Forwarded from BackgroundChild.
385 static void CloseForCurrentThread();
387 static void CloseThreadWithIndex(unsigned int aThreadLocalIndex
);
389 // Forwarded from BackgroundChildImpl.
390 static BackgroundChildImpl::ThreadLocal
* GetThreadLocalForCurrentThread();
392 static void ThreadLocalDestructor(void* aThreadLocal
);
394 // This class is reference counted.
395 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive
, mActorDestroyed
); }
397 // Only called by IPDL.
398 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
401 // -----------------------------------------------------------------------------
402 // ParentImpl Helper Declarations
403 // -----------------------------------------------------------------------------
405 class ParentImpl::ShutdownObserver final
: public nsIObserver
{
407 ShutdownObserver() { AssertIsOnMainThread(); }
413 ~ShutdownObserver() { AssertIsOnMainThread(); }
416 class ParentImpl::RequestMessageLoopRunnable final
: public Runnable
{
417 nsCOMPtr
<nsIThread
> mTargetThread
;
418 MessageLoop
* mMessageLoop
;
421 explicit RequestMessageLoopRunnable(nsIThread
* aTargetThread
)
422 : Runnable("Background::ParentImpl::RequestMessageLoopRunnable"),
423 mTargetThread(aTargetThread
),
424 mMessageLoop(nullptr) {
425 AssertIsInMainOrSocketProcess();
426 AssertIsOnMainThread();
427 MOZ_ASSERT(aTargetThread
);
431 ~RequestMessageLoopRunnable() {}
436 class ParentImpl::ShutdownBackgroundThreadRunnable final
: public Runnable
{
438 ShutdownBackgroundThreadRunnable()
439 : Runnable("Background::ParentImpl::ShutdownBackgroundThreadRunnable") {
440 AssertIsInMainOrSocketProcess();
441 AssertIsOnMainThread();
445 ~ShutdownBackgroundThreadRunnable() {}
450 class ParentImpl::ForceCloseBackgroundActorsRunnable final
: public Runnable
{
451 nsTArray
<ParentImpl
*>* mActorArray
;
454 explicit ForceCloseBackgroundActorsRunnable(
455 nsTArray
<ParentImpl
*>* aActorArray
)
456 : Runnable("Background::ParentImpl::ForceCloseBackgroundActorsRunnable"),
457 mActorArray(aActorArray
) {
458 AssertIsInMainOrSocketProcess();
459 AssertIsOnMainThread();
460 MOZ_ASSERT(aActorArray
);
464 ~ForceCloseBackgroundActorsRunnable() {}
469 class ParentImpl::ConnectActorRunnable final
: public Runnable
{
470 RefPtr
<ParentImpl
> mActor
;
471 Endpoint
<PBackgroundParent
> mEndpoint
;
472 nsTArray
<ParentImpl
*>* mLiveActorArray
;
475 ConnectActorRunnable(ParentImpl
* aActor
,
476 Endpoint
<PBackgroundParent
>&& aEndpoint
,
477 nsTArray
<ParentImpl
*>* aLiveActorArray
)
478 : Runnable("Background::ParentImpl::ConnectActorRunnable"),
480 mEndpoint(std::move(aEndpoint
)),
481 mLiveActorArray(aLiveActorArray
) {
482 AssertIsInMainOrSocketProcess();
483 AssertIsOnMainThread();
484 MOZ_ASSERT(mEndpoint
.IsValid());
485 MOZ_ASSERT(aLiveActorArray
);
489 ~ConnectActorRunnable() { AssertIsInMainOrSocketProcess(); }
494 class ParentImpl::CreateActorHelper final
: public Runnable
{
495 mozilla::Monitor mMonitor
;
496 RefPtr
<ParentImpl
> mParentActor
;
497 nsCOMPtr
<nsIThread
> mThread
;
498 nsresult mMainThreadResultCode
;
502 explicit CreateActorHelper()
503 : Runnable("Background::ParentImpl::CreateActorHelper"),
504 mMonitor("CreateActorHelper::mMonitor"),
505 mMainThreadResultCode(NS_OK
),
507 AssertIsInMainOrSocketProcess();
508 AssertIsNotOnMainThread();
511 nsresult
BlockAndGetResults(nsIEventTarget
* aMainEventTarget
,
512 RefPtr
<ParentImpl
>& aParentActor
,
513 nsCOMPtr
<nsIThread
>& aThread
);
516 ~CreateActorHelper() { AssertIsInMainOrSocketProcess(); }
518 nsresult
RunOnMainThread();
523 class NS_NO_VTABLE
ParentImpl::CreateCallback
{
525 NS_INLINE_DECL_REFCOUNTING(CreateCallback
)
527 virtual void Success(already_AddRefed
<ParentImpl
> aActor
,
528 MessageLoop
* aMessageLoop
) = 0;
530 virtual void Failure() = 0;
533 virtual ~CreateCallback() {}
536 // -----------------------------------------------------------------------------
537 // ChildImpl Helper Declarations
538 // -----------------------------------------------------------------------------
540 class ChildImpl::ShutdownObserver final
: public nsIObserver
{
542 ShutdownObserver() { AssertIsOnMainThread(); }
548 ~ShutdownObserver() { AssertIsOnMainThread(); }
551 class ChildImpl::SendInitBackgroundRunnable final
: public CancelableRunnable
{
552 nsCOMPtr
<nsISerialEventTarget
> mOwningEventTarget
;
553 RefPtr
<StrongWorkerRef
> mWorkerRef
;
554 Endpoint
<PBackgroundParent
> mParent
;
555 mozilla::Mutex mMutex
;
556 bool mSentInitBackground
;
557 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)> mSendInitfunc
;
560 static already_AddRefed
<SendInitBackgroundRunnable
> Create(
561 Endpoint
<PBackgroundParent
>&& aParent
,
562 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)>&& aFunc
);
564 void ClearEventTarget() {
565 mWorkerRef
= nullptr;
567 mozilla::MutexAutoLock
lock(mMutex
);
568 mOwningEventTarget
= nullptr;
572 explicit SendInitBackgroundRunnable(
573 Endpoint
<PBackgroundParent
>&& aParent
,
574 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)>&& aFunc
)
575 : CancelableRunnable("Background::ChildImpl::SendInitBackgroundRunnable"),
576 mOwningEventTarget(GetCurrentThreadSerialEventTarget()),
577 mParent(std::move(aParent
)),
578 mMutex("SendInitBackgroundRunnable::mMutex"),
579 mSentInitBackground(false),
580 mSendInitfunc(std::move(aFunc
)) {}
582 ~SendInitBackgroundRunnable() {}
592 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
596 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
601 } // namespace mozilla
603 // -----------------------------------------------------------------------------
604 // BackgroundParent Public Methods
605 // -----------------------------------------------------------------------------
608 bool BackgroundParent::IsOtherProcessActor(
609 PBackgroundParent
* aBackgroundActor
) {
610 return ParentImpl::IsOtherProcessActor(aBackgroundActor
);
614 already_AddRefed
<ContentParent
> BackgroundParent::GetContentParent(
615 PBackgroundParent
* aBackgroundActor
) {
616 return ParentImpl::GetContentParent(aBackgroundActor
);
620 intptr_t BackgroundParent::GetRawContentParentForComparison(
621 PBackgroundParent
* aBackgroundActor
) {
622 return ParentImpl::GetRawContentParentForComparison(aBackgroundActor
);
626 uint64_t BackgroundParent::GetChildID(PBackgroundParent
* aBackgroundActor
) {
627 return ParentImpl::GetChildID(aBackgroundActor
);
631 bool BackgroundParent::GetLiveActorArray(
632 PBackgroundParent
* aBackgroundActor
,
633 nsTArray
<PBackgroundParent
*>& aLiveActorArray
) {
634 return ParentImpl::GetLiveActorArray(aBackgroundActor
, aLiveActorArray
);
638 bool BackgroundParent::Alloc(ContentParent
* aContent
,
639 Endpoint
<PBackgroundParent
>&& aEndpoint
) {
640 return ParentImpl::Alloc(aContent
, std::move(aEndpoint
));
643 // -----------------------------------------------------------------------------
644 // BackgroundChild Public Methods
645 // -----------------------------------------------------------------------------
648 void BackgroundChild::Startup() { ChildImpl::Startup(); }
651 PBackgroundChild
* BackgroundChild::GetForCurrentThread() {
652 return ChildImpl::GetForCurrentThread();
656 PBackgroundChild
* BackgroundChild::GetOrCreateForCurrentThread(
657 nsIEventTarget
* aMainEventTarget
) {
658 return ChildImpl::GetOrCreateForCurrentThread(aMainEventTarget
);
662 PBackgroundChild
* BackgroundChild::GetOrCreateSocketActorForCurrentThread(
663 nsIEventTarget
* aMainEventTarget
) {
664 return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget
);
668 void BackgroundChild::CloseForCurrentThread() {
669 ChildImpl::CloseForCurrentThread();
672 // -----------------------------------------------------------------------------
673 // BackgroundChildImpl Public Methods
674 // -----------------------------------------------------------------------------
677 BackgroundChildImpl::ThreadLocal
*
678 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
679 return ChildImpl::GetThreadLocalForCurrentThread();
682 // -----------------------------------------------------------------------------
683 // ParentImpl Static Members
684 // -----------------------------------------------------------------------------
686 StaticRefPtr
<nsIThread
> ParentImpl::sBackgroundThread
;
688 nsTArray
<ParentImpl
*>* ParentImpl::sLiveActorsForBackgroundThread
;
690 StaticRefPtr
<nsITimer
> ParentImpl::sShutdownTimer
;
692 Atomic
<PRThread
*> ParentImpl::sBackgroundPRThread
;
694 MessageLoop
* ParentImpl::sBackgroundThreadMessageLoop
= nullptr;
696 uint64_t ParentImpl::sLiveActorCount
= 0;
698 bool ParentImpl::sShutdownObserverRegistered
= false;
700 bool ParentImpl::sShutdownHasStarted
= false;
702 // -----------------------------------------------------------------------------
703 // ChildImpl Static Members
704 // -----------------------------------------------------------------------------
706 unsigned int ChildImpl::sThreadLocalIndex
= kBadThreadLocalIndex
;
707 unsigned int ChildImpl::sThreadLocalIndexForSocketProcess
=
708 kBadThreadLocalIndex
;
710 bool ChildImpl::sShutdownHasStarted
= false;
712 // -----------------------------------------------------------------------------
713 // ParentImpl Implementation
714 // -----------------------------------------------------------------------------
717 bool ParentImpl::IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
) {
718 AssertIsOnBackgroundThread();
719 MOZ_ASSERT(aBackgroundActor
);
721 return static_cast<ParentImpl
*>(aBackgroundActor
)->mIsOtherProcessActor
;
725 already_AddRefed
<ContentParent
> ParentImpl::GetContentParent(
726 PBackgroundParent
* aBackgroundActor
) {
727 AssertIsOnBackgroundThread();
728 MOZ_ASSERT(aBackgroundActor
);
730 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
731 if (actor
->mActorDestroyed
) {
732 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
736 if (actor
->mContent
) {
737 // We need to hand out a reference to our ContentParent but we also need to
738 // keep the one we have. We can't call AddRef here because ContentParent is
739 // not threadsafe so instead we dispatch a runnable to the main thread to do
740 // it for us. This is safe since we are guaranteed that our AddRef runnable
741 // will run before the reference we hand out can be released, and the
742 // ContentParent can't die as long as the existing reference is maintained.
743 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
744 "ContentParent::AddRef", actor
->mContent
, &ContentParent::AddRef
)));
747 return already_AddRefed
<ContentParent
>(actor
->mContent
.get());
751 intptr_t ParentImpl::GetRawContentParentForComparison(
752 PBackgroundParent
* aBackgroundActor
) {
753 AssertIsOnBackgroundThread();
754 MOZ_ASSERT(aBackgroundActor
);
756 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
757 if (actor
->mActorDestroyed
) {
759 "GetRawContentParentForComparison called after ActorDestroy was "
764 return intptr_t(static_cast<ContentParent
*>(actor
->mContent
.get()));
768 uint64_t ParentImpl::GetChildID(PBackgroundParent
* aBackgroundActor
) {
769 AssertIsOnBackgroundThread();
770 MOZ_ASSERT(aBackgroundActor
);
772 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
773 if (actor
->mActorDestroyed
) {
774 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
778 if (actor
->mContent
) {
779 return actor
->mContent
->ChildID();
786 bool ParentImpl::GetLiveActorArray(
787 PBackgroundParent
* aBackgroundActor
,
788 nsTArray
<PBackgroundParent
*>& aLiveActorArray
) {
789 AssertIsOnBackgroundThread();
790 MOZ_ASSERT(aBackgroundActor
);
791 MOZ_ASSERT(aLiveActorArray
.IsEmpty());
793 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
794 if (actor
->mActorDestroyed
) {
796 "GetLiveActorArray called after ActorDestroy was called!");
800 if (!actor
->mLiveActorArray
) {
804 for (ParentImpl
* liveActor
: *actor
->mLiveActorArray
) {
805 aLiveActorArray
.AppendElement(liveActor
);
812 bool ParentImpl::Alloc(ContentParent
* aContent
,
813 Endpoint
<PBackgroundParent
>&& aEndpoint
) {
814 AssertIsInMainOrSocketProcess();
815 AssertIsOnMainThread();
816 MOZ_ASSERT(aEndpoint
.IsValid());
818 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
819 NS_WARNING("Failed to create background thread!");
823 MOZ_ASSERT(sLiveActorsForBackgroundThread
);
827 RefPtr
<ParentImpl
> actor
= new ParentImpl(aContent
);
829 nsCOMPtr
<nsIRunnable
> connectRunnable
= new ConnectActorRunnable(
830 actor
, std::move(aEndpoint
), sLiveActorsForBackgroundThread
);
833 sBackgroundThread
->Dispatch(connectRunnable
, NS_DISPATCH_NORMAL
))) {
834 NS_WARNING("Failed to dispatch connect runnable!");
836 MOZ_ASSERT(sLiveActorCount
);
846 already_AddRefed
<ChildImpl
> ParentImpl::CreateActorForSameProcess(
847 nsIEventTarget
* aMainEventTarget
) {
848 AssertIsInMainProcess();
850 RefPtr
<ParentImpl
> parentActor
;
851 nsCOMPtr
<nsIThread
> backgroundThread
;
853 if (NS_IsMainThread()) {
854 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
855 NS_WARNING("Failed to create background thread!");
859 MOZ_ASSERT(!sShutdownHasStarted
);
863 parentActor
= new ParentImpl();
864 backgroundThread
= sBackgroundThread
.get();
866 RefPtr
<CreateActorHelper
> helper
= new CreateActorHelper();
868 nsresult rv
= helper
->BlockAndGetResults(aMainEventTarget
, parentActor
,
870 if (NS_WARN_IF(NS_FAILED(rv
))) {
875 RefPtr
<ChildImpl
> childActor
= new ChildImpl();
877 MessageChannel
* parentChannel
= parentActor
->GetIPCChannel();
878 MOZ_ASSERT(parentChannel
);
880 if (!childActor
->Open(parentChannel
, backgroundThread
, ChildSide
)) {
881 NS_WARNING("Failed to open ChildImpl!");
883 // Can't release it here, we will release this reference in Destroy.
885 parentActor
.forget(&actor
);
892 childActor
->SetActorAlive();
894 // Make sure the parent knows it is same process.
895 parentActor
->SetOtherProcessId(base::GetCurrentProcId());
897 // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
898 Unused
<< parentActor
.forget();
900 return childActor
.forget();
904 bool ParentImpl::CreateBackgroundThread() {
905 AssertIsInMainOrSocketProcess();
906 AssertIsOnMainThread();
907 MOZ_ASSERT(!sBackgroundThread
);
908 MOZ_ASSERT(!sLiveActorsForBackgroundThread
);
910 if (sShutdownHasStarted
) {
912 "Trying to create background thread after shutdown has "
917 nsCOMPtr
<nsITimer
> newShutdownTimer
;
919 if (!sShutdownTimer
) {
920 newShutdownTimer
= NS_NewTimer();
921 if (!newShutdownTimer
) {
926 if (!sShutdownObserverRegistered
) {
927 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
928 if (NS_WARN_IF(!obs
)) {
932 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
934 nsresult rv
= obs
->AddObserver(
935 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
936 if (NS_WARN_IF(NS_FAILED(rv
))) {
940 sShutdownObserverRegistered
= true;
943 nsCOMPtr
<nsIThread
> thread
;
944 if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread
)))) {
945 NS_WARNING("NS_NewNamedThread failed!");
949 nsCOMPtr
<nsIRunnable
> messageLoopRunnable
=
950 new RequestMessageLoopRunnable(thread
);
951 if (NS_FAILED(thread
->Dispatch(messageLoopRunnable
, NS_DISPATCH_NORMAL
))) {
952 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable!");
956 sBackgroundThread
= thread
;
957 sLiveActorsForBackgroundThread
= new nsTArray
<ParentImpl
*>(1);
959 if (!sShutdownTimer
) {
960 MOZ_ASSERT(newShutdownTimer
);
961 sShutdownTimer
= newShutdownTimer
;
968 void ParentImpl::ShutdownBackgroundThread() {
969 AssertIsInMainOrSocketProcess();
970 AssertIsOnMainThread();
971 MOZ_ASSERT(sShutdownHasStarted
);
972 MOZ_ASSERT_IF(!sBackgroundThread
, !sLiveActorCount
);
973 MOZ_ASSERT_IF(sBackgroundThread
, sShutdownTimer
);
975 nsCOMPtr
<nsITimer
> shutdownTimer
= sShutdownTimer
.get();
976 sShutdownTimer
= nullptr;
978 if (sBackgroundThread
) {
979 nsCOMPtr
<nsIThread
> thread
= sBackgroundThread
.get();
980 sBackgroundThread
= nullptr;
982 nsAutoPtr
<nsTArray
<ParentImpl
*>> liveActors(sLiveActorsForBackgroundThread
);
983 sLiveActorsForBackgroundThread
= nullptr;
985 MOZ_ASSERT_IF(!sShutdownHasStarted
, !sLiveActorCount
);
987 if (sLiveActorCount
) {
988 // We need to spin the event loop while we wait for all the actors to be
989 // cleaned up. We also set a timeout to force-kill any hanging actors.
990 TimerCallbackClosure
closure(thread
, liveActors
);
992 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->InitWithNamedFuncCallback(
993 &ShutdownTimerCallback
, &closure
, kShutdownTimerDelayMS
,
994 nsITimer::TYPE_ONE_SHOT
, "ParentImpl::ShutdownTimerCallback"));
996 SpinEventLoopUntil([&]() { return !sLiveActorCount
; });
998 MOZ_ASSERT(liveActors
->IsEmpty());
1000 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->Cancel());
1003 // Dispatch this runnable to unregister the thread from the profiler.
1004 nsCOMPtr
<nsIRunnable
> shutdownRunnable
=
1005 new ShutdownBackgroundThreadRunnable();
1006 MOZ_ALWAYS_SUCCEEDS(thread
->Dispatch(shutdownRunnable
, NS_DISPATCH_NORMAL
));
1008 MOZ_ALWAYS_SUCCEEDS(thread
->Shutdown());
1013 void ParentImpl::ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
) {
1014 AssertIsInMainOrSocketProcess();
1015 AssertIsOnMainThread();
1016 MOZ_ASSERT(sShutdownHasStarted
);
1017 MOZ_ASSERT(sLiveActorCount
);
1019 auto closure
= static_cast<TimerCallbackClosure
*>(aClosure
);
1020 MOZ_ASSERT(closure
);
1022 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1026 nsCOMPtr
<nsIRunnable
> forceCloseRunnable
=
1027 new ForceCloseBackgroundActorsRunnable(closure
->mLiveActors
);
1028 MOZ_ALWAYS_SUCCEEDS(
1029 closure
->mThread
->Dispatch(forceCloseRunnable
, NS_DISPATCH_NORMAL
));
1032 void ParentImpl::Destroy() {
1033 // May be called on any thread!
1035 AssertIsInMainOrSocketProcess();
1037 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1038 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1039 &ParentImpl::MainThreadActorDestroy
)));
1042 void ParentImpl::MainThreadActorDestroy() {
1043 AssertIsInMainOrSocketProcess();
1044 AssertIsOnMainThread();
1045 MOZ_ASSERT_IF(mIsOtherProcessActor
&& XRE_IsParentProcess(), mContent
);
1046 MOZ_ASSERT_IF(!mIsOtherProcessActor
, !mContent
);
1050 MOZ_ASSERT(sLiveActorCount
);
1053 // This may be the last reference!
1057 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1058 AssertIsInMainOrSocketProcess();
1059 AssertIsOnBackgroundThread();
1060 MOZ_ASSERT(!mActorDestroyed
);
1061 MOZ_ASSERT_IF(mIsOtherProcessActor
, mLiveActorArray
);
1063 BackgroundParentImpl::ActorDestroy(aWhy
);
1065 mActorDestroyed
= true;
1067 if (mLiveActorArray
) {
1068 MOZ_ALWAYS_TRUE(mLiveActorArray
->RemoveElement(this));
1069 mLiveActorArray
= nullptr;
1072 // This is tricky. We should be able to call Destroy() here directly because
1073 // we're not going to touch 'this' or our MessageChannel any longer on this
1074 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1075 // it runs it will destroy 'this' and our associated MessageChannel. However,
1076 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1077 // racing with the main thread we must ensure that the MessageChannel lives
1078 // long enough to be cleared in this call stack.
1080 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1081 "ParentImpl::Destroy", this, &ParentImpl::Destroy
)));
1084 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver
, nsIObserver
)
1087 ParentImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1088 const char16_t
* aData
) {
1089 AssertIsInMainOrSocketProcess();
1090 AssertIsOnMainThread();
1091 MOZ_ASSERT(!sShutdownHasStarted
);
1092 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1094 sShutdownHasStarted
= true;
1096 // Do this first before calling (and spinning the event loop in)
1097 // ShutdownBackgroundThread().
1098 // Since we didn't call BackgroundChild::Startup() in socket process,
1099 // we can't call ChildImpl::Shutdown() here.
1100 if (!XRE_IsSocketProcess()) {
1101 ChildImpl::Shutdown();
1104 ShutdownBackgroundThread();
1110 ParentImpl::RequestMessageLoopRunnable::Run() {
1111 AssertIsInMainOrSocketProcess();
1112 MOZ_ASSERT(mTargetThread
);
1114 if (NS_IsMainThread()) {
1115 MOZ_ASSERT(mMessageLoop
);
1117 if (!sBackgroundThread
||
1118 !SameCOMIdentity(mTargetThread
.get(), sBackgroundThread
.get())) {
1122 MOZ_ASSERT(!sBackgroundThreadMessageLoop
);
1123 sBackgroundThreadMessageLoop
= mMessageLoop
;
1131 MOZ_ASSERT(NS_SUCCEEDED(mTargetThread
->IsOnCurrentThread(&correctThread
)));
1132 MOZ_ASSERT(correctThread
);
1136 DebugOnly
<PRThread
*> oldBackgroundThread
=
1137 sBackgroundPRThread
.exchange(PR_GetCurrentThread());
1139 MOZ_ASSERT_IF(oldBackgroundThread
,
1140 PR_GetCurrentThread() != oldBackgroundThread
);
1142 MOZ_ASSERT(!mMessageLoop
);
1144 mMessageLoop
= MessageLoop::current();
1145 MOZ_ASSERT(mMessageLoop
);
1147 if (NS_FAILED(NS_DispatchToMainThread(this))) {
1148 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!");
1149 return NS_ERROR_FAILURE
;
1156 ParentImpl::ShutdownBackgroundThreadRunnable::Run() {
1157 AssertIsInMainOrSocketProcess();
1159 // It is possible that another background thread was created while this thread
1160 // was shutting down. In that case we can't assert anything about
1161 // sBackgroundPRThread and we should not modify it here.
1162 sBackgroundPRThread
.compareExchange(PR_GetCurrentThread(), nullptr);
1168 ParentImpl::ForceCloseBackgroundActorsRunnable::Run() {
1169 AssertIsInMainOrSocketProcess();
1170 MOZ_ASSERT(mActorArray
);
1172 if (NS_IsMainThread()) {
1173 MOZ_ASSERT(sLiveActorCount
);
1178 AssertIsOnBackgroundThread();
1180 if (!mActorArray
->IsEmpty()) {
1181 // Copy the array since calling Close() could mutate the actual array.
1182 nsTArray
<ParentImpl
*> actorsToClose(*mActorArray
);
1184 for (uint32_t index
= 0; index
< actorsToClose
.Length(); index
++) {
1185 actorsToClose
[index
]->Close();
1189 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1195 ParentImpl::ConnectActorRunnable::Run() {
1196 AssertIsInMainOrSocketProcess();
1197 AssertIsOnBackgroundThread();
1199 // Transfer ownership to this thread. If Open() fails then we will release
1200 // this reference in Destroy.
1202 mActor
.forget(&actor
);
1204 Endpoint
<PBackgroundParent
> endpoint
= std::move(mEndpoint
);
1206 if (!endpoint
.Bind(actor
)) {
1208 return NS_ERROR_FAILURE
;
1211 actor
->SetLiveActorArray(mLiveActorArray
);
1216 nsresult
ParentImpl::CreateActorHelper::BlockAndGetResults(
1217 nsIEventTarget
* aMainEventTarget
, RefPtr
<ParentImpl
>& aParentActor
,
1218 nsCOMPtr
<nsIThread
>& aThread
) {
1219 AssertIsNotOnMainThread();
1221 if (aMainEventTarget
) {
1222 MOZ_ALWAYS_SUCCEEDS(aMainEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
1224 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1227 mozilla::MonitorAutoLock
lock(mMonitor
);
1232 if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode
))) {
1233 return mMainThreadResultCode
;
1236 aParentActor
= std::move(mParentActor
);
1237 aThread
= std::move(mThread
);
1241 nsresult
ParentImpl::CreateActorHelper::RunOnMainThread() {
1242 AssertIsOnMainThread();
1244 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
1245 NS_WARNING("Failed to create background thread!");
1246 return NS_ERROR_FAILURE
;
1249 MOZ_ASSERT(!sShutdownHasStarted
);
1253 mParentActor
= new ParentImpl();
1254 mThread
= sBackgroundThread
;
1260 ParentImpl::CreateActorHelper::Run() {
1261 AssertIsOnMainThread();
1263 nsresult rv
= RunOnMainThread();
1264 if (NS_WARN_IF(NS_FAILED(rv
))) {
1265 mMainThreadResultCode
= rv
;
1268 mozilla::MonitorAutoLock
lock(mMonitor
);
1269 MOZ_ASSERT(mWaiting
);
1277 // -----------------------------------------------------------------------------
1278 // ChildImpl Implementation
1279 // -----------------------------------------------------------------------------
1282 void ChildImpl::Startup() {
1283 // This happens on the main thread but before XPCOM has started so we can't
1284 // assert that we're being called on the main thread here.
1286 MOZ_ASSERT(sThreadLocalIndex
== kBadThreadLocalIndex
,
1287 "BackgroundChild::Startup() called more than once!");
1288 MOZ_ASSERT(sThreadLocalIndexForSocketProcess
== kBadThreadLocalIndex
,
1289 "BackgroundChild::Startup() called more than once!");
1292 PR_NewThreadPrivateIndex(&sThreadLocalIndex
, ThreadLocalDestructor
);
1293 MOZ_RELEASE_ASSERT(status
== PR_SUCCESS
, "PR_NewThreadPrivateIndex failed!");
1295 status
= PR_NewThreadPrivateIndex(&sThreadLocalIndexForSocketProcess
,
1296 ThreadLocalDestructor
);
1297 MOZ_RELEASE_ASSERT(status
== PR_SUCCESS
, "PR_NewThreadPrivateIndex failed!");
1299 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
);
1300 MOZ_ASSERT(sThreadLocalIndexForSocketProcess
!= kBadThreadLocalIndex
);
1302 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1303 MOZ_RELEASE_ASSERT(observerService
);
1305 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
1307 nsresult rv
= observerService
->AddObserver(
1308 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
1309 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
1312 void ChildImpl::ShutdownWithThreadLocalIndex(unsigned int aThreadLocalIndex
) {
1313 MOZ_ASSERT(aThreadLocalIndex
!= kBadThreadLocalIndex
);
1315 ThreadLocalInfo
* threadLocalInfo
;
1318 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(aThreadLocalIndex
));
1319 MOZ_ASSERT(!threadLocalInfo
);
1321 threadLocalInfo
= aThreadLocalIndex
== sThreadLocalIndex
1323 : sMainThreadInfoForSocketProcess
;
1325 if (threadLocalInfo
) {
1327 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
1328 threadLocalInfo
->mClosed
= true;
1331 ThreadLocalDestructor(threadLocalInfo
);
1332 if (aThreadLocalIndex
== sThreadLocalIndex
) {
1333 sMainThreadInfo
= nullptr;
1335 sMainThreadInfoForSocketProcess
= nullptr;
1341 void ChildImpl::Shutdown() {
1342 AssertIsOnMainThread();
1344 if (sShutdownHasStarted
) {
1345 MOZ_ASSERT_IF(sThreadLocalIndex
!= kBadThreadLocalIndex
,
1346 !PR_GetThreadPrivate(sThreadLocalIndex
));
1347 MOZ_ASSERT_IF(sThreadLocalIndexForSocketProcess
!= kBadThreadLocalIndex
,
1348 !PR_GetThreadPrivate(sThreadLocalIndexForSocketProcess
));
1352 sShutdownHasStarted
= true;
1354 ShutdownWithThreadLocalIndex(sThreadLocalIndex
);
1356 if (sThreadLocalIndexForSocketProcess
!= kBadThreadLocalIndex
) {
1357 ShutdownWithThreadLocalIndex(sThreadLocalIndexForSocketProcess
);
1361 ChildImpl::ThreadLocalInfo
* ChildImpl::sMainThreadInfo
= nullptr;
1362 ChildImpl::ThreadLocalInfo
* ChildImpl::sMainThreadInfoForSocketProcess
=
1366 PBackgroundChild
* ChildImpl::GetForCurrentThread() {
1367 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
);
1369 auto threadLocalInfo
= NS_IsMainThread()
1371 : static_cast<ThreadLocalInfo
*>(
1372 PR_GetThreadPrivate(sThreadLocalIndex
));
1374 if (!threadLocalInfo
) {
1378 return threadLocalInfo
->mActor
;
1382 PBackgroundChild
* ChildImpl::GetFromThreadInfo(
1383 nsIEventTarget
* aMainEventTarget
, ThreadLocalInfo
* aThreadLocalInfo
) {
1384 MOZ_ASSERT(aThreadLocalInfo
);
1386 if (aThreadLocalInfo
->mActor
) {
1387 RefPtr
<SendInitBackgroundRunnable
>& runnable
=
1388 aThreadLocalInfo
->mSendInitBackgroundRunnable
;
1390 if (aMainEventTarget
&& runnable
) {
1391 // The SendInitBackgroundRunnable was already dispatched to the main
1392 // thread to finish initialization of a new background child actor.
1393 // However, the caller passed a custom main event target which indicates
1394 // that synchronous blocking of the main thread is happening (done by
1395 // creating a nested event target and spinning the event loop).
1396 // It can happen that the SendInitBackgroundRunnable didn't have a chance
1397 // to run before the synchronous blocking has occured. Unblocking of the
1398 // main thread can depend on an IPC message received on this thread, so
1399 // we have to dispatch the SendInitBackgroundRunnable to the custom main
1400 // event target too, otherwise IPC will be only queueing messages on this
1401 // thread. The runnable will run twice in the end, but that's a harmless
1402 // race between the main and nested event queue of the main thread.
1403 // There's a guard in the runnable implementation for calling
1404 // SendInitBackground only once.
1406 MOZ_ALWAYS_SUCCEEDS(
1407 aMainEventTarget
->Dispatch(runnable
, NS_DISPATCH_NORMAL
));
1410 return aThreadLocalInfo
->mActor
;
1417 PBackgroundChild
* ChildImpl::GetOrCreateForCurrentThread(
1418 nsIEventTarget
* aMainEventTarget
) {
1419 MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget
);
1421 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
,
1422 "BackgroundChild::Startup() was never called!");
1424 if (NS_IsMainThread() && sShutdownHasStarted
) {
1428 auto threadLocalInfo
= NS_IsMainThread()
1430 : static_cast<ThreadLocalInfo
*>(
1431 PR_GetThreadPrivate(sThreadLocalIndex
));
1433 if (!threadLocalInfo
) {
1434 nsAutoPtr
<ThreadLocalInfo
> newInfo(new ThreadLocalInfo());
1436 if (NS_IsMainThread()) {
1437 sMainThreadInfo
= newInfo
;
1439 if (PR_SetThreadPrivate(sThreadLocalIndex
, newInfo
) != PR_SUCCESS
) {
1440 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
1445 threadLocalInfo
= newInfo
.forget();
1448 PBackgroundChild
* bgChild
=
1449 GetFromThreadInfo(aMainEventTarget
, threadLocalInfo
);
1454 if (XRE_IsParentProcess()) {
1455 RefPtr
<ChildImpl
> strongActor
=
1456 ParentImpl::CreateActorForSameProcess(aMainEventTarget
);
1457 if (NS_WARN_IF(!strongActor
)) {
1461 RefPtr
<ChildImpl
>& actor
= threadLocalInfo
->mActor
;
1462 strongActor
.swap(actor
);
1467 RefPtr
<ContentChild
> content
= ContentChild::GetSingleton();
1468 MOZ_ASSERT(content
);
1470 if (content
->IsShuttingDown()) {
1471 // The transport for ContentChild is shut down and can't be used to open
1476 Endpoint
<PBackgroundParent
> parent
;
1477 Endpoint
<PBackgroundChild
> child
;
1479 rv
= PBackground::CreateEndpoints(content
->OtherPid(),
1480 base::GetCurrentProcId(), &parent
, &child
);
1481 if (NS_FAILED(rv
)) {
1482 NS_WARNING("Failed to create top level actor!");
1486 RefPtr
<SendInitBackgroundRunnable
> runnable
;
1487 if (!NS_IsMainThread()) {
1488 runnable
= SendInitBackgroundRunnable::Create(
1489 std::move(parent
), [](Endpoint
<PBackgroundParent
>&& aParent
) {
1490 RefPtr
<ContentChild
> content
= ContentChild::GetSingleton();
1491 MOZ_ASSERT(content
);
1493 if (!content
->SendInitBackground(std::move(aParent
))) {
1494 NS_WARNING("Failed to create top level actor!");
1502 RefPtr
<ChildImpl
> strongActor
= new ChildImpl();
1504 if (!child
.Bind(strongActor
)) {
1505 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
1510 strongActor
->SetActorAlive();
1512 if (NS_IsMainThread()) {
1513 if (!content
->SendInitBackground(std::move(parent
))) {
1514 NS_WARNING("Failed to create top level actor!");
1518 if (aMainEventTarget
) {
1519 MOZ_ALWAYS_SUCCEEDS(
1520 aMainEventTarget
->Dispatch(runnable
, NS_DISPATCH_NORMAL
));
1522 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
));
1525 threadLocalInfo
->mSendInitBackgroundRunnable
= runnable
;
1528 RefPtr
<ChildImpl
>& actor
= threadLocalInfo
->mActor
;
1529 strongActor
.swap(actor
);
1535 PBackgroundChild
* ChildImpl::GetOrCreateSocketActorForCurrentThread(
1536 nsIEventTarget
* aMainEventTarget
) {
1537 MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget
);
1539 MOZ_ASSERT(sThreadLocalIndexForSocketProcess
!= kBadThreadLocalIndex
,
1540 "BackgroundChild::Startup() was never called!");
1542 if (NS_IsMainThread() && sShutdownHasStarted
) {
1546 auto threadLocalInfo
=
1547 NS_IsMainThread() ? sMainThreadInfoForSocketProcess
1548 : static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(
1549 sThreadLocalIndexForSocketProcess
));
1551 if (!threadLocalInfo
) {
1552 nsAutoPtr
<ThreadLocalInfo
> newInfo(new ThreadLocalInfo());
1554 if (NS_IsMainThread()) {
1555 sMainThreadInfoForSocketProcess
= newInfo
;
1557 if (PR_SetThreadPrivate(sThreadLocalIndexForSocketProcess
, newInfo
) !=
1559 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
1564 threadLocalInfo
= newInfo
.forget();
1567 PBackgroundChild
* bgChild
=
1568 GetFromThreadInfo(aMainEventTarget
, threadLocalInfo
);
1573 RefPtr
<SocketProcessBridgeChild
> bridgeChild
=
1574 SocketProcessBridgeChild::GetSingleton();
1576 if (!bridgeChild
|| bridgeChild
->IsShuttingDown()) {
1577 // The transport for SocketProcessBridgeChild is shut down
1578 // and can't be used to open PBackground.
1582 Endpoint
<PBackgroundParent
> parent
;
1583 Endpoint
<PBackgroundChild
> child
;
1585 rv
= PBackground::CreateEndpoints(bridgeChild
->SocketProcessPid(),
1586 base::GetCurrentProcId(), &parent
, &child
);
1587 if (NS_FAILED(rv
)) {
1588 NS_WARNING("Failed to create top level actor!");
1592 RefPtr
<SendInitBackgroundRunnable
> runnable
;
1593 if (!NS_IsMainThread()) {
1594 runnable
= SendInitBackgroundRunnable::Create(
1595 std::move(parent
), [](Endpoint
<PBackgroundParent
>&& aParent
) {
1596 RefPtr
<SocketProcessBridgeChild
> bridgeChild
=
1597 SocketProcessBridgeChild::GetSingleton();
1599 if (!bridgeChild
->SendInitBackground(std::move(aParent
))) {
1600 NS_WARNING("Failed to create top level actor!");
1608 RefPtr
<ChildImpl
> strongActor
= new ChildImpl();
1610 if (!child
.Bind(strongActor
)) {
1611 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
1616 strongActor
->SetActorAlive();
1618 if (NS_IsMainThread()) {
1619 if (!bridgeChild
->SendInitBackground(std::move(parent
))) {
1620 NS_WARNING("Failed to create top level actor!");
1621 // Need to close the IPC channel before ChildImpl getting deleted.
1622 strongActor
->Close();
1623 strongActor
->AssertActorDestroyed();
1627 if (aMainEventTarget
) {
1628 MOZ_ALWAYS_SUCCEEDS(
1629 aMainEventTarget
->Dispatch(runnable
, NS_DISPATCH_NORMAL
));
1631 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
));
1634 threadLocalInfo
->mSendInitBackgroundRunnable
= runnable
;
1637 RefPtr
<ChildImpl
>& actor
= threadLocalInfo
->mActor
;
1638 strongActor
.swap(actor
);
1644 void ChildImpl::CloseThreadWithIndex(unsigned int aThreadLocalIndex
) {
1645 auto threadLocalInfo
=
1646 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(aThreadLocalIndex
));
1648 if (!threadLocalInfo
) {
1653 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
1654 threadLocalInfo
->mClosed
= true;
1657 // Clearing the thread local will synchronously close the actor.
1658 DebugOnly
<PRStatus
> status
= PR_SetThreadPrivate(aThreadLocalIndex
, nullptr);
1659 MOZ_ASSERT(status
== PR_SUCCESS
);
1663 void ChildImpl::CloseForCurrentThread() {
1664 MOZ_ASSERT(!NS_IsMainThread(),
1665 "PBackground for the main thread should be shut down via "
1666 "ChildImpl::Shutdown().");
1668 if (sThreadLocalIndex
!= kBadThreadLocalIndex
) {
1669 CloseThreadWithIndex(sThreadLocalIndex
);
1671 if (sThreadLocalIndexForSocketProcess
!= kBadThreadLocalIndex
) {
1672 CloseThreadWithIndex(sThreadLocalIndexForSocketProcess
);
1677 BackgroundChildImpl::ThreadLocal
* ChildImpl::GetThreadLocalForCurrentThread() {
1678 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
,
1679 "BackgroundChild::Startup() was never called!");
1681 auto threadLocalInfo
= NS_IsMainThread()
1683 : static_cast<ThreadLocalInfo
*>(
1684 PR_GetThreadPrivate(sThreadLocalIndex
));
1686 if (!threadLocalInfo
) {
1690 if (!threadLocalInfo
->mConsumerThreadLocal
) {
1691 threadLocalInfo
->mConsumerThreadLocal
=
1692 new BackgroundChildImpl::ThreadLocal();
1695 return threadLocalInfo
->mConsumerThreadLocal
;
1699 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal
) {
1700 auto threadLocalInfo
= static_cast<ThreadLocalInfo
*>(aThreadLocal
);
1702 if (threadLocalInfo
) {
1703 MOZ_ASSERT(threadLocalInfo
->mClosed
);
1705 if (threadLocalInfo
->mActor
) {
1706 threadLocalInfo
->mActor
->Close();
1707 threadLocalInfo
->mActor
->AssertActorDestroyed();
1710 if (threadLocalInfo
->mSendInitBackgroundRunnable
) {
1711 threadLocalInfo
->mSendInitBackgroundRunnable
->ClearEventTarget();
1714 delete threadLocalInfo
;
1718 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1719 AssertIsOnOwningThread();
1722 MOZ_ASSERT(!mActorDestroyed
);
1723 mActorDestroyed
= true;
1726 BackgroundChildImpl::ActorDestroy(aWhy
);
1729 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver
, nsIObserver
)
1732 ChildImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1733 const char16_t
* aData
) {
1734 AssertIsOnMainThread();
1735 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1737 ChildImpl::Shutdown();
1743 already_AddRefed
<ChildImpl::SendInitBackgroundRunnable
>
1744 ChildImpl::SendInitBackgroundRunnable::Create(
1745 Endpoint
<PBackgroundParent
>&& aParent
,
1746 std::function
<void(Endpoint
<PBackgroundParent
>&& aParent
)>&& aFunc
) {
1747 MOZ_ASSERT(!NS_IsMainThread());
1749 RefPtr
<SendInitBackgroundRunnable
> runnable
=
1750 new SendInitBackgroundRunnable(std::move(aParent
), std::move(aFunc
));
1752 WorkerPrivate
* workerPrivate
= mozilla::dom::GetCurrentThreadWorkerPrivate();
1753 if (!workerPrivate
) {
1754 return runnable
.forget();
1757 workerPrivate
->AssertIsOnWorkerThread();
1759 runnable
->mWorkerRef
= StrongWorkerRef::Create(
1760 workerPrivate
, "ChildImpl::SendInitBackgroundRunnable");
1761 if (NS_WARN_IF(!runnable
->mWorkerRef
)) {
1765 return runnable
.forget();
1769 ChildImpl::SendInitBackgroundRunnable::Run() {
1770 if (NS_IsMainThread()) {
1771 if (mSentInitBackground
) {
1775 mSentInitBackground
= true;
1777 mSendInitfunc(std::move(mParent
));
1779 nsCOMPtr
<nsISerialEventTarget
> owningEventTarget
;
1781 mozilla::MutexAutoLock
lock(mMutex
);
1782 owningEventTarget
= mOwningEventTarget
;
1785 if (!owningEventTarget
) {
1789 nsresult rv
= owningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
);
1790 if (NS_WARN_IF(NS_FAILED(rv
))) {
1799 auto threadLocalInfo
=
1800 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1802 if (!threadLocalInfo
) {
1806 threadLocalInfo
->mSendInitBackgroundRunnable
= nullptr;