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