1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "base/process_util.h"
6 #include "mozilla/Assertions.h"
7 #include "mozilla/Atomics.h"
8 #include "mozilla/ClearOnShutdown.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/Services.h"
11 #include "mozilla/StaticPtr.h"
12 #include "mozilla/unused.h"
13 #include "mozilla/dom/ContentChild.h"
14 #include "mozilla/dom/ContentParent.h"
15 #include "mozilla/ipc/ProtocolTypes.h"
16 #include "BackgroundChild.h"
17 #include "BackgroundChildImpl.h"
18 #include "BackgroundParent.h"
19 #include "BackgroundParentImpl.h"
20 #include "GeckoProfiler.h"
21 #include "nsAutoPtr.h"
23 #include "nsIEventTarget.h"
24 #include "nsIIPCBackgroundChildCreateCallback.h"
25 #include "nsIObserver.h"
26 #include "nsIObserverService.h"
27 #include "nsIRunnable.h"
28 #include "nsISupportsImpl.h"
29 #include "nsIThread.h"
32 #include "nsThreadUtils.h"
33 #include "nsTraceRefcnt.h"
34 #include "nsXULAppAPI.h"
35 #include "nsXPCOMPrivate.h"
39 #define THREADSAFETY_ASSERT MOZ_ASSERT
41 #define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
44 #define CRASH_IN_CHILD_PROCESS(_msg) \
46 if (IsMainProcess()) { \
47 MOZ_ASSERT(false, _msg); \
54 using namespace mozilla
;
55 using namespace mozilla::ipc
;
57 using mozilla::dom::ContentChild
;
58 using mozilla::dom::ContentParent
;
62 // -----------------------------------------------------------------------------
64 // -----------------------------------------------------------------------------
69 static const bool isMainProcess
=
70 XRE_GetProcessType() == GeckoProcessType_Default
;
78 return !IsMainProcess();
83 AssertIsInMainProcess()
85 MOZ_ASSERT(IsMainProcess());
89 AssertIsInChildProcess()
91 MOZ_ASSERT(IsChildProcess());
95 AssertIsOnMainThread()
97 THREADSAFETY_ASSERT(NS_IsMainThread());
100 // -----------------------------------------------------------------------------
101 // ParentImpl Declaration
102 // -----------------------------------------------------------------------------
104 class ParentImpl MOZ_FINAL
: public BackgroundParentImpl
106 friend class mozilla::ipc::BackgroundParent
;
109 class CreateCallback
;
112 class ShutdownObserver
;
113 class RequestMessageLoopRunnable
;
114 class ShutdownBackgroundThreadRunnable
;
115 class ForceCloseBackgroundActorsRunnable
;
116 class CreateCallbackRunnable
;
117 class ConnectActorRunnable
;
119 struct MOZ_STACK_CLASS TimerCallbackClosure
122 nsTArray
<ParentImpl
*>* mLiveActors
;
124 TimerCallbackClosure(nsIThread
* aThread
, nsTArray
<ParentImpl
*>* aLiveActors
)
125 : mThread(aThread
), mLiveActors(aLiveActors
)
127 AssertIsInMainProcess();
128 AssertIsOnMainThread();
130 MOZ_ASSERT(aLiveActors
);
134 // A handle that is invalid on any platform.
135 static const ProcessHandle kInvalidProcessHandle
;
137 // The length of time we will wait at shutdown for all actors to clean
138 // themselves up before forcing them to be destroyed.
139 static const uint32_t kShutdownTimerDelayMS
= 10000;
141 // This is only modified on the main thread. It is null if the thread does not
142 // exist or is shutting down.
143 static StaticRefPtr
<nsIThread
> sBackgroundThread
;
145 // This is created and destroyed on the main thread but only modified on the
146 // background thread. It is specific to each instance of sBackgroundThread.
147 static nsTArray
<ParentImpl
*>* sLiveActorsForBackgroundThread
;
149 // This is only modified on the main thread.
150 static StaticRefPtr
<nsITimer
> sShutdownTimer
;
152 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
153 // work during shutdown.
154 static Atomic
<PRThread
*> sBackgroundPRThread
;
156 // This is only modified on the main thread. It is null if the thread does not
157 // exist or is shutting down.
158 static MessageLoop
* sBackgroundThreadMessageLoop
;
160 // This is only modified on the main thread. It maintains a count of live
161 // actors so that the background thread can be shut down when it is no longer
163 static uint64_t sLiveActorCount
;
165 // This is only modified on the main thread. It is true after the shutdown
166 // observer is registered and is never unset thereafter.
167 static bool sShutdownObserverRegistered
;
169 // This is only modified on the main thread. It prevents us from trying to
170 // create the background thread after application shutdown has started.
171 static bool sShutdownHasStarted
;
173 // This is only modified on the main thread. It is a FIFO queue for callbacks
174 // waiting for the background thread to be created.
175 static StaticAutoPtr
<nsTArray
<nsRefPtr
<CreateCallback
>>> sPendingCallbacks
;
177 // Only touched on the main thread, null if this is a same-process actor.
178 nsRefPtr
<ContentParent
> mContent
;
180 // mTransport is "owned" by this object but it must only be released on the
181 // IPC thread. It's left as a raw pointer here to prevent accidentally
182 // deleting it on the wrong thread. Only non-null for other-process actors.
183 Transport
* mTransport
;
185 // Set when the actor is opened successfully and used to handle shutdown
186 // hangs. Only touched on the background thread.
187 nsTArray
<ParentImpl
*>* mLiveActorArray
;
189 // Set at construction to indicate whether this parent actor corresponds to a
190 // child actor in another process or to a child actor from a different thread
191 // in the same process.
192 const bool mIsOtherProcessActor
;
194 // Set after ActorDestroy has been called. Only touched on the background
196 bool mActorDestroyed
;
200 CreateActorForSameProcess(CreateCallback
* aCallback
);
203 IsOnBackgroundThread()
205 return PR_GetCurrentThread() == sBackgroundPRThread
;
209 AssertIsOnBackgroundThread()
211 THREADSAFETY_ASSERT(IsOnBackgroundThread());
214 NS_INLINE_DECL_REFCOUNTING(ParentImpl
)
220 // Forwarded from BackgroundParent.
222 IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
);
224 // Forwarded from BackgroundParent.
225 static already_AddRefed
<ContentParent
>
226 GetContentParent(PBackgroundParent
* aBackgroundActor
);
228 // Forwarded from BackgroundParent.
229 static PBackgroundParent
*
230 Alloc(ContentParent
* aContent
,
231 Transport
* aTransport
,
232 ProcessId aOtherProcess
);
235 CreateBackgroundThread();
238 ShutdownBackgroundThread();
241 ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
);
243 // For same-process actors.
245 : mTransport(nullptr), mLiveActorArray(nullptr), mIsOtherProcessActor(false),
246 mActorDestroyed(false)
248 AssertIsInMainProcess();
249 AssertIsOnMainThread();
251 SetOtherProcess(kInvalidProcessHandle
);
254 // For other-process actors.
255 ParentImpl(ContentParent
* aContent
, Transport
* aTransport
)
256 : mContent(aContent
), mTransport(aTransport
), mLiveActorArray(nullptr),
257 mIsOtherProcessActor(true), mActorDestroyed(false)
259 AssertIsInMainProcess();
260 AssertIsOnMainThread();
261 MOZ_ASSERT(aContent
);
262 MOZ_ASSERT(aTransport
);
267 AssertIsInMainProcess();
268 AssertIsOnMainThread();
269 MOZ_ASSERT(!mContent
);
270 MOZ_ASSERT(!mTransport
);
274 MainThreadActorDestroy();
277 SetLiveActorArray(nsTArray
<ParentImpl
*>* aLiveActorArray
)
279 AssertIsInMainProcess();
280 AssertIsOnBackgroundThread();
281 MOZ_ASSERT(aLiveActorArray
);
282 MOZ_ASSERT(!aLiveActorArray
->Contains(this));
283 MOZ_ASSERT(!mLiveActorArray
);
284 MOZ_ASSERT(mIsOtherProcessActor
);
286 mLiveActorArray
= aLiveActorArray
;
287 mLiveActorArray
->AppendElement(this);
290 // These methods are only called by IPDL.
291 virtual IToplevelProtocol
*
292 CloneToplevel(const InfallibleTArray
<ProtocolFdMapping
>& aFds
,
293 ProcessHandle aPeerProcess
,
294 ProtocolCloneContext
* aCtx
) MOZ_OVERRIDE
;
297 ActorDestroy(ActorDestroyReason aWhy
) MOZ_OVERRIDE
;
300 // -----------------------------------------------------------------------------
301 // ChildImpl Declaration
302 // -----------------------------------------------------------------------------
304 class ChildImpl MOZ_FINAL
: public BackgroundChildImpl
306 friend class mozilla::ipc::BackgroundChild
;
307 friend class mozilla::ipc::BackgroundChildImpl
;
309 typedef base::ProcessId ProcessId
;
310 typedef mozilla::ipc::Transport Transport
;
312 class ShutdownObserver
;
313 class CreateActorRunnable
;
314 class ParentCreateCallback
;
315 class AlreadyCreatedCallbackRunnable
;
316 class FailedCreateCallbackRunnable
;
317 class OpenChildProcessActorRunnable
;
318 class OpenMainProcessActorRunnable
;
320 // A thread-local index that is not valid.
321 static const unsigned int kBadThreadLocalIndex
=
322 static_cast<unsigned int>(-1);
324 // This is only modified on the main thread. It is the thread-local index that
325 // we use to store the BackgroundChild for each thread.
326 static unsigned int sThreadLocalIndex
;
328 struct ThreadLocalInfo
330 explicit ThreadLocalInfo(nsIIPCBackgroundChildCreateCallback
* aCallback
)
332 mCallbacks
.AppendElement(aCallback
);
335 nsRefPtr
<ChildImpl
> mActor
;
336 nsTArray
<nsCOMPtr
<nsIIPCBackgroundChildCreateCallback
>> mCallbacks
;
337 nsAutoPtr
<BackgroundChildImpl::ThreadLocal
> mConsumerThreadLocal
;
340 // This is only modified on the main thread. It is a FIFO queue for actors
341 // that are in the process of construction.
342 static StaticAutoPtr
<nsTArray
<nsCOMPtr
<nsIEventTarget
>>> sPendingTargets
;
344 // This is only modified on the main thread. It prevents us from trying to
345 // create the background thread after application shutdown has started.
346 static bool sShutdownHasStarted
;
349 DebugOnly
<nsIThread
*> mBoundThread
;
351 nsIThread
* mBoundThread
;
354 DebugOnly
<bool> mActorDestroyed
;
358 OpenProtocolOnMainThread(nsIEventTarget
* aEventTarget
);
364 AssertIsOnBoundThread()
366 THREADSAFETY_ASSERT(mBoundThread
);
369 DebugOnly
<bool> current
;
374 NS_SUCCEEDED(mBoundThread
->IsOnCurrentThread(¤t
)));
375 THREADSAFETY_ASSERT(current
);
379 AssertActorDestroyed()
381 MOZ_ASSERT(mActorDestroyed
, "ChildImpl::ActorDestroy not called in time");
385 : mBoundThread(nullptr)
386 , mActorDestroyed(false)
388 AssertIsOnMainThread();
391 NS_INLINE_DECL_REFCOUNTING(ChildImpl
)
394 // Forwarded from BackgroundChild.
398 // Forwarded from BackgroundChild.
399 static PBackgroundChild
*
400 Alloc(Transport
* aTransport
, ProcessId aOtherProcess
);
402 // Forwarded from BackgroundChild.
403 static PBackgroundChild
*
404 GetForCurrentThread();
406 // Forwarded from BackgroundChild.
408 GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback
* aCallback
);
410 // Forwarded from BackgroundChild.
412 CloseForCurrentThread();
414 // Forwarded from BackgroundChildImpl.
415 static BackgroundChildImpl::ThreadLocal
*
416 GetThreadLocalForCurrentThread();
419 ThreadLocalDestructor(void* aThreadLocal
)
421 auto threadLocalInfo
= static_cast<ThreadLocalInfo
*>(aThreadLocal
);
423 if (threadLocalInfo
) {
424 if (threadLocalInfo
->mActor
) {
425 threadLocalInfo
->mActor
->Close();
426 threadLocalInfo
->mActor
->AssertActorDestroyed();
428 // Since the actor is created on the main thread it must only
429 // be released on the main thread as well.
430 if (!NS_IsMainThread()) {
432 threadLocalInfo
->mActor
.forget(&actor
);
434 nsCOMPtr
<nsIRunnable
> releaser
=
435 NS_NewNonOwningRunnableMethod(actor
, &ChildImpl::Release
);
436 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(releaser
)));
439 delete threadLocalInfo
;
444 DispatchFailureCallback(nsIEventTarget
* aEventTarget
);
446 // This class is reference counted.
449 AssertActorDestroyed();
455 THREADSAFETY_ASSERT(!mBoundThread
);
457 #if defined(DEBUG) || !defined(RELEASE_BUILD)
458 mBoundThread
= NS_GetCurrentThread();
461 THREADSAFETY_ASSERT(mBoundThread
);
464 // Only called by IPDL.
466 ActorDestroy(ActorDestroyReason aWhy
) MOZ_OVERRIDE
;
468 static already_AddRefed
<nsIIPCBackgroundChildCreateCallback
>
472 // -----------------------------------------------------------------------------
473 // ParentImpl Helper Declarations
474 // -----------------------------------------------------------------------------
476 class ParentImpl::ShutdownObserver MOZ_FINAL
: public nsIObserver
481 AssertIsOnMainThread();
490 AssertIsOnMainThread();
494 class ParentImpl::RequestMessageLoopRunnable MOZ_FINAL
:
497 nsCOMPtr
<nsIThread
> mTargetThread
;
498 MessageLoop
* mMessageLoop
;
501 explicit RequestMessageLoopRunnable(nsIThread
* aTargetThread
)
502 : mTargetThread(aTargetThread
), mMessageLoop(nullptr)
504 AssertIsInMainProcess();
505 AssertIsOnMainThread();
506 MOZ_ASSERT(aTargetThread
);
509 NS_DECL_ISUPPORTS_INHERITED
512 ~RequestMessageLoopRunnable()
518 class ParentImpl::ShutdownBackgroundThreadRunnable MOZ_FINAL
: public nsRunnable
521 ShutdownBackgroundThreadRunnable()
523 AssertIsInMainProcess();
524 AssertIsOnMainThread();
527 NS_DECL_ISUPPORTS_INHERITED
530 ~ShutdownBackgroundThreadRunnable()
536 class ParentImpl::ForceCloseBackgroundActorsRunnable MOZ_FINAL
: public nsRunnable
538 nsTArray
<ParentImpl
*>* mActorArray
;
541 explicit ForceCloseBackgroundActorsRunnable(nsTArray
<ParentImpl
*>* aActorArray
)
542 : mActorArray(aActorArray
)
544 AssertIsInMainProcess();
545 AssertIsOnMainThread();
546 MOZ_ASSERT(aActorArray
);
549 NS_DECL_ISUPPORTS_INHERITED
552 ~ForceCloseBackgroundActorsRunnable()
558 class ParentImpl::CreateCallbackRunnable MOZ_FINAL
: public nsRunnable
560 nsRefPtr
<CreateCallback
> mCallback
;
563 explicit CreateCallbackRunnable(CreateCallback
* aCallback
)
564 : mCallback(aCallback
)
566 AssertIsInMainProcess();
567 AssertIsOnMainThread();
568 MOZ_ASSERT(aCallback
);
571 NS_DECL_ISUPPORTS_INHERITED
574 ~CreateCallbackRunnable()
580 class ParentImpl::ConnectActorRunnable MOZ_FINAL
: public nsRunnable
582 nsRefPtr
<ParentImpl
> mActor
;
583 Transport
* mTransport
;
584 ProcessHandle mProcessHandle
;
585 nsTArray
<ParentImpl
*>* mLiveActorArray
;
588 ConnectActorRunnable(ParentImpl
* aActor
,
589 Transport
* aTransport
,
590 ProcessHandle aProcessHandle
,
591 nsTArray
<ParentImpl
*>* aLiveActorArray
)
592 : mActor(aActor
), mTransport(aTransport
), mProcessHandle(aProcessHandle
),
593 mLiveActorArray(aLiveActorArray
)
595 AssertIsInMainProcess();
596 AssertIsOnMainThread();
598 MOZ_ASSERT(aTransport
);
599 MOZ_ASSERT(aLiveActorArray
);
602 NS_DECL_ISUPPORTS_INHERITED
605 ~ConnectActorRunnable()
607 AssertIsInMainProcess();
613 class NS_NO_VTABLE
ParentImpl::CreateCallback
616 NS_INLINE_DECL_REFCOUNTING(CreateCallback
)
619 Success(already_AddRefed
<ParentImpl
> aActor
, MessageLoop
* aMessageLoop
) = 0;
625 virtual ~CreateCallback()
629 // -----------------------------------------------------------------------------
630 // ChildImpl Helper Declarations
631 // -----------------------------------------------------------------------------
633 class ChildImpl::ShutdownObserver MOZ_FINAL
: public nsIObserver
638 AssertIsOnMainThread();
647 AssertIsOnMainThread();
651 class ChildImpl::CreateActorRunnable MOZ_FINAL
: public nsRunnable
653 nsCOMPtr
<nsIEventTarget
> mEventTarget
;
656 CreateActorRunnable()
657 : mEventTarget(NS_GetCurrentThread())
659 MOZ_ASSERT(mEventTarget
);
662 NS_DECL_ISUPPORTS_INHERITED
665 ~CreateActorRunnable()
671 class ChildImpl::ParentCreateCallback MOZ_FINAL
:
672 public ParentImpl::CreateCallback
674 nsCOMPtr
<nsIEventTarget
> mEventTarget
;
677 explicit ParentCreateCallback(nsIEventTarget
* aEventTarget
)
678 : mEventTarget(aEventTarget
)
680 AssertIsInMainProcess();
681 AssertIsOnMainThread();
682 MOZ_ASSERT(aEventTarget
);
686 ~ParentCreateCallback()
690 Success(already_AddRefed
<ParentImpl
> aActor
, MessageLoop
* aMessageLoop
)
694 Failure() MOZ_OVERRIDE
;
697 // Must be cancelable in order to dispatch on active worker threads
698 class ChildImpl::AlreadyCreatedCallbackRunnable MOZ_FINAL
:
699 public nsCancelableRunnable
702 AlreadyCreatedCallbackRunnable()
704 // May be created on any thread!
707 NS_DECL_ISUPPORTS_INHERITED
710 virtual ~AlreadyCreatedCallbackRunnable()
714 NS_DECL_NSICANCELABLERUNNABLE
717 class ChildImpl::FailedCreateCallbackRunnable MOZ_FINAL
: public nsRunnable
720 FailedCreateCallbackRunnable()
722 // May be created on any thread!
725 NS_DECL_ISUPPORTS_INHERITED
728 virtual ~FailedCreateCallbackRunnable()
734 class ChildImpl::OpenChildProcessActorRunnable MOZ_FINAL
: public nsRunnable
736 nsRefPtr
<ChildImpl
> mActor
;
737 nsAutoPtr
<Transport
> mTransport
;
738 ProcessHandle mProcessHandle
;
741 OpenChildProcessActorRunnable(already_AddRefed
<ChildImpl
>&& aActor
,
742 Transport
* aTransport
,
743 ProcessHandle aProcessHandle
)
744 : mActor(aActor
), mTransport(aTransport
),
745 mProcessHandle(aProcessHandle
)
747 AssertIsOnMainThread();
749 MOZ_ASSERT(aTransport
);
752 NS_DECL_ISUPPORTS_INHERITED
755 ~OpenChildProcessActorRunnable()
758 CRASH_IN_CHILD_PROCESS("Leaking transport!");
759 unused
<< mTransport
.forget();
766 class ChildImpl::OpenMainProcessActorRunnable MOZ_FINAL
: public nsRunnable
768 nsRefPtr
<ChildImpl
> mActor
;
769 nsRefPtr
<ParentImpl
> mParentActor
;
770 MessageLoop
* mParentMessageLoop
;
773 OpenMainProcessActorRunnable(already_AddRefed
<ChildImpl
>&& aChildActor
,
774 already_AddRefed
<ParentImpl
> aParentActor
,
775 MessageLoop
* aParentMessageLoop
)
776 : mActor(aChildActor
), mParentActor(aParentActor
),
777 mParentMessageLoop(aParentMessageLoop
)
779 AssertIsOnMainThread();
780 MOZ_ASSERT(mParentActor
);
781 MOZ_ASSERT(aParentMessageLoop
);
784 NS_DECL_ISUPPORTS_INHERITED
787 ~OpenMainProcessActorRunnable()
793 } // anonymous namespace
799 IsOnBackgroundThread()
801 return ParentImpl::IsOnBackgroundThread();
807 AssertIsOnBackgroundThread()
809 ParentImpl::AssertIsOnBackgroundThread();
815 } // namespace mozilla
817 // -----------------------------------------------------------------------------
818 // BackgroundParent Public Methods
819 // -----------------------------------------------------------------------------
823 BackgroundParent::IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
)
825 return ParentImpl::IsOtherProcessActor(aBackgroundActor
);
829 already_AddRefed
<ContentParent
>
830 BackgroundParent::GetContentParent(PBackgroundParent
* aBackgroundActor
)
832 return ParentImpl::GetContentParent(aBackgroundActor
);
837 BackgroundParent::Alloc(ContentParent
* aContent
,
838 Transport
* aTransport
,
839 ProcessId aOtherProcess
)
841 return ParentImpl::Alloc(aContent
, aTransport
, aOtherProcess
);
844 // -----------------------------------------------------------------------------
845 // BackgroundChild Public Methods
846 // -----------------------------------------------------------------------------
850 BackgroundChild::Startup()
852 ChildImpl::Startup();
857 BackgroundChild::Alloc(Transport
* aTransport
, ProcessId aOtherProcess
)
859 return ChildImpl::Alloc(aTransport
, aOtherProcess
);
864 BackgroundChild::GetForCurrentThread()
866 return ChildImpl::GetForCurrentThread();
871 BackgroundChild::GetOrCreateForCurrentThread(
872 nsIIPCBackgroundChildCreateCallback
* aCallback
)
874 return ChildImpl::GetOrCreateForCurrentThread(aCallback
);
879 BackgroundChild::CloseForCurrentThread()
881 ChildImpl::CloseForCurrentThread();
884 // -----------------------------------------------------------------------------
885 // BackgroundChildImpl Public Methods
886 // -----------------------------------------------------------------------------
889 BackgroundChildImpl::ThreadLocal
*
890 BackgroundChildImpl::GetThreadLocalForCurrentThread()
892 return ChildImpl::GetThreadLocalForCurrentThread();
895 // -----------------------------------------------------------------------------
896 // ParentImpl Static Members
897 // -----------------------------------------------------------------------------
899 const ParentImpl::ProcessHandle
ParentImpl::kInvalidProcessHandle
=
901 ProcessHandle(INVALID_HANDLE_VALUE
);
906 StaticRefPtr
<nsIThread
> ParentImpl::sBackgroundThread
;
908 nsTArray
<ParentImpl
*>* ParentImpl::sLiveActorsForBackgroundThread
;
910 StaticRefPtr
<nsITimer
> ParentImpl::sShutdownTimer
;
912 Atomic
<PRThread
*> ParentImpl::sBackgroundPRThread
;
914 MessageLoop
* ParentImpl::sBackgroundThreadMessageLoop
= nullptr;
916 uint64_t ParentImpl::sLiveActorCount
= 0;
918 bool ParentImpl::sShutdownObserverRegistered
= false;
920 bool ParentImpl::sShutdownHasStarted
= false;
922 StaticAutoPtr
<nsTArray
<nsRefPtr
<ParentImpl::CreateCallback
>>>
923 ParentImpl::sPendingCallbacks
;
925 // -----------------------------------------------------------------------------
926 // ChildImpl Static Members
927 // -----------------------------------------------------------------------------
929 unsigned int ChildImpl::sThreadLocalIndex
= kBadThreadLocalIndex
;
931 StaticAutoPtr
<nsTArray
<nsCOMPtr
<nsIEventTarget
>>> ChildImpl::sPendingTargets
;
933 bool ChildImpl::sShutdownHasStarted
= false;
935 // -----------------------------------------------------------------------------
936 // ParentImpl Implementation
937 // -----------------------------------------------------------------------------
941 ParentImpl::IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
)
943 AssertIsOnBackgroundThread();
944 MOZ_ASSERT(aBackgroundActor
);
946 return static_cast<ParentImpl
*>(aBackgroundActor
)->mIsOtherProcessActor
;
950 already_AddRefed
<ContentParent
>
951 ParentImpl::GetContentParent(PBackgroundParent
* aBackgroundActor
)
953 AssertIsOnBackgroundThread();
954 MOZ_ASSERT(aBackgroundActor
);
956 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
957 if (actor
->mActorDestroyed
) {
958 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
962 if (actor
->mContent
) {
963 // We need to hand out a reference to our ContentParent but we also need to
964 // keep the one we have. We can't call AddRef here because ContentParent is
965 // not threadsafe so instead we dispatch a runnable to the main thread to do
966 // it for us. This is safe since we are guaranteed that our AddRef runnable
967 // will run before the reference we hand out can be released, and the
968 // ContentParent can't die as long as the existing reference is maintained.
969 nsCOMPtr
<nsIRunnable
> runnable
=
970 NS_NewNonOwningRunnableMethod(actor
->mContent
, &ContentParent::AddRef
);
971 MOZ_ASSERT(runnable
);
973 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable
)));
976 return already_AddRefed
<ContentParent
>(actor
->mContent
.get());
981 ParentImpl::Alloc(ContentParent
* aContent
,
982 Transport
* aTransport
,
983 ProcessId aOtherProcess
)
985 AssertIsInMainProcess();
986 AssertIsOnMainThread();
987 MOZ_ASSERT(aTransport
);
989 ProcessHandle processHandle
;
990 if (!base::OpenProcessHandle(aOtherProcess
, &processHandle
)) {
991 // Process has already died?
995 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
996 NS_WARNING("Failed to create background thread!");
1000 MOZ_ASSERT(sLiveActorsForBackgroundThread
);
1004 nsRefPtr
<ParentImpl
> actor
= new ParentImpl(aContent
, aTransport
);
1006 nsCOMPtr
<nsIRunnable
> connectRunnable
=
1007 new ConnectActorRunnable(actor
, aTransport
, processHandle
,
1008 sLiveActorsForBackgroundThread
);
1010 if (NS_FAILED(sBackgroundThread
->Dispatch(connectRunnable
,
1011 NS_DISPATCH_NORMAL
))) {
1012 NS_WARNING("Failed to dispatch connect runnable!");
1014 MOZ_ASSERT(sLiveActorCount
);
1017 if (!sLiveActorCount
) {
1018 ShutdownBackgroundThread();
1029 ParentImpl::CreateActorForSameProcess(CreateCallback
* aCallback
)
1031 AssertIsInMainProcess();
1032 AssertIsOnMainThread();
1033 MOZ_ASSERT(aCallback
);
1035 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
1036 NS_WARNING("Failed to create background thread!");
1040 MOZ_ASSERT(!sShutdownHasStarted
);
1044 if (sBackgroundThreadMessageLoop
) {
1045 nsCOMPtr
<nsIRunnable
> callbackRunnable
=
1046 new CreateCallbackRunnable(aCallback
);
1047 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(callbackRunnable
)));
1051 if (!sPendingCallbacks
) {
1052 sPendingCallbacks
= new nsTArray
<nsRefPtr
<CreateCallback
>>();
1055 sPendingCallbacks
->AppendElement(aCallback
);
1061 ParentImpl::CreateBackgroundThread()
1063 AssertIsInMainProcess();
1064 AssertIsOnMainThread();
1065 MOZ_ASSERT(!sBackgroundThread
);
1066 MOZ_ASSERT(!sLiveActorsForBackgroundThread
);
1068 if (sShutdownHasStarted
) {
1069 NS_WARNING("Trying to create background thread after shutdown has "
1074 nsCOMPtr
<nsITimer
> newShutdownTimer
;
1076 if (!sShutdownTimer
) {
1078 newShutdownTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
, &rv
);
1079 if (NS_WARN_IF(NS_FAILED(rv
))) {
1084 if (!sShutdownObserverRegistered
) {
1085 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
1086 if (NS_WARN_IF(!obs
)) {
1090 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
1093 obs
->AddObserver(observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
1094 if (NS_WARN_IF(NS_FAILED(rv
))) {
1098 sShutdownObserverRegistered
= true;
1101 nsCOMPtr
<nsIThread
> thread
;
1102 if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread
)))) {
1103 NS_WARNING("NS_NewNamedThread failed!");
1107 nsCOMPtr
<nsIRunnable
> messageLoopRunnable
=
1108 new RequestMessageLoopRunnable(thread
);
1109 if (NS_FAILED(thread
->Dispatch(messageLoopRunnable
, NS_DISPATCH_NORMAL
))) {
1110 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable!");
1114 sBackgroundThread
= thread
;
1115 sLiveActorsForBackgroundThread
= new nsTArray
<ParentImpl
*>(1);
1117 if (!sShutdownTimer
) {
1118 MOZ_ASSERT(newShutdownTimer
);
1119 sShutdownTimer
= newShutdownTimer
;
1127 ParentImpl::ShutdownBackgroundThread()
1129 AssertIsInMainProcess();
1130 AssertIsOnMainThread();
1131 MOZ_ASSERT_IF(!sBackgroundThread
, !sBackgroundThreadMessageLoop
);
1132 MOZ_ASSERT_IF(!sShutdownHasStarted
, !sLiveActorCount
);
1133 MOZ_ASSERT_IF(!sBackgroundThread
, !sLiveActorCount
);
1134 MOZ_ASSERT_IF(sBackgroundThread
, sShutdownTimer
);
1136 if (sPendingCallbacks
) {
1137 if (!sPendingCallbacks
->IsEmpty()) {
1138 nsTArray
<nsRefPtr
<CreateCallback
>> callbacks
;
1139 sPendingCallbacks
->SwapElements(callbacks
);
1141 for (uint32_t index
= 0; index
< callbacks
.Length(); index
++) {
1142 nsRefPtr
<CreateCallback
> callback
;
1143 callbacks
[index
].swap(callback
);
1144 MOZ_ASSERT(callback
);
1146 callback
->Failure();
1150 if (sShutdownHasStarted
) {
1151 sPendingCallbacks
= nullptr;
1155 nsCOMPtr
<nsITimer
> shutdownTimer
;
1156 if (sShutdownHasStarted
) {
1157 shutdownTimer
= sShutdownTimer
.get();
1158 sShutdownTimer
= nullptr;
1161 if (sBackgroundThread
) {
1162 nsCOMPtr
<nsIThread
> thread
= sBackgroundThread
.get();
1163 nsAutoPtr
<nsTArray
<ParentImpl
*>> liveActors(sLiveActorsForBackgroundThread
);
1165 sBackgroundThread
= nullptr;
1166 sLiveActorsForBackgroundThread
= nullptr;
1167 sBackgroundThreadMessageLoop
= nullptr;
1169 MOZ_ASSERT_IF(!sShutdownHasStarted
, !sLiveActorCount
);
1171 if (sShutdownHasStarted
) {
1172 // If this is final shutdown then we need to spin the event loop while we
1173 // wait for all the actors to be cleaned up. We also set a timeout to
1174 // force-kill any hanging actors.
1176 if (sLiveActorCount
) {
1177 TimerCallbackClosure
closure(thread
, liveActors
);
1179 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
1180 shutdownTimer
->InitWithFuncCallback(&ShutdownTimerCallback
, &closure
,
1181 kShutdownTimerDelayMS
,
1182 nsITimer::TYPE_ONE_SHOT
)));
1184 nsIThread
* currentThread
= NS_GetCurrentThread();
1185 MOZ_ASSERT(currentThread
);
1187 while (sLiveActorCount
) {
1188 NS_ProcessNextEvent(currentThread
);
1191 MOZ_ASSERT(liveActors
->IsEmpty());
1193 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(shutdownTimer
->Cancel()));
1197 // Dispatch this runnable to unregister the thread from the profiler.
1198 nsCOMPtr
<nsIRunnable
> shutdownRunnable
=
1199 new ShutdownBackgroundThreadRunnable();
1200 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread
->Dispatch(shutdownRunnable
,
1201 NS_DISPATCH_NORMAL
)));
1203 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread
->Shutdown()));
1209 ParentImpl::ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
)
1211 AssertIsInMainProcess();
1212 AssertIsOnMainThread();
1213 MOZ_ASSERT(sShutdownHasStarted
);
1214 MOZ_ASSERT(sLiveActorCount
);
1216 auto closure
= static_cast<TimerCallbackClosure
*>(aClosure
);
1217 MOZ_ASSERT(closure
);
1219 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1223 nsCOMPtr
<nsIRunnable
> forceCloseRunnable
=
1224 new ForceCloseBackgroundActorsRunnable(closure
->mLiveActors
);
1225 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(closure
->mThread
->Dispatch(forceCloseRunnable
,
1226 NS_DISPATCH_NORMAL
)));
1230 ParentImpl::Destroy()
1232 // May be called on any thread!
1234 AssertIsInMainProcess();
1236 nsCOMPtr
<nsIRunnable
> destroyRunnable
=
1237 NS_NewNonOwningRunnableMethod(this, &ParentImpl::MainThreadActorDestroy
);
1238 MOZ_ASSERT(destroyRunnable
);
1240 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(destroyRunnable
)));
1244 ParentImpl::MainThreadActorDestroy()
1246 AssertIsInMainProcess();
1247 AssertIsOnMainThread();
1248 MOZ_ASSERT_IF(mIsOtherProcessActor
, mContent
);
1249 MOZ_ASSERT_IF(!mIsOtherProcessActor
, !mContent
);
1250 MOZ_ASSERT_IF(mIsOtherProcessActor
, mTransport
);
1251 MOZ_ASSERT_IF(!mIsOtherProcessActor
, !mTransport
);
1254 XRE_GetIOMessageLoop()->PostTask(FROM_HERE
,
1255 new DeleteTask
<Transport
>(mTransport
));
1256 mTransport
= nullptr;
1259 ProcessHandle otherProcess
= OtherProcess();
1260 if (otherProcess
!= kInvalidProcessHandle
) {
1261 base::CloseProcessHandle(otherProcess
);
1263 SetOtherProcess(kInvalidProcessHandle
);
1269 MOZ_ASSERT(sLiveActorCount
);
1272 if (!sLiveActorCount
) {
1273 ShutdownBackgroundThread();
1276 // This may be the last reference!
1281 ParentImpl::CloneToplevel(const InfallibleTArray
<ProtocolFdMapping
>& aFds
,
1282 ProcessHandle aPeerProcess
,
1283 ProtocolCloneContext
* aCtx
)
1285 AssertIsInMainProcess();
1286 AssertIsOnMainThread();
1288 const ProtocolId protocolId
= GetProtocolId();
1290 for (unsigned int i
= 0; i
< aFds
.Length(); i
++) {
1291 if (static_cast<ProtocolId
>(aFds
[i
].protocolId()) != protocolId
) {
1295 Transport
* transport
= OpenDescriptor(aFds
[i
].fd(),
1296 Transport::MODE_SERVER
);
1298 NS_WARNING("Failed to open transport!");
1302 PBackgroundParent
* clonedActor
=
1303 Alloc(mContent
, transport
, base::GetProcId(aPeerProcess
));
1304 MOZ_ASSERT(clonedActor
);
1306 clonedActor
->CloneManagees(this, aCtx
);
1307 clonedActor
->SetTransport(transport
);
1316 ParentImpl::ActorDestroy(ActorDestroyReason aWhy
)
1318 AssertIsInMainProcess();
1319 AssertIsOnBackgroundThread();
1320 MOZ_ASSERT(!mActorDestroyed
);
1321 MOZ_ASSERT_IF(mIsOtherProcessActor
, mLiveActorArray
);
1323 BackgroundParentImpl::ActorDestroy(aWhy
);
1325 mActorDestroyed
= true;
1327 if (mLiveActorArray
) {
1328 MOZ_ALWAYS_TRUE(mLiveActorArray
->RemoveElement(this));
1329 mLiveActorArray
= nullptr;
1332 // This is tricky. We should be able to call Destroy() here directly because
1333 // we're not going to touch 'this' or our MessageChannel any longer on this
1334 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1335 // it runs it will destroy 'this' and our associated MessageChannel. However,
1336 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1337 // racing with the main thread we must ensure that the MessageChannel lives
1338 // long enough to be cleared in this call stack.
1339 nsCOMPtr
<nsIRunnable
> destroyRunnable
=
1340 NS_NewNonOwningRunnableMethod(this, &ParentImpl::Destroy
);
1341 MOZ_ASSERT(destroyRunnable
);
1343 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(destroyRunnable
)));
1346 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver
, nsIObserver
)
1349 ParentImpl::ShutdownObserver::Observe(nsISupports
* aSubject
,
1351 const char16_t
* aData
)
1353 AssertIsInMainProcess();
1354 AssertIsOnMainThread();
1355 MOZ_ASSERT(!sShutdownHasStarted
);
1356 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1358 sShutdownHasStarted
= true;
1360 // Do this first before calling (and spinning the event loop in)
1361 // ShutdownBackgroundThread().
1362 ChildImpl::Shutdown();
1364 ShutdownBackgroundThread();
1369 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::RequestMessageLoopRunnable
,
1373 ParentImpl::RequestMessageLoopRunnable::Run()
1375 AssertIsInMainProcess();
1376 MOZ_ASSERT(mTargetThread
);
1378 if (NS_IsMainThread()) {
1379 MOZ_ASSERT(mMessageLoop
);
1381 if (!sBackgroundThread
||
1382 !SameCOMIdentity(mTargetThread
.get(), sBackgroundThread
.get())) {
1386 MOZ_ASSERT(!sBackgroundThreadMessageLoop
);
1387 sBackgroundThreadMessageLoop
= mMessageLoop
;
1389 if (sPendingCallbacks
&& !sPendingCallbacks
->IsEmpty()) {
1390 nsTArray
<nsRefPtr
<CreateCallback
>> callbacks
;
1391 sPendingCallbacks
->SwapElements(callbacks
);
1393 for (uint32_t index
= 0; index
< callbacks
.Length(); index
++) {
1394 MOZ_ASSERT(callbacks
[index
]);
1396 nsCOMPtr
<nsIRunnable
> callbackRunnable
=
1397 new CreateCallbackRunnable(callbacks
[index
]);
1398 if (NS_FAILED(NS_DispatchToCurrentThread(callbackRunnable
))) {
1399 NS_WARNING("Failed to dispatch callback runnable!");
1407 char stackBaseGuess
;
1408 profiler_register_thread("IPDL Background", &stackBaseGuess
);
1413 MOZ_ASSERT(NS_SUCCEEDED(mTargetThread
->IsOnCurrentThread(&correctThread
)));
1414 MOZ_ASSERT(correctThread
);
1418 DebugOnly
<PRThread
*> oldBackgroundThread
=
1419 sBackgroundPRThread
.exchange(PR_GetCurrentThread());
1421 MOZ_ASSERT_IF(oldBackgroundThread
,
1422 PR_GetCurrentThread() != oldBackgroundThread
);
1424 MOZ_ASSERT(!mMessageLoop
);
1426 mMessageLoop
= MessageLoop::current();
1427 MOZ_ASSERT(mMessageLoop
);
1429 if (NS_FAILED(NS_DispatchToMainThread(this))) {
1430 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!");
1431 return NS_ERROR_FAILURE
;
1437 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ShutdownBackgroundThreadRunnable
,
1441 ParentImpl::ShutdownBackgroundThreadRunnable::Run()
1443 AssertIsInMainProcess();
1445 // It is possible that another background thread was created while this thread
1446 // was shutting down. In that case we can't assert anything about
1447 // sBackgroundPRThread and we should not modify it here.
1448 sBackgroundPRThread
.compareExchange(PR_GetCurrentThread(), nullptr);
1450 profiler_unregister_thread();
1455 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ForceCloseBackgroundActorsRunnable
,
1459 ParentImpl::ForceCloseBackgroundActorsRunnable::Run()
1461 AssertIsInMainProcess();
1462 MOZ_ASSERT(mActorArray
);
1464 if (NS_IsMainThread()) {
1465 MOZ_ASSERT(sLiveActorCount
);
1470 AssertIsOnBackgroundThread();
1472 if (!mActorArray
->IsEmpty()) {
1473 // Copy the array since calling Close() could mutate the actual array.
1474 nsTArray
<ParentImpl
*> actorsToClose(*mActorArray
);
1476 for (uint32_t index
= 0; index
< actorsToClose
.Length(); index
++) {
1477 actorsToClose
[index
]->Close();
1481 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this)));
1486 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::CreateCallbackRunnable
, nsRunnable
)
1489 ParentImpl::CreateCallbackRunnable::Run()
1491 AssertIsInMainProcess();
1492 AssertIsOnMainThread();
1493 MOZ_ASSERT(sBackgroundThreadMessageLoop
);
1494 MOZ_ASSERT(mCallback
);
1496 nsRefPtr
<CreateCallback
> callback
;
1497 mCallback
.swap(callback
);
1499 nsRefPtr
<ParentImpl
> actor
= new ParentImpl();
1501 callback
->Success(actor
.forget(), sBackgroundThreadMessageLoop
);
1506 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ConnectActorRunnable
, nsRunnable
)
1509 ParentImpl::ConnectActorRunnable::Run()
1511 AssertIsInMainProcess();
1512 AssertIsOnBackgroundThread();
1514 // Transfer ownership to this thread. If Open() fails then we will release
1515 // this reference in Destroy.
1517 mActor
.forget(&actor
);
1519 if (!actor
->Open(mTransport
, mProcessHandle
, XRE_GetIOMessageLoop(),
1522 return NS_ERROR_FAILURE
;
1525 actor
->SetLiveActorArray(mLiveActorArray
);
1530 // -----------------------------------------------------------------------------
1531 // ChildImpl Implementation
1532 // -----------------------------------------------------------------------------
1536 ChildImpl::Startup()
1538 // This happens on the main thread but before XPCOM has started so we can't
1539 // assert that we're being called on the main thread here.
1541 MOZ_ASSERT(sThreadLocalIndex
== kBadThreadLocalIndex
,
1542 "BackgroundChild::Startup() called more than once!");
1545 PR_NewThreadPrivateIndex(&sThreadLocalIndex
, ThreadLocalDestructor
);
1546 MOZ_RELEASE_ASSERT(status
== PR_SUCCESS
, "PR_NewThreadPrivateIndex failed!");
1548 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
);
1550 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1551 MOZ_RELEASE_ASSERT(observerService
);
1553 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
1556 observerService
->AddObserver(observer
,
1557 NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
,
1559 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
1564 ChildImpl::Shutdown()
1566 AssertIsOnMainThread();
1568 if (sShutdownHasStarted
) {
1569 MOZ_ASSERT_IF(sThreadLocalIndex
!= kBadThreadLocalIndex
,
1570 !PR_GetThreadPrivate(sThreadLocalIndex
));
1574 sShutdownHasStarted
= true;
1576 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
);
1578 DebugOnly
<PRStatus
> status
= PR_SetThreadPrivate(sThreadLocalIndex
, nullptr);
1579 MOZ_ASSERT(status
== PR_SUCCESS
);
1584 ChildImpl::Alloc(Transport
* aTransport
, ProcessId aOtherProcess
)
1586 AssertIsInChildProcess();
1587 AssertIsOnMainThread();
1588 MOZ_ASSERT(aTransport
);
1589 MOZ_ASSERT(sPendingTargets
);
1590 MOZ_ASSERT(!sPendingTargets
->IsEmpty());
1592 nsCOMPtr
<nsIEventTarget
> eventTarget
;
1593 sPendingTargets
->ElementAt(0).swap(eventTarget
);
1595 sPendingTargets
->RemoveElementAt(0);
1597 ProcessHandle processHandle
;
1598 if (!base::OpenProcessHandle(aOtherProcess
, &processHandle
)) {
1599 MOZ_CRASH("Failed to open process handle!");
1602 nsRefPtr
<ChildImpl
> actor
= new ChildImpl();
1604 ChildImpl
* weakActor
= actor
;
1606 nsCOMPtr
<nsIRunnable
> openRunnable
=
1607 new OpenChildProcessActorRunnable(actor
.forget(), aTransport
,
1609 if (NS_FAILED(eventTarget
->Dispatch(openRunnable
, NS_DISPATCH_NORMAL
))) {
1610 MOZ_CRASH("Failed to dispatch OpenActorRunnable!");
1613 // This value is only checked against null to determine success/failure, so
1614 // there is no need to worry about the reference count here.
1620 ChildImpl::GetForCurrentThread()
1622 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
);
1624 auto threadLocalInfo
=
1625 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1627 if (!threadLocalInfo
) {
1631 return threadLocalInfo
->mActor
;
1636 ChildImpl::GetOrCreateForCurrentThread(
1637 nsIIPCBackgroundChildCreateCallback
* aCallback
)
1639 MOZ_ASSERT(aCallback
);
1640 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
,
1641 "BackgroundChild::Startup() was never called!");
1643 bool created
= false;
1645 auto threadLocalInfo
=
1646 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1648 if (threadLocalInfo
) {
1649 threadLocalInfo
->mCallbacks
.AppendElement(aCallback
);
1651 nsAutoPtr
<ThreadLocalInfo
> newInfo(new ThreadLocalInfo(aCallback
));
1653 if (PR_SetThreadPrivate(sThreadLocalIndex
, newInfo
) != PR_SUCCESS
) {
1654 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
1659 threadLocalInfo
= newInfo
.forget();
1662 if (threadLocalInfo
->mActor
) {
1663 // Runnable will use GetForCurrentThread() to retrieve actor again. This
1664 // allows us to avoid addref'ing on the wrong thread.
1665 nsCOMPtr
<nsIRunnable
> runnable
= new AlreadyCreatedCallbackRunnable();
1666 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable
)));
1672 // We have already started the sequence for opening the actor so there's
1673 // nothing else we need to do here. This callback will be called after the
1674 // first callback in the schedule runnable.
1678 if (NS_IsMainThread()) {
1679 if (NS_WARN_IF(!OpenProtocolOnMainThread(NS_GetCurrentThread()))) {
1686 nsRefPtr
<CreateActorRunnable
> runnable
= new CreateActorRunnable();
1687 if (NS_FAILED(NS_DispatchToMainThread(runnable
))) {
1688 CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
1697 ChildImpl::CloseForCurrentThread()
1699 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
,
1700 "BackgroundChild::Startup() was never called!");
1701 auto threadLocalInfo
=
1702 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1704 // If we don't have a thread local we are in one of these conditions:
1705 // 1) Startup has not completed and we are racing
1706 // 2) We were called again after a previous close or shutdown
1707 // For now, these should not happen, so crash. We can add extra complexity
1708 // in the future if it turns out we need to support these cases.
1709 if (!threadLocalInfo
) {
1710 MOZ_CRASH("Attempting to close a non-existent PBackground actor!");
1713 if (threadLocalInfo
->mActor
) {
1714 threadLocalInfo
->mActor
->FlushPendingInterruptQueue();
1717 // Clearing the thread local will synchronously close the actor.
1718 DebugOnly
<PRStatus
> status
= PR_SetThreadPrivate(sThreadLocalIndex
, nullptr);
1719 MOZ_ASSERT(status
== PR_SUCCESS
);
1723 BackgroundChildImpl::ThreadLocal
*
1724 ChildImpl::GetThreadLocalForCurrentThread()
1726 MOZ_ASSERT(sThreadLocalIndex
!= kBadThreadLocalIndex
,
1727 "BackgroundChild::Startup() was never called!");
1729 auto threadLocalInfo
=
1730 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1732 if (!threadLocalInfo
) {
1736 if (!threadLocalInfo
->mConsumerThreadLocal
) {
1737 threadLocalInfo
->mConsumerThreadLocal
=
1738 new BackgroundChildImpl::ThreadLocal();
1741 return threadLocalInfo
->mConsumerThreadLocal
;
1745 already_AddRefed
<nsIIPCBackgroundChildCreateCallback
>
1746 ChildImpl::GetNextCallback()
1748 // May run on any thread!
1750 auto threadLocalInfo
=
1751 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1752 MOZ_ASSERT(threadLocalInfo
);
1754 if (threadLocalInfo
->mCallbacks
.IsEmpty()) {
1758 nsCOMPtr
<nsIIPCBackgroundChildCreateCallback
> callback
;
1759 threadLocalInfo
->mCallbacks
[0].swap(callback
);
1761 threadLocalInfo
->mCallbacks
.RemoveElementAt(0);
1763 return callback
.forget();
1766 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::AlreadyCreatedCallbackRunnable
,
1767 nsCancelableRunnable
)
1770 ChildImpl::AlreadyCreatedCallbackRunnable::Run()
1772 // May run on any thread!
1774 // Report the current actor back in the callback.
1775 PBackgroundChild
* actor
= ChildImpl::GetForCurrentThread();
1777 // If the current actor is null, do not create a new actor here. This likely
1778 // means we are in the process of cleaning up a worker thread and do not want
1779 // a new actor created. Unfortunately we cannot report back to the callback
1780 // because the thread local is gone at this point. Instead simply do nothing
1782 if (NS_WARN_IF(!actor
)) {
1786 nsCOMPtr
<nsIIPCBackgroundChildCreateCallback
> callback
=
1787 ChildImpl::GetNextCallback();
1789 callback
->ActorCreated(actor
);
1790 callback
= ChildImpl::GetNextCallback();
1797 ChildImpl::AlreadyCreatedCallbackRunnable::Cancel()
1799 // These are IPC infrastructure objects and need to run unconditionally.
1804 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::FailedCreateCallbackRunnable
,
1808 ChildImpl::FailedCreateCallbackRunnable::Run()
1810 // May run on any thread!
1812 nsCOMPtr
<nsIIPCBackgroundChildCreateCallback
> callback
=
1813 ChildImpl::GetNextCallback();
1815 callback
->ActorFailed();
1816 callback
= ChildImpl::GetNextCallback();
1822 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenChildProcessActorRunnable
,
1826 ChildImpl::OpenChildProcessActorRunnable::Run()
1828 // May be run on any thread!
1830 AssertIsInChildProcess();
1832 MOZ_ASSERT(mTransport
);
1834 nsCOMPtr
<nsIIPCBackgroundChildCreateCallback
> callback
=
1835 ChildImpl::GetNextCallback();
1836 MOZ_ASSERT(callback
,
1837 "There should be at least one callback when first creating the "
1840 nsRefPtr
<ChildImpl
> strongActor
;
1841 mActor
.swap(strongActor
);
1843 if (!strongActor
->Open(mTransport
.forget(), mProcessHandle
,
1844 XRE_GetIOMessageLoop(), ChildSide
)) {
1845 CRASH_IN_CHILD_PROCESS("Failed to open ChildImpl!");
1848 callback
->ActorFailed();
1849 callback
= ChildImpl::GetNextCallback();
1855 // Now that Open() has succeeded transfer the ownership of the actor to IPDL.
1856 auto threadLocalInfo
=
1857 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1859 MOZ_ASSERT(threadLocalInfo
);
1860 MOZ_ASSERT(!threadLocalInfo
->mActor
);
1862 nsRefPtr
<ChildImpl
>& actor
= threadLocalInfo
->mActor
;
1863 strongActor
.swap(actor
);
1865 actor
->SetBoundThread();
1868 callback
->ActorCreated(actor
);
1869 callback
= ChildImpl::GetNextCallback();
1875 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenMainProcessActorRunnable
,
1879 ChildImpl::OpenMainProcessActorRunnable::Run()
1881 // May run on any thread!
1883 AssertIsInMainProcess();
1885 MOZ_ASSERT(mParentActor
);
1886 MOZ_ASSERT(mParentMessageLoop
);
1888 nsCOMPtr
<nsIIPCBackgroundChildCreateCallback
> callback
=
1889 ChildImpl::GetNextCallback();
1890 MOZ_ASSERT(callback
,
1891 "There should be at least one callback when first creating the "
1894 nsRefPtr
<ChildImpl
> strongChildActor
;
1895 mActor
.swap(strongChildActor
);
1897 nsRefPtr
<ParentImpl
> parentActor
;
1898 mParentActor
.swap(parentActor
);
1900 MessageChannel
* parentChannel
= parentActor
->GetIPCChannel();
1901 MOZ_ASSERT(parentChannel
);
1903 if (!strongChildActor
->Open(parentChannel
, mParentMessageLoop
, ChildSide
)) {
1904 NS_WARNING("Failed to open ChildImpl!");
1906 parentActor
->Destroy();
1909 callback
->ActorFailed();
1910 callback
= ChildImpl::GetNextCallback();
1916 // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
1917 unused
<< parentActor
.forget();
1919 auto threadLocalInfo
=
1920 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(sThreadLocalIndex
));
1922 MOZ_ASSERT(threadLocalInfo
);
1923 MOZ_ASSERT(!threadLocalInfo
->mActor
);
1925 nsRefPtr
<ChildImpl
>& childActor
= threadLocalInfo
->mActor
;
1926 strongChildActor
.swap(childActor
);
1928 childActor
->SetBoundThread();
1931 callback
->ActorCreated(childActor
);
1932 callback
= ChildImpl::GetNextCallback();
1938 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateActorRunnable
, nsRunnable
)
1941 ChildImpl::CreateActorRunnable::Run()
1943 AssertIsOnMainThread();
1945 if (!OpenProtocolOnMainThread(mEventTarget
)) {
1946 NS_WARNING("OpenProtocolOnMainThread failed!");
1947 return NS_ERROR_FAILURE
;
1954 ChildImpl::ParentCreateCallback::Success(
1955 already_AddRefed
<ParentImpl
> aParentActor
,
1956 MessageLoop
* aParentMessageLoop
)
1958 AssertIsInMainProcess();
1959 AssertIsOnMainThread();
1961 nsRefPtr
<ParentImpl
> parentActor
= aParentActor
;
1962 MOZ_ASSERT(parentActor
);
1963 MOZ_ASSERT(aParentMessageLoop
);
1964 MOZ_ASSERT(mEventTarget
);
1966 nsRefPtr
<ChildImpl
> childActor
= new ChildImpl();
1968 nsCOMPtr
<nsIEventTarget
> target
;
1969 mEventTarget
.swap(target
);
1971 nsCOMPtr
<nsIRunnable
> openRunnable
=
1972 new OpenMainProcessActorRunnable(childActor
.forget(), parentActor
.forget(),
1973 aParentMessageLoop
);
1974 if (NS_FAILED(target
->Dispatch(openRunnable
, NS_DISPATCH_NORMAL
))) {
1975 NS_WARNING("Failed to dispatch open runnable!");
1980 ChildImpl::ParentCreateCallback::Failure()
1982 AssertIsInMainProcess();
1983 AssertIsOnMainThread();
1984 MOZ_ASSERT(mEventTarget
);
1986 nsCOMPtr
<nsIEventTarget
> target
;
1987 mEventTarget
.swap(target
);
1989 DispatchFailureCallback(target
);
1994 ChildImpl::OpenProtocolOnMainThread(nsIEventTarget
* aEventTarget
)
1996 AssertIsOnMainThread();
1997 MOZ_ASSERT(aEventTarget
);
1999 if (sShutdownHasStarted
) {
2000 MOZ_CRASH("Called BackgroundChild::GetOrCreateForCurrentThread after "
2001 "shutdown has started!");
2004 if (IsMainProcess()) {
2005 nsRefPtr
<ParentImpl::CreateCallback
> parentCallback
=
2006 new ParentCreateCallback(aEventTarget
);
2008 if (!ParentImpl::CreateActorForSameProcess(parentCallback
)) {
2009 NS_WARNING("BackgroundParent::CreateActor() failed!");
2010 DispatchFailureCallback(aEventTarget
);
2017 ContentChild
* content
= ContentChild::GetSingleton();
2018 MOZ_ASSERT(content
);
2020 if (!PBackground::Open(content
)) {
2021 MOZ_CRASH("Failed to create top level actor!");
2025 if (!sPendingTargets
) {
2026 sPendingTargets
= new nsTArray
<nsCOMPtr
<nsIEventTarget
>>(1);
2027 ClearOnShutdown(&sPendingTargets
);
2030 sPendingTargets
->AppendElement(aEventTarget
);
2037 ChildImpl::DispatchFailureCallback(nsIEventTarget
* aEventTarget
)
2039 MOZ_ASSERT(aEventTarget
);
2041 nsCOMPtr
<nsIRunnable
> callbackRunnable
= new FailedCreateCallbackRunnable();
2042 if (NS_FAILED(aEventTarget
->Dispatch(callbackRunnable
, NS_DISPATCH_NORMAL
))) {
2043 NS_WARNING("Failed to dispatch CreateCallbackRunnable!");
2048 ChildImpl::ActorDestroy(ActorDestroyReason aWhy
)
2050 AssertIsOnBoundThread();
2052 MOZ_ASSERT(!mActorDestroyed
);
2053 mActorDestroyed
= true;
2055 BackgroundChildImpl::ActorDestroy(aWhy
);
2058 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver
, nsIObserver
)
2061 ChildImpl::ShutdownObserver::Observe(nsISupports
* aSubject
,
2063 const char16_t
* aData
)
2065 AssertIsOnMainThread();
2066 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
2068 ChildImpl::Shutdown();