Bumping manifests a=b2g-bump
[gecko.git] / ipc / glue / BackgroundImpl.cpp
blobb98c61fc57ce56922d650ab95157ba51d563a01d
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"
22 #include "nsCOMPtr.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"
30 #include "nsITimer.h"
31 #include "nsTArray.h"
32 #include "nsThreadUtils.h"
33 #include "nsTraceRefcnt.h"
34 #include "nsXULAppAPI.h"
35 #include "nsXPCOMPrivate.h"
36 #include "prthread.h"
38 #ifdef RELEASE_BUILD
39 #define THREADSAFETY_ASSERT MOZ_ASSERT
40 #else
41 #define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
42 #endif
44 #define CRASH_IN_CHILD_PROCESS(_msg) \
45 do { \
46 if (IsMainProcess()) { \
47 MOZ_ASSERT(false, _msg); \
48 } else { \
49 MOZ_CRASH(_msg); \
50 } \
51 } \
52 while (0)
54 using namespace mozilla;
55 using namespace mozilla::ipc;
57 using mozilla::dom::ContentChild;
58 using mozilla::dom::ContentParent;
60 namespace {
62 // -----------------------------------------------------------------------------
63 // Utility Functions
64 // -----------------------------------------------------------------------------
66 bool
67 IsMainProcess()
69 static const bool isMainProcess =
70 XRE_GetProcessType() == GeckoProcessType_Default;
71 return isMainProcess;
74 #ifdef DEBUG
75 bool
76 IsChildProcess()
78 return !IsMainProcess();
80 #endif
82 void
83 AssertIsInMainProcess()
85 MOZ_ASSERT(IsMainProcess());
88 void
89 AssertIsInChildProcess()
91 MOZ_ASSERT(IsChildProcess());
94 void
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;
108 public:
109 class CreateCallback;
111 private:
112 class ShutdownObserver;
113 class RequestMessageLoopRunnable;
114 class ShutdownBackgroundThreadRunnable;
115 class ForceCloseBackgroundActorsRunnable;
116 class CreateCallbackRunnable;
117 class ConnectActorRunnable;
119 struct MOZ_STACK_CLASS TimerCallbackClosure
121 nsIThread* mThread;
122 nsTArray<ParentImpl*>* mLiveActors;
124 TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
125 : mThread(aThread), mLiveActors(aLiveActors)
127 AssertIsInMainProcess();
128 AssertIsOnMainThread();
129 MOZ_ASSERT(aThread);
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
162 // needed.
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
195 // thread.
196 bool mActorDestroyed;
198 public:
199 static bool
200 CreateActorForSameProcess(CreateCallback* aCallback);
202 static bool
203 IsOnBackgroundThread()
205 return PR_GetCurrentThread() == sBackgroundPRThread;
208 static void
209 AssertIsOnBackgroundThread()
211 THREADSAFETY_ASSERT(IsOnBackgroundThread());
214 NS_INLINE_DECL_REFCOUNTING(ParentImpl)
216 void
217 Destroy();
219 private:
220 // Forwarded from BackgroundParent.
221 static bool
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);
234 static bool
235 CreateBackgroundThread();
237 static void
238 ShutdownBackgroundThread();
240 static void
241 ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
243 // For same-process actors.
244 ParentImpl()
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);
265 ~ParentImpl()
267 AssertIsInMainProcess();
268 AssertIsOnMainThread();
269 MOZ_ASSERT(!mContent);
270 MOZ_ASSERT(!mTransport);
273 void
274 MainThreadActorDestroy();
276 void
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;
296 virtual void
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;
348 #ifdef RELEASE_BUILD
349 DebugOnly<nsIThread*> mBoundThread;
350 #else
351 nsIThread* mBoundThread;
352 #endif
354 DebugOnly<bool> mActorDestroyed;
356 public:
357 static bool
358 OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
360 static void
361 Shutdown();
363 void
364 AssertIsOnBoundThread()
366 THREADSAFETY_ASSERT(mBoundThread);
368 #ifdef RELEASE_BUILD
369 DebugOnly<bool> current;
370 #else
371 bool current;
372 #endif
373 THREADSAFETY_ASSERT(
374 NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
375 THREADSAFETY_ASSERT(current);
378 void
379 AssertActorDestroyed()
381 MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
384 ChildImpl()
385 : mBoundThread(nullptr)
386 , mActorDestroyed(false)
388 AssertIsOnMainThread();
391 NS_INLINE_DECL_REFCOUNTING(ChildImpl)
393 private:
394 // Forwarded from BackgroundChild.
395 static void
396 Startup();
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.
407 static bool
408 GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
410 // Forwarded from BackgroundChild.
411 static void
412 CloseForCurrentThread();
414 // Forwarded from BackgroundChildImpl.
415 static BackgroundChildImpl::ThreadLocal*
416 GetThreadLocalForCurrentThread();
418 static void
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()) {
431 ChildImpl* actor;
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;
443 static void
444 DispatchFailureCallback(nsIEventTarget* aEventTarget);
446 // This class is reference counted.
447 ~ChildImpl()
449 AssertActorDestroyed();
452 void
453 SetBoundThread()
455 THREADSAFETY_ASSERT(!mBoundThread);
457 #if defined(DEBUG) || !defined(RELEASE_BUILD)
458 mBoundThread = NS_GetCurrentThread();
459 #endif
461 THREADSAFETY_ASSERT(mBoundThread);
464 // Only called by IPDL.
465 virtual void
466 ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
468 static already_AddRefed<nsIIPCBackgroundChildCreateCallback>
469 GetNextCallback();
472 // -----------------------------------------------------------------------------
473 // ParentImpl Helper Declarations
474 // -----------------------------------------------------------------------------
476 class ParentImpl::ShutdownObserver MOZ_FINAL : public nsIObserver
478 public:
479 ShutdownObserver()
481 AssertIsOnMainThread();
484 NS_DECL_ISUPPORTS
485 NS_DECL_NSIOBSERVER
487 private:
488 ~ShutdownObserver()
490 AssertIsOnMainThread();
494 class ParentImpl::RequestMessageLoopRunnable MOZ_FINAL :
495 public nsRunnable
497 nsCOMPtr<nsIThread> mTargetThread;
498 MessageLoop* mMessageLoop;
500 public:
501 explicit RequestMessageLoopRunnable(nsIThread* aTargetThread)
502 : mTargetThread(aTargetThread), mMessageLoop(nullptr)
504 AssertIsInMainProcess();
505 AssertIsOnMainThread();
506 MOZ_ASSERT(aTargetThread);
509 NS_DECL_ISUPPORTS_INHERITED
511 private:
512 ~RequestMessageLoopRunnable()
515 NS_DECL_NSIRUNNABLE
518 class ParentImpl::ShutdownBackgroundThreadRunnable MOZ_FINAL : public nsRunnable
520 public:
521 ShutdownBackgroundThreadRunnable()
523 AssertIsInMainProcess();
524 AssertIsOnMainThread();
527 NS_DECL_ISUPPORTS_INHERITED
529 private:
530 ~ShutdownBackgroundThreadRunnable()
533 NS_DECL_NSIRUNNABLE
536 class ParentImpl::ForceCloseBackgroundActorsRunnable MOZ_FINAL : public nsRunnable
538 nsTArray<ParentImpl*>* mActorArray;
540 public:
541 explicit ForceCloseBackgroundActorsRunnable(nsTArray<ParentImpl*>* aActorArray)
542 : mActorArray(aActorArray)
544 AssertIsInMainProcess();
545 AssertIsOnMainThread();
546 MOZ_ASSERT(aActorArray);
549 NS_DECL_ISUPPORTS_INHERITED
551 private:
552 ~ForceCloseBackgroundActorsRunnable()
555 NS_DECL_NSIRUNNABLE
558 class ParentImpl::CreateCallbackRunnable MOZ_FINAL : public nsRunnable
560 nsRefPtr<CreateCallback> mCallback;
562 public:
563 explicit CreateCallbackRunnable(CreateCallback* aCallback)
564 : mCallback(aCallback)
566 AssertIsInMainProcess();
567 AssertIsOnMainThread();
568 MOZ_ASSERT(aCallback);
571 NS_DECL_ISUPPORTS_INHERITED
573 private:
574 ~CreateCallbackRunnable()
577 NS_DECL_NSIRUNNABLE
580 class ParentImpl::ConnectActorRunnable MOZ_FINAL : public nsRunnable
582 nsRefPtr<ParentImpl> mActor;
583 Transport* mTransport;
584 ProcessHandle mProcessHandle;
585 nsTArray<ParentImpl*>* mLiveActorArray;
587 public:
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();
597 MOZ_ASSERT(aActor);
598 MOZ_ASSERT(aTransport);
599 MOZ_ASSERT(aLiveActorArray);
602 NS_DECL_ISUPPORTS_INHERITED
604 private:
605 ~ConnectActorRunnable()
607 AssertIsInMainProcess();
610 NS_DECL_NSIRUNNABLE
613 class NS_NO_VTABLE ParentImpl::CreateCallback
615 public:
616 NS_INLINE_DECL_REFCOUNTING(CreateCallback)
618 virtual void
619 Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop) = 0;
621 virtual void
622 Failure() = 0;
624 protected:
625 virtual ~CreateCallback()
629 // -----------------------------------------------------------------------------
630 // ChildImpl Helper Declarations
631 // -----------------------------------------------------------------------------
633 class ChildImpl::ShutdownObserver MOZ_FINAL : public nsIObserver
635 public:
636 ShutdownObserver()
638 AssertIsOnMainThread();
641 NS_DECL_ISUPPORTS
642 NS_DECL_NSIOBSERVER
644 private:
645 ~ShutdownObserver()
647 AssertIsOnMainThread();
651 class ChildImpl::CreateActorRunnable MOZ_FINAL : public nsRunnable
653 nsCOMPtr<nsIEventTarget> mEventTarget;
655 public:
656 CreateActorRunnable()
657 : mEventTarget(NS_GetCurrentThread())
659 MOZ_ASSERT(mEventTarget);
662 NS_DECL_ISUPPORTS_INHERITED
664 private:
665 ~CreateActorRunnable()
668 NS_DECL_NSIRUNNABLE
671 class ChildImpl::ParentCreateCallback MOZ_FINAL :
672 public ParentImpl::CreateCallback
674 nsCOMPtr<nsIEventTarget> mEventTarget;
676 public:
677 explicit ParentCreateCallback(nsIEventTarget* aEventTarget)
678 : mEventTarget(aEventTarget)
680 AssertIsInMainProcess();
681 AssertIsOnMainThread();
682 MOZ_ASSERT(aEventTarget);
685 private:
686 ~ParentCreateCallback()
689 virtual void
690 Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop)
691 MOZ_OVERRIDE;
693 virtual void
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
701 public:
702 AlreadyCreatedCallbackRunnable()
704 // May be created on any thread!
707 NS_DECL_ISUPPORTS_INHERITED
709 protected:
710 virtual ~AlreadyCreatedCallbackRunnable()
713 NS_DECL_NSIRUNNABLE
714 NS_DECL_NSICANCELABLERUNNABLE
717 class ChildImpl::FailedCreateCallbackRunnable MOZ_FINAL : public nsRunnable
719 public:
720 FailedCreateCallbackRunnable()
722 // May be created on any thread!
725 NS_DECL_ISUPPORTS_INHERITED
727 protected:
728 virtual ~FailedCreateCallbackRunnable()
731 NS_DECL_NSIRUNNABLE
734 class ChildImpl::OpenChildProcessActorRunnable MOZ_FINAL : public nsRunnable
736 nsRefPtr<ChildImpl> mActor;
737 nsAutoPtr<Transport> mTransport;
738 ProcessHandle mProcessHandle;
740 public:
741 OpenChildProcessActorRunnable(already_AddRefed<ChildImpl>&& aActor,
742 Transport* aTransport,
743 ProcessHandle aProcessHandle)
744 : mActor(aActor), mTransport(aTransport),
745 mProcessHandle(aProcessHandle)
747 AssertIsOnMainThread();
748 MOZ_ASSERT(mActor);
749 MOZ_ASSERT(aTransport);
752 NS_DECL_ISUPPORTS_INHERITED
754 private:
755 ~OpenChildProcessActorRunnable()
757 if (mTransport) {
758 CRASH_IN_CHILD_PROCESS("Leaking transport!");
759 unused << mTransport.forget();
763 NS_DECL_NSIRUNNABLE
766 class ChildImpl::OpenMainProcessActorRunnable MOZ_FINAL : public nsRunnable
768 nsRefPtr<ChildImpl> mActor;
769 nsRefPtr<ParentImpl> mParentActor;
770 MessageLoop* mParentMessageLoop;
772 public:
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
786 private:
787 ~OpenMainProcessActorRunnable()
790 NS_DECL_NSIRUNNABLE
793 } // anonymous namespace
795 namespace mozilla {
796 namespace ipc {
798 bool
799 IsOnBackgroundThread()
801 return ParentImpl::IsOnBackgroundThread();
804 #ifdef DEBUG
806 void
807 AssertIsOnBackgroundThread()
809 ParentImpl::AssertIsOnBackgroundThread();
812 #endif // DEBUG
814 } // namespace ipc
815 } // namespace mozilla
817 // -----------------------------------------------------------------------------
818 // BackgroundParent Public Methods
819 // -----------------------------------------------------------------------------
821 // static
822 bool
823 BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
825 return ParentImpl::IsOtherProcessActor(aBackgroundActor);
828 // static
829 already_AddRefed<ContentParent>
830 BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor)
832 return ParentImpl::GetContentParent(aBackgroundActor);
835 // static
836 PBackgroundParent*
837 BackgroundParent::Alloc(ContentParent* aContent,
838 Transport* aTransport,
839 ProcessId aOtherProcess)
841 return ParentImpl::Alloc(aContent, aTransport, aOtherProcess);
844 // -----------------------------------------------------------------------------
845 // BackgroundChild Public Methods
846 // -----------------------------------------------------------------------------
848 // static
849 void
850 BackgroundChild::Startup()
852 ChildImpl::Startup();
855 // static
856 PBackgroundChild*
857 BackgroundChild::Alloc(Transport* aTransport, ProcessId aOtherProcess)
859 return ChildImpl::Alloc(aTransport, aOtherProcess);
862 // static
863 PBackgroundChild*
864 BackgroundChild::GetForCurrentThread()
866 return ChildImpl::GetForCurrentThread();
869 // static
870 bool
871 BackgroundChild::GetOrCreateForCurrentThread(
872 nsIIPCBackgroundChildCreateCallback* aCallback)
874 return ChildImpl::GetOrCreateForCurrentThread(aCallback);
877 // static
878 void
879 BackgroundChild::CloseForCurrentThread()
881 ChildImpl::CloseForCurrentThread();
884 // -----------------------------------------------------------------------------
885 // BackgroundChildImpl Public Methods
886 // -----------------------------------------------------------------------------
888 // static
889 BackgroundChildImpl::ThreadLocal*
890 BackgroundChildImpl::GetThreadLocalForCurrentThread()
892 return ChildImpl::GetThreadLocalForCurrentThread();
895 // -----------------------------------------------------------------------------
896 // ParentImpl Static Members
897 // -----------------------------------------------------------------------------
899 const ParentImpl::ProcessHandle ParentImpl::kInvalidProcessHandle =
900 #ifdef XP_WIN
901 ProcessHandle(INVALID_HANDLE_VALUE);
902 #else
903 ProcessHandle(-1);
904 #endif
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 // -----------------------------------------------------------------------------
939 // static
940 bool
941 ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
943 AssertIsOnBackgroundThread();
944 MOZ_ASSERT(aBackgroundActor);
946 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
949 // static
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!");
959 return nullptr;
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());
979 // static
980 PBackgroundParent*
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?
992 return nullptr;
995 if (!sBackgroundThread && !CreateBackgroundThread()) {
996 NS_WARNING("Failed to create background thread!");
997 return nullptr;
1000 MOZ_ASSERT(sLiveActorsForBackgroundThread);
1002 sLiveActorCount++;
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);
1015 sLiveActorCount--;
1017 if (!sLiveActorCount) {
1018 ShutdownBackgroundThread();
1021 return nullptr;
1024 return actor;
1027 // static
1028 bool
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!");
1037 return false;
1040 MOZ_ASSERT(!sShutdownHasStarted);
1042 sLiveActorCount++;
1044 if (sBackgroundThreadMessageLoop) {
1045 nsCOMPtr<nsIRunnable> callbackRunnable =
1046 new CreateCallbackRunnable(aCallback);
1047 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(callbackRunnable)));
1048 return true;
1051 if (!sPendingCallbacks) {
1052 sPendingCallbacks = new nsTArray<nsRefPtr<CreateCallback>>();
1055 sPendingCallbacks->AppendElement(aCallback);
1056 return true;
1059 // static
1060 bool
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 "
1070 "already begun!");
1071 return false;
1074 nsCOMPtr<nsITimer> newShutdownTimer;
1076 if (!sShutdownTimer) {
1077 nsresult rv;
1078 newShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1079 if (NS_WARN_IF(NS_FAILED(rv))) {
1080 return false;
1084 if (!sShutdownObserverRegistered) {
1085 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1086 if (NS_WARN_IF(!obs)) {
1087 return false;
1090 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1092 nsresult rv =
1093 obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1094 if (NS_WARN_IF(NS_FAILED(rv))) {
1095 return false;
1098 sShutdownObserverRegistered = true;
1101 nsCOMPtr<nsIThread> thread;
1102 if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread)))) {
1103 NS_WARNING("NS_NewNamedThread failed!");
1104 return false;
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!");
1111 return false;
1114 sBackgroundThread = thread;
1115 sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
1117 if (!sShutdownTimer) {
1118 MOZ_ASSERT(newShutdownTimer);
1119 sShutdownTimer = newShutdownTimer;
1122 return true;
1125 // static
1126 void
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()));
1207 // static
1208 void
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
1220 // finished.
1221 sLiveActorCount++;
1223 nsCOMPtr<nsIRunnable> forceCloseRunnable =
1224 new ForceCloseBackgroundActorsRunnable(closure->mLiveActors);
1225 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(closure->mThread->Dispatch(forceCloseRunnable,
1226 NS_DISPATCH_NORMAL)));
1229 void
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)));
1243 void
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);
1253 if (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);
1262 #ifdef DEBUG
1263 SetOtherProcess(kInvalidProcessHandle);
1264 #endif
1267 mContent = nullptr;
1269 MOZ_ASSERT(sLiveActorCount);
1270 sLiveActorCount--;
1272 if (!sLiveActorCount) {
1273 ShutdownBackgroundThread();
1276 // This may be the last reference!
1277 Release();
1280 IToplevelProtocol*
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) {
1292 continue;
1295 Transport* transport = OpenDescriptor(aFds[i].fd(),
1296 Transport::MODE_SERVER);
1297 if (!transport) {
1298 NS_WARNING("Failed to open transport!");
1299 break;
1302 PBackgroundParent* clonedActor =
1303 Alloc(mContent, transport, base::GetProcId(aPeerProcess));
1304 MOZ_ASSERT(clonedActor);
1306 clonedActor->CloneManagees(this, aCtx);
1307 clonedActor->SetTransport(transport);
1309 return clonedActor;
1312 return nullptr;
1315 void
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)
1348 NS_IMETHODIMP
1349 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject,
1350 const char* aTopic,
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();
1366 return NS_OK;
1369 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::RequestMessageLoopRunnable,
1370 nsRunnable)
1372 NS_IMETHODIMP
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())) {
1383 return NS_OK;
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!");
1404 return NS_OK;
1407 char stackBaseGuess;
1408 profiler_register_thread("IPDL Background", &stackBaseGuess);
1410 #ifdef DEBUG
1412 bool correctThread;
1413 MOZ_ASSERT(NS_SUCCEEDED(mTargetThread->IsOnCurrentThread(&correctThread)));
1414 MOZ_ASSERT(correctThread);
1416 #endif
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;
1434 return NS_OK;
1437 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ShutdownBackgroundThreadRunnable,
1438 nsRunnable)
1440 NS_IMETHODIMP
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();
1452 return NS_OK;
1455 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ForceCloseBackgroundActorsRunnable,
1456 nsRunnable)
1458 NS_IMETHODIMP
1459 ParentImpl::ForceCloseBackgroundActorsRunnable::Run()
1461 AssertIsInMainProcess();
1462 MOZ_ASSERT(mActorArray);
1464 if (NS_IsMainThread()) {
1465 MOZ_ASSERT(sLiveActorCount);
1466 sLiveActorCount--;
1467 return NS_OK;
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)));
1483 return NS_OK;
1486 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::CreateCallbackRunnable, nsRunnable)
1488 NS_IMETHODIMP
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);
1503 return NS_OK;
1506 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ConnectActorRunnable, nsRunnable)
1508 NS_IMETHODIMP
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.
1516 ParentImpl* actor;
1517 mActor.forget(&actor);
1519 if (!actor->Open(mTransport, mProcessHandle, XRE_GetIOMessageLoop(),
1520 ParentSide)) {
1521 actor->Destroy();
1522 return NS_ERROR_FAILURE;
1525 actor->SetLiveActorArray(mLiveActorArray);
1527 return NS_OK;
1530 // -----------------------------------------------------------------------------
1531 // ChildImpl Implementation
1532 // -----------------------------------------------------------------------------
1534 // static
1535 void
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!");
1544 PRStatus status =
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();
1555 nsresult rv =
1556 observerService->AddObserver(observer,
1557 NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
1558 false);
1559 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1562 // static
1563 void
1564 ChildImpl::Shutdown()
1566 AssertIsOnMainThread();
1568 if (sShutdownHasStarted) {
1569 MOZ_ASSERT_IF(sThreadLocalIndex != kBadThreadLocalIndex,
1570 !PR_GetThreadPrivate(sThreadLocalIndex));
1571 return;
1574 sShutdownHasStarted = true;
1576 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1578 DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
1579 MOZ_ASSERT(status == PR_SUCCESS);
1582 // static
1583 PBackgroundChild*
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,
1608 processHandle);
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.
1615 return weakActor;
1618 // static
1619 PBackgroundChild*
1620 ChildImpl::GetForCurrentThread()
1622 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1624 auto threadLocalInfo =
1625 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1627 if (!threadLocalInfo) {
1628 return nullptr;
1631 return threadLocalInfo->mActor;
1634 // static
1635 bool
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);
1650 } else {
1651 nsAutoPtr<ThreadLocalInfo> newInfo(new ThreadLocalInfo(aCallback));
1653 if (PR_SetThreadPrivate(sThreadLocalIndex, newInfo) != PR_SUCCESS) {
1654 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
1655 return false;
1658 created = true;
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)));
1668 return true;
1671 if (!created) {
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.
1675 return true;
1678 if (NS_IsMainThread()) {
1679 if (NS_WARN_IF(!OpenProtocolOnMainThread(NS_GetCurrentThread()))) {
1680 return false;
1683 return true;
1686 nsRefPtr<CreateActorRunnable> runnable = new CreateActorRunnable();
1687 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
1688 CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
1689 return false;
1692 return true;
1695 // static
1696 void
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);
1722 // static
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) {
1733 return nullptr;
1736 if (!threadLocalInfo->mConsumerThreadLocal) {
1737 threadLocalInfo->mConsumerThreadLocal =
1738 new BackgroundChildImpl::ThreadLocal();
1741 return threadLocalInfo->mConsumerThreadLocal;
1744 // static
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()) {
1755 return nullptr;
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)
1769 NS_IMETHODIMP
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
1781 // and return.
1782 if (NS_WARN_IF(!actor)) {
1783 return NS_OK;
1786 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
1787 ChildImpl::GetNextCallback();
1788 while (callback) {
1789 callback->ActorCreated(actor);
1790 callback = ChildImpl::GetNextCallback();
1793 return NS_OK;
1796 NS_IMETHODIMP
1797 ChildImpl::AlreadyCreatedCallbackRunnable::Cancel()
1799 // These are IPC infrastructure objects and need to run unconditionally.
1800 Run();
1801 return NS_OK;
1804 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::FailedCreateCallbackRunnable,
1805 nsRunnable);
1807 NS_IMETHODIMP
1808 ChildImpl::FailedCreateCallbackRunnable::Run()
1810 // May run on any thread!
1812 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
1813 ChildImpl::GetNextCallback();
1814 while (callback) {
1815 callback->ActorFailed();
1816 callback = ChildImpl::GetNextCallback();
1819 return NS_OK;
1822 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenChildProcessActorRunnable,
1823 nsRunnable);
1825 NS_IMETHODIMP
1826 ChildImpl::OpenChildProcessActorRunnable::Run()
1828 // May be run on any thread!
1830 AssertIsInChildProcess();
1831 MOZ_ASSERT(mActor);
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 "
1838 "actor!");
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!");
1847 while (callback) {
1848 callback->ActorFailed();
1849 callback = ChildImpl::GetNextCallback();
1852 return NS_OK;
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();
1867 while (callback) {
1868 callback->ActorCreated(actor);
1869 callback = ChildImpl::GetNextCallback();
1872 return NS_OK;
1875 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenMainProcessActorRunnable,
1876 nsRunnable);
1878 NS_IMETHODIMP
1879 ChildImpl::OpenMainProcessActorRunnable::Run()
1881 // May run on any thread!
1883 AssertIsInMainProcess();
1884 MOZ_ASSERT(mActor);
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 "
1892 "actor!");
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();
1908 while (callback) {
1909 callback->ActorFailed();
1910 callback = ChildImpl::GetNextCallback();
1913 return NS_OK;
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();
1930 while (callback) {
1931 callback->ActorCreated(childActor);
1932 callback = ChildImpl::GetNextCallback();
1935 return NS_OK;
1938 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateActorRunnable, nsRunnable)
1940 NS_IMETHODIMP
1941 ChildImpl::CreateActorRunnable::Run()
1943 AssertIsOnMainThread();
1945 if (!OpenProtocolOnMainThread(mEventTarget)) {
1946 NS_WARNING("OpenProtocolOnMainThread failed!");
1947 return NS_ERROR_FAILURE;
1950 return NS_OK;
1953 void
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!");
1979 void
1980 ChildImpl::ParentCreateCallback::Failure()
1982 AssertIsInMainProcess();
1983 AssertIsOnMainThread();
1984 MOZ_ASSERT(mEventTarget);
1986 nsCOMPtr<nsIEventTarget> target;
1987 mEventTarget.swap(target);
1989 DispatchFailureCallback(target);
1992 // static
1993 bool
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);
2011 return false;
2014 return true;
2017 ContentChild* content = ContentChild::GetSingleton();
2018 MOZ_ASSERT(content);
2020 if (!PBackground::Open(content)) {
2021 MOZ_CRASH("Failed to create top level actor!");
2022 return false;
2025 if (!sPendingTargets) {
2026 sPendingTargets = new nsTArray<nsCOMPtr<nsIEventTarget>>(1);
2027 ClearOnShutdown(&sPendingTargets);
2030 sPendingTargets->AppendElement(aEventTarget);
2032 return true;
2035 // static
2036 void
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!");
2047 void
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)
2060 NS_IMETHODIMP
2061 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject,
2062 const char* aTopic,
2063 const char16_t* aData)
2065 AssertIsOnMainThread();
2066 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
2068 ChildImpl::Shutdown();
2070 return NS_OK;