Bug 1834537 - Part 6: Simplify GCRuntime::checkAllocatorState a little r=sfink
[gecko.git] / ipc / glue / BackgroundImpl.cpp
blob420f047f42e0377a0a8b1e56d8b06049a07d5edf
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 "MainThreadUtils.h"
13 #include "base/process_util.h"
14 #include "base/task.h"
15 #include "FileDescriptor.h"
16 #include "GeckoProfiler.h"
17 #include "InputStreamUtils.h"
18 #include "mozilla/Assertions.h"
19 #include "mozilla/Atomics.h"
20 #include "mozilla/ClearOnShutdown.h"
21 #include "mozilla/DebugOnly.h"
22 #include "mozilla/MozPromise.h"
23 #include "mozilla/Services.h"
24 #include "mozilla/SpinEventLoopUntil.h"
25 #include "mozilla/StaticPtr.h"
26 #include "mozilla/Unused.h"
27 #include "mozilla/dom/ContentChild.h"
28 #include "mozilla/dom/ContentParent.h"
29 #include "mozilla/dom/File.h"
30 #include "mozilla/dom/WorkerPrivate.h"
31 #include "mozilla/dom/WorkerRef.h"
32 #include "mozilla/ipc/BackgroundStarterChild.h"
33 #include "mozilla/ipc/BackgroundStarterParent.h"
34 #include "mozilla/ipc/Endpoint.h"
35 #include "mozilla/ipc/PBackgroundStarter.h"
36 #include "mozilla/ipc/ProtocolTypes.h"
37 #include "mozilla/net/SocketProcessChild.h"
38 #include "mozilla/net/SocketProcessBridgeChild.h"
39 #include "nsCOMPtr.h"
40 #include "nsIEventTarget.h"
41 #include "nsIObserver.h"
42 #include "nsIObserverService.h"
43 #include "nsIRunnable.h"
44 #include "nsISupportsImpl.h"
45 #include "nsIThread.h"
46 #include "nsITimer.h"
47 #include "nsTArray.h"
48 #include "nsThreadUtils.h"
49 #include "nsTraceRefcnt.h"
50 #include "nsXULAppAPI.h"
51 #include "nsXPCOMPrivate.h"
52 #include "prthread.h"
54 #include <functional>
56 #ifdef RELEASE_OR_BETA
57 # define THREADSAFETY_ASSERT MOZ_ASSERT
58 #else
59 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
60 #endif
62 #define CRASH_IN_CHILD_PROCESS(_msg) \
63 do { \
64 if (XRE_IsParentProcess()) { \
65 MOZ_ASSERT(false, _msg); \
66 } else { \
67 MOZ_CRASH(_msg); \
68 } \
69 } while (0)
71 using namespace mozilla;
72 using namespace mozilla::dom;
73 using namespace mozilla::ipc;
74 using namespace mozilla::net;
76 namespace {
78 class ChildImpl;
80 // -----------------------------------------------------------------------------
81 // Utility Functions
82 // -----------------------------------------------------------------------------
84 void AssertIsInMainOrSocketProcess() {
85 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
88 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
90 // -----------------------------------------------------------------------------
91 // ParentImpl Declaration
92 // -----------------------------------------------------------------------------
94 class ParentImpl final : public BackgroundParentImpl {
95 friend class ChildImpl;
96 friend class mozilla::ipc::BackgroundParent;
97 friend class mozilla::ipc::BackgroundStarterParent;
99 private:
100 class ShutdownObserver;
102 struct MOZ_STACK_CLASS TimerCallbackClosure {
103 nsIThread* mThread;
104 nsTArray<IToplevelProtocol*>* mLiveActors;
106 TimerCallbackClosure(nsIThread* aThread,
107 nsTArray<IToplevelProtocol*>* aLiveActors)
108 : mThread(aThread), mLiveActors(aLiveActors) {
109 AssertIsInMainOrSocketProcess();
110 AssertIsOnMainThread();
111 MOZ_ASSERT(aThread);
112 MOZ_ASSERT(aLiveActors);
116 // The length of time we will wait at shutdown for all actors to clean
117 // themselves up before forcing them to be destroyed.
118 static const uint32_t kShutdownTimerDelayMS = 10000;
120 // This is only modified on the main thread. It is null if the thread does not
121 // exist or is shutting down.
122 static StaticRefPtr<nsIThread> sBackgroundThread;
124 // This is created and destroyed on the main thread but only modified on the
125 // background thread. It is specific to each instance of sBackgroundThread.
126 static nsTArray<IToplevelProtocol*>* sLiveActorsForBackgroundThread;
128 // This is only modified on the main thread.
129 static StaticRefPtr<nsITimer> sShutdownTimer;
131 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
132 // work during shutdown.
133 static Atomic<PRThread*> sBackgroundPRThread;
135 // Maintains a count of live actors so that the background thread can be shut
136 // down when it is no longer needed.
137 // May be incremented on either the background thread (by an existing actor)
138 // or on the main thread, but must be decremented on the main thread.
139 static Atomic<uint64_t> sLiveActorCount;
141 // This is only modified on the main thread. It is true after the shutdown
142 // observer is registered and is never unset thereafter.
143 static bool sShutdownObserverRegistered;
145 // This is only modified on the main thread. It prevents us from trying to
146 // create the background thread after application shutdown has started.
147 static bool sShutdownHasStarted;
149 // null if this is a same-process or socket process actor.
150 const RefPtr<ThreadsafeContentParentHandle> mContent;
152 // Set when the actor is opened successfully and used to handle shutdown
153 // hangs. Only touched on the background thread.
154 nsTArray<IToplevelProtocol*>* mLiveActorArray;
156 // Set at construction to indicate whether this parent actor corresponds to a
157 // child actor in another process or to a child actor from a different thread
158 // in the same process.
159 const bool mIsOtherProcessActor;
161 // Set after ActorDestroy has been called. Only touched on the background
162 // thread.
163 bool mActorDestroyed;
165 public:
166 static bool IsOnBackgroundThread() {
167 return PR_GetCurrentThread() == sBackgroundPRThread;
170 static void AssertIsOnBackgroundThread() {
171 THREADSAFETY_ASSERT(IsOnBackgroundThread());
174 // `ParentImpl` instances need to be deleted on the main thread, despite IPC
175 // controlling them on a background thread. Use `_WITH_DELETE_ON_MAIN_THREAD`
176 // to force destruction to occur on the desired thread.
177 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(ParentImpl,
178 override)
180 void Destroy();
182 private:
183 // Forwarded from BackgroundParent.
184 static bool IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
186 // Forwarded from BackgroundParent.
187 static ThreadsafeContentParentHandle* GetContentParentHandle(
188 PBackgroundParent* aBackgroundActor);
190 // Forwarded from BackgroundParent.
191 static uint64_t GetChildID(PBackgroundParent* aBackgroundActor);
193 // Forwarded from BackgroundParent.
194 static bool AllocStarter(ContentParent* aContent,
195 Endpoint<PBackgroundStarterParent>&& aEndpoint,
196 bool aCrossProcess = true);
198 static bool CreateBackgroundThread();
200 static void ShutdownBackgroundThread();
202 static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
204 // NOTE: ParentImpl could be used in 4 cases below.
205 // 1. Within the parent process.
206 // 2. Between parent process and content process.
207 // 3. Between socket process and content process.
208 // 4. Between parent process and socket process.
209 // |aContent| should be not null for case 2. For cases 1, 3 and 4, it's null.
210 explicit ParentImpl(ThreadsafeContentParentHandle* aContent,
211 bool aIsOtherProcessActor)
212 : mContent(aContent),
213 mLiveActorArray(nullptr),
214 mIsOtherProcessActor(aIsOtherProcessActor),
215 mActorDestroyed(false) {
216 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
217 MOZ_ASSERT_IF(!aIsOtherProcessActor, XRE_IsParentProcess());
220 ~ParentImpl() {
221 AssertIsInMainOrSocketProcess();
222 AssertIsOnMainThread();
225 void MainThreadActorDestroy();
227 void SetLiveActorArray(nsTArray<IToplevelProtocol*>* aLiveActorArray) {
228 AssertIsInMainOrSocketProcess();
229 AssertIsOnBackgroundThread();
230 MOZ_ASSERT(aLiveActorArray);
231 MOZ_ASSERT(!aLiveActorArray->Contains(this));
232 MOZ_ASSERT(!mLiveActorArray);
233 MOZ_ASSERT(mIsOtherProcessActor);
235 mLiveActorArray = aLiveActorArray;
236 mLiveActorArray->AppendElement(this);
239 // These methods are only called by IPDL.
240 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
243 // -----------------------------------------------------------------------------
244 // ChildImpl Declaration
245 // -----------------------------------------------------------------------------
247 class ChildImpl final : public BackgroundChildImpl {
248 friend class mozilla::ipc::BackgroundChild;
249 friend class mozilla::ipc::BackgroundChildImpl;
250 friend class mozilla::ipc::BackgroundStarterChild;
252 typedef base::ProcessId ProcessId;
254 class ShutdownObserver;
256 public:
257 struct ThreadLocalInfo {
258 ThreadLocalInfo()
259 #ifdef DEBUG
260 : mClosed(false)
261 #endif
265 RefPtr<ChildImpl> mActor;
266 UniquePtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
267 #ifdef DEBUG
268 bool mClosed;
269 #endif
272 private:
273 // A thread-local index that is not valid.
274 static constexpr unsigned int kBadThreadLocalIndex =
275 static_cast<unsigned int>(-1);
277 // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
278 // also provides some common functions for creating PBackground IPC actor.
279 class ThreadInfoWrapper final {
280 friend class ChildImpl;
282 public:
283 using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
284 nsIEventTarget*, ChildImpl**);
286 ThreadInfoWrapper() = default;
288 void Startup() {
289 MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
290 "ThreadInfoWrapper::Startup() called more than once!");
292 PRStatus status =
293 PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
294 MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
295 "PR_NewThreadPrivateIndex failed!");
297 MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
300 void Shutdown() {
301 if (sShutdownHasStarted) {
302 MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
303 !PR_GetThreadPrivate(mThreadLocalIndex));
304 return;
307 if (mThreadLocalIndex == kBadThreadLocalIndex) {
308 return;
311 RefPtr<BackgroundStarterChild> starter;
313 auto lock = mStarter.Lock();
314 starter = lock->forget();
316 if (starter) {
317 CloseStarter(starter);
320 ThreadLocalInfo* threadLocalInfo;
321 #ifdef DEBUG
322 threadLocalInfo =
323 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
324 MOZ_ASSERT(!threadLocalInfo);
325 #endif
327 threadLocalInfo = mMainThreadInfo;
328 if (threadLocalInfo) {
329 #ifdef DEBUG
330 MOZ_ASSERT(!threadLocalInfo->mClosed);
331 threadLocalInfo->mClosed = true;
332 #endif
334 ThreadLocalDestructor(threadLocalInfo);
335 mMainThreadInfo = nullptr;
339 template <typename Actor>
340 void InitStarter(Actor* aActor) {
341 AssertIsOnMainThread();
343 // Create a pair of endpoints and send them to the other process.
344 Endpoint<PBackgroundStarterParent> parent;
345 Endpoint<PBackgroundStarterChild> child;
346 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
347 aActor->OtherPid(), base::GetCurrentProcId(), &parent, &child));
348 MOZ_ALWAYS_TRUE(aActor->SendInitBackground(std::move(parent)));
350 InitStarter(std::move(child));
353 void InitStarter(Endpoint<PBackgroundStarterChild>&& aEndpoint) {
354 AssertIsOnMainThread();
356 base::ProcessId otherPid = aEndpoint.OtherPid();
358 nsCOMPtr<nsISerialEventTarget> taskQueue;
359 MOZ_ALWAYS_SUCCEEDS(NS_CreateBackgroundTaskQueue(
360 "PBackgroundStarter Queue", getter_AddRefs(taskQueue)));
362 RefPtr<BackgroundStarterChild> starter =
363 new BackgroundStarterChild(otherPid, taskQueue);
365 taskQueue->Dispatch(NS_NewRunnableFunction(
366 "PBackgroundStarterChild Init",
367 [starter, endpoint = std::move(aEndpoint)]() mutable {
368 MOZ_ALWAYS_TRUE(endpoint.Bind(starter));
369 }));
371 // Swap in the newly initialized `BackgroundStarterChild`, and close the
372 // previous one if we're replacing an existing PBackgroundStarterChild
373 // instance.
374 RefPtr<BackgroundStarterChild> prevStarter;
376 auto lock = mStarter.Lock();
377 prevStarter = lock->forget();
378 *lock = starter.forget();
380 if (prevStarter) {
381 CloseStarter(prevStarter);
385 void CloseForCurrentThread() {
386 MOZ_ASSERT(!NS_IsMainThread());
388 if (mThreadLocalIndex == kBadThreadLocalIndex) {
389 return;
392 auto* threadLocalInfo =
393 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
395 if (!threadLocalInfo) {
396 return;
399 #ifdef DEBUG
400 MOZ_ASSERT(!threadLocalInfo->mClosed);
401 threadLocalInfo->mClosed = true;
402 #endif
404 // Clearing the thread local will synchronously close the actor.
405 DebugOnly<PRStatus> status =
406 PR_SetThreadPrivate(mThreadLocalIndex, nullptr);
407 MOZ_ASSERT(status == PR_SUCCESS);
410 PBackgroundChild* GetOrCreateForCurrentThread() {
411 // Processes can be told to do final CC's during shutdown even though
412 // they never finished starting (and thus call this), because they
413 // hadn't gotten far enough to call Startup() before shutdown began.
414 if (mThreadLocalIndex == kBadThreadLocalIndex) {
415 NS_ERROR("BackgroundChild::Startup() was never called");
416 return nullptr;
418 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
419 return nullptr;
422 auto* threadLocalInfo = NS_IsMainThread()
423 ? mMainThreadInfo
424 : static_cast<ThreadLocalInfo*>(
425 PR_GetThreadPrivate(mThreadLocalIndex));
427 if (!threadLocalInfo) {
428 auto newInfo = MakeUnique<ThreadLocalInfo>();
430 if (NS_IsMainThread()) {
431 mMainThreadInfo = newInfo.get();
432 } else {
433 if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
434 PR_SUCCESS) {
435 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
436 return nullptr;
440 threadLocalInfo = newInfo.release();
443 if (threadLocalInfo->mActor) {
444 return threadLocalInfo->mActor;
447 RefPtr<BackgroundStarterChild> starter;
449 auto lock = mStarter.Lock();
450 starter = *lock;
452 if (!starter) {
453 CRASH_IN_CHILD_PROCESS("No BackgroundStarterChild");
454 return nullptr;
457 Endpoint<PBackgroundParent> parent;
458 Endpoint<PBackgroundChild> child;
459 nsresult rv;
460 rv = PBackground::CreateEndpoints(
461 starter->mOtherPid, base::GetCurrentProcId(), &parent, &child);
462 if (NS_FAILED(rv)) {
463 NS_WARNING("Failed to create top level actor!");
464 return nullptr;
467 RefPtr<ChildImpl> strongActor = new ChildImpl();
468 if (!child.Bind(strongActor)) {
469 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
470 return nullptr;
472 strongActor->SetActorAlive();
473 threadLocalInfo->mActor = strongActor;
475 // Dispatch to the background task queue to create the relevant actor in
476 // the remote process.
477 starter->mTaskQueue->Dispatch(NS_NewRunnableFunction(
478 "PBackground GetOrCreateForCurrentThread",
479 [starter, endpoint = std::move(parent)]() mutable {
480 if (!starter->SendInitBackground(std::move(endpoint))) {
481 NS_WARNING("Failed to create toplevel actor");
483 }));
484 return strongActor;
487 private:
488 static void CloseStarter(BackgroundStarterChild* aStarter) {
489 aStarter->mTaskQueue->Dispatch(NS_NewRunnableFunction(
490 "PBackgroundStarterChild Close",
491 [starter = RefPtr{aStarter}] { starter->Close(); }));
494 // This is only modified on the main thread. It is the thread-local index
495 // that we use to store the BackgroundChild for each thread.
496 unsigned int mThreadLocalIndex = kBadThreadLocalIndex;
498 // On the main thread, we store TLS in this global instead of in
499 // mThreadLocalIndex. That way, cooperative main threads all share the same
500 // thread info.
501 ThreadLocalInfo* mMainThreadInfo = nullptr;
503 // The starter which will be used to launch PBackground instances of this
504 // type. Only modified on the main thread, but may be read by any thread
505 // wanting to start background actors.
506 StaticDataMutex<StaticRefPtr<BackgroundStarterChild>> mStarter{"mStarter"};
509 // For PBackground between parent and content process.
510 static ThreadInfoWrapper sParentAndContentProcessThreadInfo;
512 // For PBackground between socket and content process.
513 static ThreadInfoWrapper sSocketAndContentProcessThreadInfo;
515 // For PBackground between socket and parent process.
516 static ThreadInfoWrapper sSocketAndParentProcessThreadInfo;
518 // This is only modified on the main thread. It prevents us from trying to
519 // create the background thread after application shutdown has started.
520 static bool sShutdownHasStarted;
522 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
523 nsISerialEventTarget* mOwningEventTarget;
524 #endif
526 #ifdef DEBUG
527 bool mActorWasAlive;
528 bool mActorDestroyed;
529 #endif
531 public:
532 static void Shutdown();
534 void AssertIsOnOwningThread() {
535 THREADSAFETY_ASSERT(mOwningEventTarget);
537 #ifdef RELEASE_OR_BETA
538 DebugOnly<bool> current;
539 #else
540 bool current;
541 #endif
542 THREADSAFETY_ASSERT(
543 NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)));
544 THREADSAFETY_ASSERT(current);
547 void AssertActorDestroyed() {
548 MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
551 explicit ChildImpl()
552 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
553 : mOwningEventTarget(GetCurrentSerialEventTarget())
554 #endif
555 #ifdef DEBUG
557 mActorWasAlive(false),
558 mActorDestroyed(false)
559 #endif
561 AssertIsOnOwningThread();
564 void SetActorAlive() {
565 AssertIsOnOwningThread();
566 MOZ_ASSERT(!mActorWasAlive);
567 MOZ_ASSERT(!mActorDestroyed);
569 #ifdef DEBUG
570 mActorWasAlive = true;
571 #endif
574 NS_INLINE_DECL_REFCOUNTING(ChildImpl, override)
576 private:
577 // Forwarded from BackgroundChild.
578 static void Startup();
580 // Forwarded from BackgroundChild.
581 static PBackgroundChild* GetForCurrentThread();
583 // Forwarded from BackgroundChild.
584 static PBackgroundChild* GetOrCreateForCurrentThread();
586 // Forwarded from BackgroundChild.
587 static PBackgroundChild* GetOrCreateSocketActorForCurrentThread();
589 // Forwarded from BackgroundChild.
590 static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread();
592 static void CloseForCurrentThread();
594 // Forwarded from BackgroundChildImpl.
595 static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
597 // Forwarded from BackgroundChild.
598 static void InitContentStarter(mozilla::dom::ContentChild* aContent);
600 // Forwarded from BackgroundChild.
601 static void InitSocketStarter(mozilla::net::SocketProcessChild* aSocket);
603 // Forwarded from BackgroundChild.
604 static void InitSocketBridgeStarter(
605 mozilla::net::SocketProcessBridgeChild* aSocketBridge);
607 static void ThreadLocalDestructor(void* aThreadLocal);
609 // This class is reference counted.
610 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed); }
612 // Only called by IPDL.
613 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
616 // -----------------------------------------------------------------------------
617 // ParentImpl Helper Declarations
618 // -----------------------------------------------------------------------------
620 class ParentImpl::ShutdownObserver final : public nsIObserver {
621 public:
622 ShutdownObserver() { AssertIsOnMainThread(); }
624 NS_DECL_ISUPPORTS
625 NS_DECL_NSIOBSERVER
627 private:
628 ~ShutdownObserver() { AssertIsOnMainThread(); }
631 // -----------------------------------------------------------------------------
632 // ChildImpl Helper Declarations
633 // -----------------------------------------------------------------------------
635 class ChildImpl::ShutdownObserver final : public nsIObserver {
636 public:
637 ShutdownObserver() { AssertIsOnMainThread(); }
639 NS_DECL_ISUPPORTS
640 NS_DECL_NSIOBSERVER
642 private:
643 ~ShutdownObserver() { AssertIsOnMainThread(); }
646 } // namespace
648 namespace mozilla {
649 namespace ipc {
651 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
653 #ifdef DEBUG
655 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
657 #endif // DEBUG
659 } // namespace ipc
660 } // namespace mozilla
662 // -----------------------------------------------------------------------------
663 // BackgroundParent Public Methods
664 // -----------------------------------------------------------------------------
666 // static
667 bool BackgroundParent::IsOtherProcessActor(
668 PBackgroundParent* aBackgroundActor) {
669 return ParentImpl::IsOtherProcessActor(aBackgroundActor);
672 // static
673 ThreadsafeContentParentHandle* BackgroundParent::GetContentParentHandle(
674 PBackgroundParent* aBackgroundActor) {
675 return ParentImpl::GetContentParentHandle(aBackgroundActor);
678 // static
679 uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) {
680 return ParentImpl::GetChildID(aBackgroundActor);
683 // static
684 bool BackgroundParent::AllocStarter(
685 ContentParent* aContent, Endpoint<PBackgroundStarterParent>&& aEndpoint) {
686 return ParentImpl::AllocStarter(aContent, std::move(aEndpoint));
689 // -----------------------------------------------------------------------------
690 // BackgroundChild Public Methods
691 // -----------------------------------------------------------------------------
693 // static
694 void BackgroundChild::Startup() { ChildImpl::Startup(); }
696 // static
697 PBackgroundChild* BackgroundChild::GetForCurrentThread() {
698 return ChildImpl::GetForCurrentThread();
701 // static
702 PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread() {
703 return ChildImpl::GetOrCreateForCurrentThread();
706 // static
707 PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread() {
708 return ChildImpl::GetOrCreateSocketActorForCurrentThread();
711 // static
712 PBackgroundChild*
713 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread() {
714 return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread();
717 // static
718 void BackgroundChild::CloseForCurrentThread() {
719 ChildImpl::CloseForCurrentThread();
722 // static
723 void BackgroundChild::InitContentStarter(ContentChild* aContent) {
724 ChildImpl::InitContentStarter(aContent);
727 // static
728 void BackgroundChild::InitSocketStarter(net::SocketProcessChild* aSocket) {
729 ChildImpl::InitSocketStarter(aSocket);
732 // static
733 void BackgroundChild::InitSocketBridgeStarter(
734 net::SocketProcessBridgeChild* aSocketBridge) {
735 ChildImpl::InitSocketBridgeStarter(aSocketBridge);
738 // -----------------------------------------------------------------------------
739 // BackgroundChildImpl Public Methods
740 // -----------------------------------------------------------------------------
742 // static
743 BackgroundChildImpl::ThreadLocal*
744 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
745 return ChildImpl::GetThreadLocalForCurrentThread();
748 // -----------------------------------------------------------------------------
749 // ParentImpl Static Members
750 // -----------------------------------------------------------------------------
752 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
754 nsTArray<IToplevelProtocol*>* ParentImpl::sLiveActorsForBackgroundThread;
756 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
758 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
760 Atomic<uint64_t> ParentImpl::sLiveActorCount;
762 bool ParentImpl::sShutdownObserverRegistered = false;
764 bool ParentImpl::sShutdownHasStarted = false;
766 // -----------------------------------------------------------------------------
767 // ChildImpl Static Members
768 // -----------------------------------------------------------------------------
770 ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo;
772 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo;
774 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo;
776 bool ChildImpl::sShutdownHasStarted = false;
778 // -----------------------------------------------------------------------------
779 // ParentImpl Implementation
780 // -----------------------------------------------------------------------------
782 // static
783 bool ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) {
784 AssertIsOnBackgroundThread();
785 MOZ_ASSERT(aBackgroundActor);
787 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
790 // static
791 ThreadsafeContentParentHandle* ParentImpl::GetContentParentHandle(
792 PBackgroundParent* aBackgroundActor) {
793 AssertIsOnBackgroundThread();
794 MOZ_ASSERT(aBackgroundActor);
796 return static_cast<ParentImpl*>(aBackgroundActor)->mContent.get();
799 // static
800 uint64_t ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor) {
801 AssertIsOnBackgroundThread();
802 MOZ_ASSERT(aBackgroundActor);
804 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
805 if (actor->mContent) {
806 return actor->mContent->ChildID();
809 return 0;
812 // static
813 bool ParentImpl::AllocStarter(ContentParent* aContent,
814 Endpoint<PBackgroundStarterParent>&& aEndpoint,
815 bool aCrossProcess) {
816 AssertIsInMainOrSocketProcess();
817 AssertIsOnMainThread();
819 MOZ_ASSERT(aEndpoint.IsValid());
821 if (!sBackgroundThread && !CreateBackgroundThread()) {
822 NS_WARNING("Failed to create background thread!");
823 return false;
826 sLiveActorCount++;
828 RefPtr<BackgroundStarterParent> actor = new BackgroundStarterParent(
829 aContent ? aContent->ThreadsafeHandle() : nullptr, aCrossProcess);
831 if (NS_FAILED(sBackgroundThread->Dispatch(NS_NewRunnableFunction(
832 "BackgroundStarterParent::ConnectActorRunnable",
833 [actor = std::move(actor), endpoint = std::move(aEndpoint),
834 liveActorArray = sLiveActorsForBackgroundThread]() mutable {
835 MOZ_ASSERT(endpoint.IsValid());
836 MOZ_ALWAYS_TRUE(endpoint.Bind(actor));
837 actor->SetLiveActorArray(liveActorArray);
838 })))) {
839 NS_WARNING("Failed to dispatch connect runnable!");
841 MOZ_ASSERT(sLiveActorCount);
842 sLiveActorCount--;
845 return true;
848 // static
849 bool ParentImpl::CreateBackgroundThread() {
850 AssertIsInMainOrSocketProcess();
851 AssertIsOnMainThread();
852 MOZ_ASSERT(!sBackgroundThread);
853 MOZ_ASSERT(!sLiveActorsForBackgroundThread);
855 if (sShutdownHasStarted) {
856 NS_WARNING(
857 "Trying to create background thread after shutdown has "
858 "already begun!");
859 return false;
862 nsCOMPtr<nsITimer> newShutdownTimer;
864 if (!sShutdownTimer) {
865 newShutdownTimer = NS_NewTimer();
866 if (!newShutdownTimer) {
867 return false;
871 if (!sShutdownObserverRegistered) {
872 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
873 if (NS_WARN_IF(!obs)) {
874 return false;
877 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
879 nsresult rv = obs->AddObserver(
880 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
881 if (NS_WARN_IF(NS_FAILED(rv))) {
882 return false;
885 sShutdownObserverRegistered = true;
888 nsCOMPtr<nsIThread> thread;
889 if (NS_FAILED(NS_NewNamedThread(
890 "IPDL Background", getter_AddRefs(thread),
891 NS_NewRunnableFunction(
892 "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
893 DebugOnly<PRThread*> oldBackgroundThread =
894 sBackgroundPRThread.exchange(PR_GetCurrentThread());
896 MOZ_ASSERT_IF(oldBackgroundThread,
897 PR_GetCurrentThread() != oldBackgroundThread);
898 })))) {
899 NS_WARNING("NS_NewNamedThread failed!");
900 return false;
903 sBackgroundThread = thread.forget();
905 sLiveActorsForBackgroundThread = new nsTArray<IToplevelProtocol*>(1);
907 if (!sShutdownTimer) {
908 MOZ_ASSERT(newShutdownTimer);
909 sShutdownTimer = newShutdownTimer;
912 return true;
915 // static
916 void ParentImpl::ShutdownBackgroundThread() {
917 AssertIsInMainOrSocketProcess();
918 AssertIsOnMainThread();
919 MOZ_ASSERT(sShutdownHasStarted);
920 MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
921 MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
923 nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
924 sShutdownTimer = nullptr;
926 if (sBackgroundThread) {
927 nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
928 sBackgroundThread = nullptr;
930 UniquePtr<nsTArray<IToplevelProtocol*>> liveActors(
931 sLiveActorsForBackgroundThread);
932 sLiveActorsForBackgroundThread = nullptr;
934 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
936 if (sLiveActorCount) {
937 // We need to spin the event loop while we wait for all the actors to be
938 // cleaned up. We also set a timeout to force-kill any hanging actors.
939 TimerCallbackClosure closure(thread, liveActors.get());
941 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->InitWithNamedFuncCallback(
942 &ShutdownTimerCallback, &closure, kShutdownTimerDelayMS,
943 nsITimer::TYPE_ONE_SHOT, "ParentImpl::ShutdownTimerCallback"));
945 SpinEventLoopUntil("ParentImpl::ShutdownBackgroundThread"_ns,
946 [&]() { return !sLiveActorCount; });
948 MOZ_ASSERT(liveActors->IsEmpty());
950 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
953 // Dispatch this runnable to unregister the PR thread from the profiler.
954 MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(NS_NewRunnableFunction(
955 "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
956 // It is possible that another background thread was created while
957 // this thread was shutting down. In that case we can't assert
958 // anything about sBackgroundPRThread and we should not modify it
959 // here.
960 sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
961 })));
963 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
967 // static
968 void ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) {
969 AssertIsInMainOrSocketProcess();
970 AssertIsOnMainThread();
971 MOZ_ASSERT(sShutdownHasStarted);
972 MOZ_ASSERT(sLiveActorCount);
974 auto closure = static_cast<TimerCallbackClosure*>(aClosure);
975 MOZ_ASSERT(closure);
977 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
978 // finished.
979 sLiveActorCount++;
981 InvokeAsync(
982 closure->mThread, __func__,
983 [liveActors = closure->mLiveActors]() {
984 MOZ_ASSERT(liveActors);
986 if (!liveActors->IsEmpty()) {
987 // Copy the array since calling Close() could mutate the
988 // actual array.
989 nsTArray<IToplevelProtocol*> actorsToClose(liveActors->Clone());
990 for (IToplevelProtocol* actor : actorsToClose) {
991 actor->Close();
994 return GenericPromise::CreateAndResolve(true, __func__);
996 ->Then(GetCurrentSerialEventTarget(), __func__, []() {
997 MOZ_ASSERT(sLiveActorCount);
998 sLiveActorCount--;
1002 void ParentImpl::Destroy() {
1003 // May be called on any thread!
1005 AssertIsInMainOrSocketProcess();
1007 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1008 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1009 &ParentImpl::MainThreadActorDestroy)));
1012 void ParentImpl::MainThreadActorDestroy() {
1013 AssertIsInMainOrSocketProcess();
1014 AssertIsOnMainThread();
1015 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1017 MOZ_ASSERT(sLiveActorCount);
1018 sLiveActorCount--;
1020 // This may be the last reference!
1021 Release();
1024 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy) {
1025 AssertIsInMainOrSocketProcess();
1026 AssertIsOnBackgroundThread();
1027 MOZ_ASSERT(!mActorDestroyed);
1028 MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1030 BackgroundParentImpl::ActorDestroy(aWhy);
1032 mActorDestroyed = true;
1034 if (mLiveActorArray) {
1035 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1036 mLiveActorArray = nullptr;
1039 // This is tricky. We should be able to call Destroy() here directly because
1040 // we're not going to touch 'this' or our MessageChannel any longer on this
1041 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1042 // it runs it will destroy 'this' and our associated MessageChannel. However,
1043 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1044 // racing with the main thread we must ensure that the MessageChannel lives
1045 // long enough to be cleared in this call stack.
1047 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1048 "ParentImpl::Destroy", this, &ParentImpl::Destroy)));
1051 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1053 NS_IMETHODIMP
1054 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1055 const char16_t* aData) {
1056 AssertIsInMainOrSocketProcess();
1057 AssertIsOnMainThread();
1058 MOZ_ASSERT(!sShutdownHasStarted);
1059 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1061 sShutdownHasStarted = true;
1063 // Do this first before calling (and spinning the event loop in)
1064 // ShutdownBackgroundThread().
1065 ChildImpl::Shutdown();
1067 ShutdownBackgroundThread();
1069 return NS_OK;
1072 BackgroundStarterParent::BackgroundStarterParent(
1073 ThreadsafeContentParentHandle* aContent, bool aCrossProcess)
1074 : mCrossProcess(aCrossProcess), mContent(aContent) {
1075 AssertIsOnMainThread();
1076 AssertIsInMainOrSocketProcess();
1077 MOZ_ASSERT_IF(!mCrossProcess, !mContent);
1078 MOZ_ASSERT_IF(!mCrossProcess, XRE_IsParentProcess());
1081 void BackgroundStarterParent::SetLiveActorArray(
1082 nsTArray<IToplevelProtocol*>* aLiveActorArray) {
1083 AssertIsInMainOrSocketProcess();
1084 AssertIsOnBackgroundThread();
1085 MOZ_ASSERT(aLiveActorArray);
1086 MOZ_ASSERT(!aLiveActorArray->Contains(this));
1087 MOZ_ASSERT(!mLiveActorArray);
1088 MOZ_ASSERT_IF(!mCrossProcess, OtherPid() == base::GetCurrentProcId());
1090 mLiveActorArray = aLiveActorArray;
1091 mLiveActorArray->AppendElement(this);
1094 IPCResult BackgroundStarterParent::RecvInitBackground(
1095 Endpoint<PBackgroundParent>&& aEndpoint) {
1096 AssertIsOnBackgroundThread();
1098 if (!aEndpoint.IsValid()) {
1099 return IPC_FAIL(this,
1100 "Cannot initialize PBackground with invalid endpoint");
1103 ParentImpl* actor = new ParentImpl(mContent, mCrossProcess);
1105 // Take a reference on this thread. If Open() fails then we will release this
1106 // reference in Destroy.
1107 NS_ADDREF(actor);
1109 ParentImpl::sLiveActorCount++;
1111 if (!aEndpoint.Bind(actor)) {
1112 actor->Destroy();
1113 return IPC_OK();
1116 if (mCrossProcess) {
1117 actor->SetLiveActorArray(mLiveActorArray);
1119 return IPC_OK();
1122 void BackgroundStarterParent::ActorDestroy(ActorDestroyReason aReason) {
1123 AssertIsOnBackgroundThread();
1125 if (mLiveActorArray) {
1126 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1127 mLiveActorArray = nullptr;
1130 // Make sure to decrement `sLiveActorCount` on the main thread.
1131 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1132 NS_NewRunnableFunction("BackgroundStarterParent::MainThreadDestroy",
1133 [] { ParentImpl::sLiveActorCount--; })));
1136 // -----------------------------------------------------------------------------
1137 // ChildImpl Implementation
1138 // -----------------------------------------------------------------------------
1140 // static
1141 void ChildImpl::Startup() {
1142 // This happens on the main thread but before XPCOM has started so we can't
1143 // assert that we're being called on the main thread here.
1145 sParentAndContentProcessThreadInfo.Startup();
1146 sSocketAndContentProcessThreadInfo.Startup();
1147 sSocketAndParentProcessThreadInfo.Startup();
1149 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1150 MOZ_RELEASE_ASSERT(observerService);
1152 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1154 nsresult rv = observerService->AddObserver(
1155 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1156 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1158 // Initialize a starter actor to allow starting PBackground within the parent
1159 // process.
1160 if (XRE_IsParentProcess()) {
1161 Endpoint<PBackgroundStarterParent> parent;
1162 Endpoint<PBackgroundStarterChild> child;
1163 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
1164 base::GetCurrentProcId(), base::GetCurrentProcId(), &parent, &child));
1166 MOZ_ALWAYS_TRUE(ParentImpl::AllocStarter(nullptr, std::move(parent),
1167 /* aCrossProcess */ false));
1168 sParentAndContentProcessThreadInfo.InitStarter(std::move(child));
1172 // static
1173 void ChildImpl::Shutdown() {
1174 AssertIsOnMainThread();
1176 sParentAndContentProcessThreadInfo.Shutdown();
1177 sSocketAndContentProcessThreadInfo.Shutdown();
1178 sSocketAndParentProcessThreadInfo.Shutdown();
1180 sShutdownHasStarted = true;
1183 // static
1184 PBackgroundChild* ChildImpl::GetForCurrentThread() {
1185 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1186 kBadThreadLocalIndex);
1188 auto threadLocalInfo =
1189 NS_IsMainThread()
1190 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1191 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1192 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1194 if (!threadLocalInfo) {
1195 return nullptr;
1198 return threadLocalInfo->mActor;
1201 /* static */
1202 PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread() {
1203 return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread();
1206 /* static */
1207 PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread() {
1208 return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread();
1211 /* static */
1212 PBackgroundChild*
1213 ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread() {
1214 return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread();
1217 // static
1218 void ChildImpl::CloseForCurrentThread() {
1219 MOZ_ASSERT(!NS_IsMainThread(),
1220 "PBackground for the main thread should be shut down via "
1221 "ChildImpl::Shutdown().");
1223 sParentAndContentProcessThreadInfo.CloseForCurrentThread();
1224 sSocketAndContentProcessThreadInfo.CloseForCurrentThread();
1225 sSocketAndParentProcessThreadInfo.CloseForCurrentThread();
1228 // static
1229 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
1230 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1231 kBadThreadLocalIndex,
1232 "BackgroundChild::Startup() was never called!");
1234 auto threadLocalInfo =
1235 NS_IsMainThread()
1236 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1237 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1238 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1240 if (!threadLocalInfo) {
1241 return nullptr;
1244 if (!threadLocalInfo->mConsumerThreadLocal) {
1245 threadLocalInfo->mConsumerThreadLocal =
1246 MakeUnique<BackgroundChildImpl::ThreadLocal>();
1249 return threadLocalInfo->mConsumerThreadLocal.get();
1252 // static
1253 void ChildImpl::InitContentStarter(mozilla::dom::ContentChild* aContent) {
1254 sParentAndContentProcessThreadInfo.InitStarter(aContent);
1257 // static
1258 void ChildImpl::InitSocketStarter(mozilla::net::SocketProcessChild* aSocket) {
1259 sSocketAndParentProcessThreadInfo.InitStarter(aSocket);
1262 // static
1263 void ChildImpl::InitSocketBridgeStarter(
1264 mozilla::net::SocketProcessBridgeChild* aSocketBridge) {
1265 sSocketAndContentProcessThreadInfo.InitStarter(aSocketBridge);
1268 // static
1269 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) {
1270 auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
1272 if (threadLocalInfo) {
1273 MOZ_ASSERT(threadLocalInfo->mClosed);
1275 if (threadLocalInfo->mActor) {
1276 threadLocalInfo->mActor->Close();
1277 threadLocalInfo->mActor->AssertActorDestroyed();
1280 delete threadLocalInfo;
1284 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy) {
1285 AssertIsOnOwningThread();
1287 #ifdef DEBUG
1288 MOZ_ASSERT(!mActorDestroyed);
1289 mActorDestroyed = true;
1290 #endif
1292 BackgroundChildImpl::ActorDestroy(aWhy);
1295 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1297 NS_IMETHODIMP
1298 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1299 const char16_t* aData) {
1300 AssertIsOnMainThread();
1301 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1303 ChildImpl::Shutdown();
1305 return NS_OK;