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