Bug 1660755 [wpt PR 25207] - [scroll-animations] Allow null source in ScrollTimeline...
[gecko.git] / ipc / glue / BackgroundImpl.cpp
blob50f4ee5fe35b8ae1530ff1ea2bd9cf6dc615ca3d
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/StaticPtr.h"
24 #include "mozilla/Unused.h"
25 #include "mozilla/dom/ContentChild.h"
26 #include "mozilla/dom/ContentParent.h"
27 #include "mozilla/dom/File.h"
28 #include "mozilla/dom/WorkerPrivate.h"
29 #include "mozilla/dom/WorkerRef.h"
30 #include "mozilla/ipc/ProtocolTypes.h"
31 #include "mozilla/net/SocketProcessChild.h"
32 #include "mozilla/net/SocketProcessBridgeChild.h"
33 #include "nsCOMPtr.h"
34 #include "nsIEventTarget.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 private:
96 class ShutdownObserver;
97 class CreateActorHelper;
99 struct MOZ_STACK_CLASS TimerCallbackClosure {
100 nsIThread* mThread;
101 nsTArray<ParentImpl*>* mLiveActors;
103 TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
104 : mThread(aThread), mLiveActors(aLiveActors) {
105 AssertIsInMainOrSocketProcess();
106 AssertIsOnMainThread();
107 MOZ_ASSERT(aThread);
108 MOZ_ASSERT(aLiveActors);
112 // The length of time we will wait at shutdown for all actors to clean
113 // themselves up before forcing them to be destroyed.
114 static const uint32_t kShutdownTimerDelayMS = 10000;
116 // This is only modified on the main thread. It is null if the thread does not
117 // exist or is shutting down.
118 static StaticRefPtr<nsIThread> sBackgroundThread;
120 // This is created and destroyed on the main thread but only modified on the
121 // background thread. It is specific to each instance of sBackgroundThread.
122 static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
124 // This is only modified on the main thread.
125 static StaticRefPtr<nsITimer> sShutdownTimer;
127 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
128 // work during shutdown.
129 static Atomic<PRThread*> sBackgroundPRThread;
131 // This is only modified on the main thread. It maintains a count of live
132 // actors so that the background thread can be shut down when it is no longer
133 // needed.
134 static uint64_t sLiveActorCount;
136 // This is only modified on the main thread. It is true after the shutdown
137 // observer is registered and is never unset thereafter.
138 static bool sShutdownObserverRegistered;
140 // This is only modified on the main thread. It prevents us from trying to
141 // create the background thread after application shutdown has started.
142 static bool sShutdownHasStarted;
144 // Only touched on the main thread, null if this is a same-process actor.
145 RefPtr<ContentParent> mContent;
147 // Set when the actor is opened successfully and used to handle shutdown
148 // hangs. Only touched on the background thread.
149 nsTArray<ParentImpl*>* mLiveActorArray;
151 // Set at construction to indicate whether this parent actor corresponds to a
152 // child actor in another process or to a child actor from a different thread
153 // in the same process.
154 const bool mIsOtherProcessActor;
156 // Set after ActorDestroy has been called. Only touched on the background
157 // thread.
158 bool mActorDestroyed;
160 public:
161 static already_AddRefed<ChildImpl> CreateActorForSameProcess(
162 nsIEventTarget* aMainEventTarget);
164 static bool IsOnBackgroundThread() {
165 return PR_GetCurrentThread() == sBackgroundPRThread;
168 static void AssertIsOnBackgroundThread() {
169 THREADSAFETY_ASSERT(IsOnBackgroundThread());
172 NS_INLINE_DECL_REFCOUNTING(ParentImpl)
174 void Destroy();
176 private:
177 // Forwarded from BackgroundParent.
178 static bool IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
180 // Forwarded from BackgroundParent.
181 static already_AddRefed<ContentParent> GetContentParent(
182 PBackgroundParent* aBackgroundActor);
184 // Forwarded from BackgroundParent.
185 static intptr_t GetRawContentParentForComparison(
186 PBackgroundParent* aBackgroundActor);
188 // Forwarded from BackgroundParent.
189 static uint64_t GetChildID(PBackgroundParent* aBackgroundActor);
191 // Forwarded from BackgroundParent.
192 static bool GetLiveActorArray(PBackgroundParent* aBackgroundActor,
193 nsTArray<PBackgroundParent*>& aLiveActorArray);
195 // Forwarded from BackgroundParent.
196 static bool Alloc(ContentParent* aContent,
197 Endpoint<PBackgroundParent>&& aEndpoint);
199 static bool CreateBackgroundThread();
201 static void ShutdownBackgroundThread();
203 static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
205 // For same-process actors.
206 ParentImpl()
207 : mLiveActorArray(nullptr),
208 mIsOtherProcessActor(false),
209 mActorDestroyed(false) {
210 AssertIsInMainProcess();
211 AssertIsOnMainThread();
214 // For other-process actors.
215 // NOTE: ParentImpl could be used in 3 cases below.
216 // 1. Between parent process and content process.
217 // 2. Between socket process and content process.
218 // 3. Between parent process and socket process.
219 // |mContent| should be not null for case 1. For case 2 and 3, it's null.
220 explicit ParentImpl(ContentParent* aContent)
221 : mContent(aContent),
222 mLiveActorArray(nullptr),
223 mIsOtherProcessActor(true),
224 mActorDestroyed(false) {
225 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
226 AssertIsOnMainThread();
229 ~ParentImpl() {
230 AssertIsInMainOrSocketProcess();
231 AssertIsOnMainThread();
232 MOZ_ASSERT(!mContent);
235 void MainThreadActorDestroy();
237 void SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray) {
238 AssertIsInMainOrSocketProcess();
239 AssertIsOnBackgroundThread();
240 MOZ_ASSERT(aLiveActorArray);
241 MOZ_ASSERT(!aLiveActorArray->Contains(this));
242 MOZ_ASSERT(!mLiveActorArray);
243 MOZ_ASSERT(mIsOtherProcessActor);
245 mLiveActorArray = aLiveActorArray;
246 mLiveActorArray->AppendElement(this);
249 // These methods are only called by IPDL.
250 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
253 // -----------------------------------------------------------------------------
254 // ChildImpl Declaration
255 // -----------------------------------------------------------------------------
257 class ChildImpl final : public BackgroundChildImpl {
258 friend class mozilla::ipc::BackgroundChild;
259 friend class mozilla::ipc::BackgroundChildImpl;
261 typedef base::ProcessId ProcessId;
262 typedef mozilla::ipc::Transport Transport;
264 class ShutdownObserver;
266 public:
267 class SendInitBackgroundRunnable;
269 struct ThreadLocalInfo {
270 ThreadLocalInfo()
271 #ifdef DEBUG
272 : mClosed(false)
273 #endif
277 RefPtr<ChildImpl> mActor;
278 RefPtr<SendInitBackgroundRunnable> mSendInitBackgroundRunnable;
279 UniquePtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
280 #ifdef DEBUG
281 bool mClosed;
282 #endif
285 private:
286 // A thread-local index that is not valid.
287 static constexpr unsigned int kBadThreadLocalIndex =
288 static_cast<unsigned int>(-1);
290 // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
291 // also provides some common functions for creating PBackground IPC actor.
292 class ThreadInfoWrapper final {
293 friend class ChildImpl;
295 public:
296 using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
297 nsIEventTarget*, ChildImpl**);
299 constexpr explicit ThreadInfoWrapper(ActorCreateFunc aFunc)
300 : mThreadLocalIndex(kBadThreadLocalIndex),
301 mMainThreadInfo(nullptr),
302 mCreateActorFunc(aFunc) {}
304 void Startup() {
305 MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
306 "ThreadInfoWrapper::Startup() called more than once!");
308 PRStatus status =
309 PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
310 MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
311 "PR_NewThreadPrivateIndex failed!");
313 MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
316 void Shutdown() {
317 if (sShutdownHasStarted) {
318 MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
319 !PR_GetThreadPrivate(mThreadLocalIndex));
320 return;
323 if (mThreadLocalIndex == kBadThreadLocalIndex) {
324 return;
327 ThreadLocalInfo* threadLocalInfo;
328 #ifdef DEBUG
329 threadLocalInfo =
330 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
331 MOZ_ASSERT(!threadLocalInfo);
332 #endif
334 threadLocalInfo = mMainThreadInfo;
335 if (threadLocalInfo) {
336 #ifdef DEBUG
337 MOZ_ASSERT(!threadLocalInfo->mClosed);
338 threadLocalInfo->mClosed = true;
339 #endif
341 ThreadLocalDestructor(threadLocalInfo);
342 mMainThreadInfo = nullptr;
346 void CloseForCurrentThread() {
347 MOZ_ASSERT(!NS_IsMainThread());
349 if (mThreadLocalIndex == kBadThreadLocalIndex) {
350 return;
353 auto threadLocalInfo =
354 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
356 if (!threadLocalInfo) {
357 return;
360 #ifdef DEBUG
361 MOZ_ASSERT(!threadLocalInfo->mClosed);
362 threadLocalInfo->mClosed = true;
363 #endif
365 // Clearing the thread local will synchronously close the actor.
366 DebugOnly<PRStatus> status =
367 PR_SetThreadPrivate(mThreadLocalIndex, nullptr);
368 MOZ_ASSERT(status == PR_SUCCESS);
371 PBackgroundChild* GetOrCreateForCurrentThread(
372 nsIEventTarget* aMainEventTarget) {
373 MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget);
375 MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex,
376 "BackgroundChild::Startup() was never called!");
378 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
379 return nullptr;
382 auto threadLocalInfo = NS_IsMainThread()
383 ? mMainThreadInfo
384 : static_cast<ThreadLocalInfo*>(
385 PR_GetThreadPrivate(mThreadLocalIndex));
387 if (!threadLocalInfo) {
388 auto newInfo = MakeUnique<ThreadLocalInfo>();
390 if (NS_IsMainThread()) {
391 mMainThreadInfo = newInfo.get();
392 } else {
393 if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
394 PR_SUCCESS) {
395 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
396 return nullptr;
400 threadLocalInfo = newInfo.release();
403 PBackgroundChild* bgChild =
404 GetFromThreadInfo(aMainEventTarget, threadLocalInfo);
405 if (bgChild) {
406 return bgChild;
409 RefPtr<ChildImpl> actor;
410 mCreateActorFunc(threadLocalInfo, mThreadLocalIndex, aMainEventTarget,
411 getter_AddRefs(actor));
412 return actor;
415 private:
416 // This is only modified on the main thread. It is the thread-local index
417 // that we use to store the BackgroundChild for each thread.
418 unsigned int mThreadLocalIndex;
420 // On the main thread, we store TLS in this global instead of in
421 // mThreadLocalIndex. That way, cooperative main threads all share the same
422 // thread info.
423 ThreadLocalInfo* mMainThreadInfo;
424 ActorCreateFunc mCreateActorFunc;
427 // For PBackground between parent and content process.
428 static ThreadInfoWrapper sParentAndContentProcessThreadInfo;
430 // For PBackground between socket and content process.
431 static ThreadInfoWrapper sSocketAndContentProcessThreadInfo;
433 // For PBackground between socket and parent process.
434 static ThreadInfoWrapper sSocketAndParentProcessThreadInfo;
436 // This is only modified on the main thread. It prevents us from trying to
437 // create the background thread after application shutdown has started.
438 static bool sShutdownHasStarted;
440 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
441 nsISerialEventTarget* mOwningEventTarget;
442 #endif
444 #ifdef DEBUG
445 bool mActorWasAlive;
446 bool mActorDestroyed;
447 #endif
449 public:
450 static void Shutdown();
452 void AssertIsOnOwningThread() {
453 THREADSAFETY_ASSERT(mOwningEventTarget);
455 #ifdef RELEASE_OR_BETA
456 DebugOnly<bool> current;
457 #else
458 bool current;
459 #endif
460 THREADSAFETY_ASSERT(
461 NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)));
462 THREADSAFETY_ASSERT(current);
465 void AssertActorDestroyed() {
466 MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
469 explicit ChildImpl()
470 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
471 : mOwningEventTarget(GetCurrentSerialEventTarget())
472 #endif
473 #ifdef DEBUG
475 mActorWasAlive(false),
476 mActorDestroyed(false)
477 #endif
479 AssertIsOnOwningThread();
482 void SetActorAlive() {
483 AssertIsOnOwningThread();
484 MOZ_ASSERT(!mActorWasAlive);
485 MOZ_ASSERT(!mActorDestroyed);
487 #ifdef DEBUG
488 mActorWasAlive = true;
489 #endif
492 NS_INLINE_DECL_REFCOUNTING(ChildImpl)
494 private:
495 // Forwarded from BackgroundChild.
496 static void Startup();
498 // Forwarded from BackgroundChild.
499 static PBackgroundChild* GetForCurrentThread();
501 // Helper function for getting PBackgroundChild from thread info.
502 static PBackgroundChild* GetFromThreadInfo(nsIEventTarget* aMainEventTarget,
503 ThreadLocalInfo* aThreadLocalInfo);
505 // Forwarded from BackgroundChild.
506 static PBackgroundChild* GetOrCreateForCurrentThread(
507 nsIEventTarget* aMainEventTarget);
509 // Forwarded from BackgroundChild.
510 static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(
511 nsIEventTarget* aMainEventTarget);
513 // Forwarded from BackgroundChild.
514 static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
515 nsIEventTarget* aMainEventTarget);
517 static void CloseForCurrentThread();
519 // Forwarded from BackgroundChildImpl.
520 static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
522 static void ThreadLocalDestructor(void* aThreadLocal);
524 // This class is reference counted.
525 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed); }
527 // Only called by IPDL.
528 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
531 // -----------------------------------------------------------------------------
532 // ParentImpl Helper Declarations
533 // -----------------------------------------------------------------------------
535 class ParentImpl::ShutdownObserver final : public nsIObserver {
536 public:
537 ShutdownObserver() { AssertIsOnMainThread(); }
539 NS_DECL_ISUPPORTS
540 NS_DECL_NSIOBSERVER
542 private:
543 ~ShutdownObserver() { AssertIsOnMainThread(); }
546 class ParentImpl::CreateActorHelper final : public Runnable {
547 mozilla::Monitor mMonitor;
548 RefPtr<ParentImpl> mParentActor;
549 nsCOMPtr<nsIThread> mThread;
550 nsresult mMainThreadResultCode;
551 bool mWaiting;
553 public:
554 explicit CreateActorHelper()
555 : Runnable("Background::ParentImpl::CreateActorHelper"),
556 mMonitor("CreateActorHelper::mMonitor"),
557 mMainThreadResultCode(NS_OK),
558 mWaiting(true) {
559 AssertIsInMainOrSocketProcess();
560 AssertIsNotOnMainThread();
563 nsresult BlockAndGetResults(nsIEventTarget* aMainEventTarget,
564 RefPtr<ParentImpl>& aParentActor,
565 nsCOMPtr<nsIThread>& aThread);
567 private:
568 ~CreateActorHelper() { AssertIsInMainOrSocketProcess(); }
570 nsresult RunOnMainThread();
572 NS_DECL_NSIRUNNABLE
575 // -----------------------------------------------------------------------------
576 // ChildImpl Helper Declarations
577 // -----------------------------------------------------------------------------
579 class ChildImpl::ShutdownObserver final : public nsIObserver {
580 public:
581 ShutdownObserver() { AssertIsOnMainThread(); }
583 NS_DECL_ISUPPORTS
584 NS_DECL_NSIOBSERVER
586 private:
587 ~ShutdownObserver() { AssertIsOnMainThread(); }
590 class ChildImpl::SendInitBackgroundRunnable final : public CancelableRunnable {
591 nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
592 RefPtr<StrongWorkerRef> mWorkerRef;
593 Endpoint<PBackgroundParent> mParent;
594 mozilla::Mutex mMutex;
595 bool mSentInitBackground;
596 std::function<void(Endpoint<PBackgroundParent>&& aParent)> mSendInitfunc;
597 unsigned int mThreadLocalIndex;
599 public:
600 static already_AddRefed<SendInitBackgroundRunnable> Create(
601 Endpoint<PBackgroundParent>&& aParent,
602 std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
603 unsigned int aThreadLocalIndex);
605 void ClearEventTarget() {
606 mWorkerRef = nullptr;
608 mozilla::MutexAutoLock lock(mMutex);
609 mOwningEventTarget = nullptr;
612 private:
613 explicit SendInitBackgroundRunnable(
614 Endpoint<PBackgroundParent>&& aParent,
615 std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
616 unsigned int aThreadLocalIndex)
617 : CancelableRunnable("Background::ChildImpl::SendInitBackgroundRunnable"),
618 mOwningEventTarget(GetCurrentSerialEventTarget()),
619 mParent(std::move(aParent)),
620 mMutex("SendInitBackgroundRunnable::mMutex"),
621 mSentInitBackground(false),
622 mSendInitfunc(std::move(aFunc)),
623 mThreadLocalIndex(aThreadLocalIndex) {}
625 ~SendInitBackgroundRunnable() = default;
627 NS_DECL_NSIRUNNABLE
630 } // namespace
632 namespace mozilla {
633 namespace ipc {
635 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
637 #ifdef DEBUG
639 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
641 #endif // DEBUG
643 } // namespace ipc
644 } // namespace mozilla
646 // -----------------------------------------------------------------------------
647 // BackgroundParent Public Methods
648 // -----------------------------------------------------------------------------
650 // static
651 bool BackgroundParent::IsOtherProcessActor(
652 PBackgroundParent* aBackgroundActor) {
653 return ParentImpl::IsOtherProcessActor(aBackgroundActor);
656 // static
657 already_AddRefed<ContentParent> BackgroundParent::GetContentParent(
658 PBackgroundParent* aBackgroundActor) {
659 return ParentImpl::GetContentParent(aBackgroundActor);
662 // static
663 intptr_t BackgroundParent::GetRawContentParentForComparison(
664 PBackgroundParent* aBackgroundActor) {
665 return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
668 // static
669 uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) {
670 return ParentImpl::GetChildID(aBackgroundActor);
673 // static
674 bool BackgroundParent::GetLiveActorArray(
675 PBackgroundParent* aBackgroundActor,
676 nsTArray<PBackgroundParent*>& aLiveActorArray) {
677 return ParentImpl::GetLiveActorArray(aBackgroundActor, aLiveActorArray);
680 // static
681 bool BackgroundParent::Alloc(ContentParent* aContent,
682 Endpoint<PBackgroundParent>&& aEndpoint) {
683 return ParentImpl::Alloc(aContent, std::move(aEndpoint));
686 // -----------------------------------------------------------------------------
687 // BackgroundChild Public Methods
688 // -----------------------------------------------------------------------------
690 // static
691 void BackgroundChild::Startup() { ChildImpl::Startup(); }
693 // static
694 PBackgroundChild* BackgroundChild::GetForCurrentThread() {
695 return ChildImpl::GetForCurrentThread();
698 // static
699 PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread(
700 nsIEventTarget* aMainEventTarget) {
701 return ChildImpl::GetOrCreateForCurrentThread(aMainEventTarget);
704 // static
705 PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread(
706 nsIEventTarget* aMainEventTarget) {
707 return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget);
710 // static
711 PBackgroundChild*
712 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread(
713 nsIEventTarget* aMainEventTarget) {
714 return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
715 aMainEventTarget);
718 // static
719 void BackgroundChild::CloseForCurrentThread() {
720 ChildImpl::CloseForCurrentThread();
723 // -----------------------------------------------------------------------------
724 // BackgroundChildImpl Public Methods
725 // -----------------------------------------------------------------------------
727 // static
728 BackgroundChildImpl::ThreadLocal*
729 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
730 return ChildImpl::GetThreadLocalForCurrentThread();
733 // -----------------------------------------------------------------------------
734 // ParentImpl Static Members
735 // -----------------------------------------------------------------------------
737 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
739 nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
741 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
743 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
745 uint64_t ParentImpl::sLiveActorCount = 0;
747 bool ParentImpl::sShutdownObserverRegistered = false;
749 bool ParentImpl::sShutdownHasStarted = false;
751 // -----------------------------------------------------------------------------
752 // ChildImpl Static Members
753 // -----------------------------------------------------------------------------
755 static void ParentContentActorCreateFunc(
756 ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
757 unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
758 ChildImpl** aOutput) {
759 if (XRE_IsParentProcess()) {
760 RefPtr<ChildImpl> strongActor =
761 ParentImpl::CreateActorForSameProcess(aMainEventTarget);
762 if (NS_WARN_IF(!strongActor)) {
763 return;
766 aThreadLocalInfo->mActor = strongActor;
767 strongActor.forget(aOutput);
768 return;
771 RefPtr<ContentChild> content = ContentChild::GetSingleton();
772 MOZ_ASSERT(content);
774 if (content->IsShuttingDown()) {
775 // The transport for ContentChild is shut down and can't be used to open
776 // PBackground.
777 return;
780 Endpoint<PBackgroundParent> parent;
781 Endpoint<PBackgroundChild> child;
782 nsresult rv;
783 rv = PBackground::CreateEndpoints(content->OtherPid(),
784 base::GetCurrentProcId(), &parent, &child);
785 if (NS_FAILED(rv)) {
786 NS_WARNING("Failed to create top level actor!");
787 return;
790 RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
791 if (!NS_IsMainThread()) {
792 runnable = ChildImpl::SendInitBackgroundRunnable::Create(
793 std::move(parent),
794 [](Endpoint<PBackgroundParent>&& aParent) {
795 RefPtr<ContentChild> content = ContentChild::GetSingleton();
796 MOZ_ASSERT(content);
798 if (!content->SendInitBackground(std::move(aParent))) {
799 NS_WARNING("Failed to create top level actor!");
802 aThreadLocalIndex);
803 if (!runnable) {
804 return;
808 RefPtr<ChildImpl> strongActor = new ChildImpl();
810 if (!child.Bind(strongActor)) {
811 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
813 return;
816 strongActor->SetActorAlive();
818 if (NS_IsMainThread()) {
819 if (!content->SendInitBackground(std::move(parent))) {
820 NS_WARNING("Failed to create top level actor!");
821 return;
823 } else {
824 if (aMainEventTarget) {
825 MOZ_ALWAYS_SUCCEEDS(
826 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
827 } else {
828 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
831 aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
834 aThreadLocalInfo->mActor = strongActor;
835 strongActor.forget(aOutput);
838 ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo(
839 ParentContentActorCreateFunc);
841 static void SocketContentActorCreateFunc(
842 ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
843 unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
844 ChildImpl** aOutput) {
845 RefPtr<SocketProcessBridgeChild> bridgeChild =
846 SocketProcessBridgeChild::GetSingleton();
848 if (!bridgeChild || bridgeChild->IsShuttingDown()) {
849 // The transport for SocketProcessBridgeChild is shut down
850 // and can't be used to open PBackground.
851 return;
854 Endpoint<PBackgroundParent> parent;
855 Endpoint<PBackgroundChild> child;
856 nsresult rv;
857 rv = PBackground::CreateEndpoints(bridgeChild->SocketProcessPid(),
858 base::GetCurrentProcId(), &parent, &child);
859 if (NS_FAILED(rv)) {
860 NS_WARNING("Failed to create top level actor!");
861 return;
864 RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
865 if (!NS_IsMainThread()) {
866 runnable = ChildImpl::SendInitBackgroundRunnable::Create(
867 std::move(parent),
868 [](Endpoint<PBackgroundParent>&& aParent) {
869 RefPtr<SocketProcessBridgeChild> bridgeChild =
870 SocketProcessBridgeChild::GetSingleton();
872 if (!bridgeChild->SendInitBackground(std::move(aParent))) {
873 NS_WARNING("Failed to create top level actor!");
876 aThreadLocalIndex);
877 if (!runnable) {
878 return;
882 RefPtr<ChildImpl> strongActor = new ChildImpl();
884 if (!child.Bind(strongActor)) {
885 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
887 return;
890 strongActor->SetActorAlive();
892 if (NS_IsMainThread()) {
893 if (!bridgeChild->SendInitBackground(std::move(parent))) {
894 NS_WARNING("Failed to create top level actor!");
895 // Need to close the IPC channel before ChildImpl getting deleted.
896 strongActor->Close();
897 strongActor->AssertActorDestroyed();
898 return;
900 } else {
901 if (aMainEventTarget) {
902 MOZ_ALWAYS_SUCCEEDS(
903 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
904 } else {
905 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
908 aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
911 aThreadLocalInfo->mActor = strongActor;
912 strongActor.forget(aOutput);
915 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo(
916 SocketContentActorCreateFunc);
918 static void SocketParentActorCreateFunc(
919 ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
920 unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
921 ChildImpl** aOutput) {
922 SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
924 if (!socketChild || socketChild->IsShuttingDown()) {
925 return;
928 Endpoint<PBackgroundParent> parent;
929 Endpoint<PBackgroundChild> child;
930 nsresult rv;
931 rv = PBackground::CreateEndpoints(socketChild->OtherPid(),
932 base::GetCurrentProcId(), &parent, &child);
933 if (NS_FAILED(rv)) {
934 NS_WARNING("Failed to create top level actor!");
935 return;
938 RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
939 if (!NS_IsMainThread()) {
940 runnable = ChildImpl::SendInitBackgroundRunnable::Create(
941 std::move(parent),
942 [](Endpoint<PBackgroundParent>&& aParent) {
943 SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
944 MOZ_ASSERT(socketChild);
946 if (!socketChild->SendInitBackground(std::move(aParent))) {
947 MOZ_CRASH("Failed to create top level actor!");
950 aThreadLocalIndex);
951 if (!runnable) {
952 return;
956 RefPtr<ChildImpl> strongActor = new ChildImpl();
958 if (!child.Bind(strongActor)) {
959 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
960 return;
963 strongActor->SetActorAlive();
965 if (NS_IsMainThread()) {
966 if (!socketChild->SendInitBackground(std::move(parent))) {
967 NS_WARNING("Failed to create top level actor!");
968 return;
970 } else {
971 if (aMainEventTarget) {
972 MOZ_ALWAYS_SUCCEEDS(
973 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
974 } else {
975 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
978 aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
981 aThreadLocalInfo->mActor = strongActor;
982 strongActor.forget(aOutput);
985 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo(
986 SocketParentActorCreateFunc);
988 bool ChildImpl::sShutdownHasStarted = false;
990 // -----------------------------------------------------------------------------
991 // ParentImpl Implementation
992 // -----------------------------------------------------------------------------
994 // static
995 bool ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) {
996 AssertIsOnBackgroundThread();
997 MOZ_ASSERT(aBackgroundActor);
999 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
1002 // static
1003 already_AddRefed<ContentParent> ParentImpl::GetContentParent(
1004 PBackgroundParent* aBackgroundActor) {
1005 AssertIsOnBackgroundThread();
1006 MOZ_ASSERT(aBackgroundActor);
1008 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1009 if (actor->mActorDestroyed) {
1010 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1011 return nullptr;
1014 if (actor->mContent) {
1015 // We need to hand out a reference to our ContentParent but we also need to
1016 // keep the one we have. We can't call AddRef here because ContentParent is
1017 // not threadsafe so instead we dispatch a runnable to the main thread to do
1018 // it for us. This is safe since we are guaranteed that our AddRef runnable
1019 // will run before the reference we hand out can be released, and the
1020 // ContentParent can't die as long as the existing reference is maintained.
1021 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
1022 "ContentParent::AddRef", actor->mContent, &ContentParent::AddRef)));
1025 return already_AddRefed<ContentParent>(actor->mContent.get());
1028 // static
1029 intptr_t ParentImpl::GetRawContentParentForComparison(
1030 PBackgroundParent* aBackgroundActor) {
1031 AssertIsOnBackgroundThread();
1032 MOZ_ASSERT(aBackgroundActor);
1034 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1035 if (actor->mActorDestroyed) {
1036 MOZ_ASSERT(false,
1037 "GetRawContentParentForComparison called after ActorDestroy was "
1038 "called!");
1039 return intptr_t(-1);
1042 return intptr_t(static_cast<ContentParent*>(actor->mContent.get()));
1045 // static
1046 uint64_t ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor) {
1047 AssertIsOnBackgroundThread();
1048 MOZ_ASSERT(aBackgroundActor);
1050 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1051 if (actor->mActorDestroyed) {
1052 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1053 return 0;
1056 if (actor->mContent) {
1057 return actor->mContent->ChildID();
1060 return 0;
1063 // static
1064 bool ParentImpl::GetLiveActorArray(
1065 PBackgroundParent* aBackgroundActor,
1066 nsTArray<PBackgroundParent*>& aLiveActorArray) {
1067 AssertIsOnBackgroundThread();
1068 MOZ_ASSERT(aBackgroundActor);
1069 MOZ_ASSERT(aLiveActorArray.IsEmpty());
1071 auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1072 if (actor->mActorDestroyed) {
1073 MOZ_ASSERT(false,
1074 "GetLiveActorArray called after ActorDestroy was called!");
1075 return false;
1078 if (!actor->mLiveActorArray) {
1079 return true;
1082 for (ParentImpl* liveActor : *actor->mLiveActorArray) {
1083 aLiveActorArray.AppendElement(liveActor);
1086 return true;
1089 // static
1090 bool ParentImpl::Alloc(ContentParent* aContent,
1091 Endpoint<PBackgroundParent>&& aEndpoint) {
1092 AssertIsInMainOrSocketProcess();
1093 AssertIsOnMainThread();
1094 MOZ_ASSERT(aEndpoint.IsValid());
1096 if (!sBackgroundThread && !CreateBackgroundThread()) {
1097 NS_WARNING("Failed to create background thread!");
1098 return false;
1101 MOZ_ASSERT(sLiveActorsForBackgroundThread);
1103 sLiveActorCount++;
1105 RefPtr<ParentImpl> actor = new ParentImpl(aContent);
1107 if (NS_FAILED(sBackgroundThread->Dispatch(NS_NewRunnableFunction(
1108 "Background::ParentImpl::ConnectActorRunnable",
1109 [actor = std::move(actor), endpoint = std::move(aEndpoint),
1110 liveActorArray = sLiveActorsForBackgroundThread]() mutable {
1111 MOZ_ASSERT(endpoint.IsValid());
1112 MOZ_ASSERT(liveActorArray);
1113 // Transfer ownership to this thread. If Open() fails then we will
1114 // release this reference in Destroy.
1115 ParentImpl* actorTmp;
1116 actor.forget(&actorTmp);
1118 if (!endpoint.Bind(actorTmp)) {
1119 actorTmp->Destroy();
1120 return;
1123 actorTmp->SetLiveActorArray(liveActorArray);
1124 })))) {
1125 NS_WARNING("Failed to dispatch connect runnable!");
1127 MOZ_ASSERT(sLiveActorCount);
1128 sLiveActorCount--;
1131 return true;
1134 // static
1135 already_AddRefed<ChildImpl> ParentImpl::CreateActorForSameProcess(
1136 nsIEventTarget* aMainEventTarget) {
1137 AssertIsInMainProcess();
1139 RefPtr<ParentImpl> parentActor;
1140 nsCOMPtr<nsIThread> backgroundThread;
1142 if (NS_IsMainThread()) {
1143 if (!sBackgroundThread && !CreateBackgroundThread()) {
1144 NS_WARNING("Failed to create background thread!");
1145 return nullptr;
1148 MOZ_ASSERT(!sShutdownHasStarted);
1150 sLiveActorCount++;
1152 parentActor = new ParentImpl();
1153 backgroundThread = sBackgroundThread.get();
1154 } else {
1155 RefPtr<CreateActorHelper> helper = new CreateActorHelper();
1157 nsresult rv = helper->BlockAndGetResults(aMainEventTarget, parentActor,
1158 backgroundThread);
1159 if (NS_WARN_IF(NS_FAILED(rv))) {
1160 return nullptr;
1164 RefPtr<ChildImpl> childActor = new ChildImpl();
1166 MessageChannel* parentChannel = parentActor->GetIPCChannel();
1167 MOZ_ASSERT(parentChannel);
1169 if (!childActor->Open(parentChannel, backgroundThread, ChildSide)) {
1170 NS_WARNING("Failed to open ChildImpl!");
1172 // Can't release it here, we will release this reference in Destroy.
1173 ParentImpl* actor;
1174 parentActor.forget(&actor);
1176 actor->Destroy();
1178 return nullptr;
1181 childActor->SetActorAlive();
1183 // Make sure the parent knows it is same process.
1184 parentActor->SetOtherProcessId(base::GetCurrentProcId());
1186 // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
1187 Unused << parentActor.forget();
1189 return childActor.forget();
1192 // static
1193 bool ParentImpl::CreateBackgroundThread() {
1194 AssertIsInMainOrSocketProcess();
1195 AssertIsOnMainThread();
1196 MOZ_ASSERT(!sBackgroundThread);
1197 MOZ_ASSERT(!sLiveActorsForBackgroundThread);
1199 if (sShutdownHasStarted) {
1200 NS_WARNING(
1201 "Trying to create background thread after shutdown has "
1202 "already begun!");
1203 return false;
1206 nsCOMPtr<nsITimer> newShutdownTimer;
1208 if (!sShutdownTimer) {
1209 newShutdownTimer = NS_NewTimer();
1210 if (!newShutdownTimer) {
1211 return false;
1215 if (!sShutdownObserverRegistered) {
1216 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1217 if (NS_WARN_IF(!obs)) {
1218 return false;
1221 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1223 nsresult rv = obs->AddObserver(
1224 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1225 if (NS_WARN_IF(NS_FAILED(rv))) {
1226 return false;
1229 sShutdownObserverRegistered = true;
1232 nsCOMPtr<nsIThread> thread;
1233 if (NS_FAILED(NS_NewNamedThread(
1234 "IPDL Background", getter_AddRefs(thread),
1235 NS_NewRunnableFunction(
1236 "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
1237 DebugOnly<PRThread*> oldBackgroundThread =
1238 sBackgroundPRThread.exchange(PR_GetCurrentThread());
1240 MOZ_ASSERT_IF(oldBackgroundThread,
1241 PR_GetCurrentThread() != oldBackgroundThread);
1242 })))) {
1243 NS_WARNING("NS_NewNamedThread failed!");
1244 return false;
1247 sBackgroundThread = thread.forget();
1249 sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
1251 if (!sShutdownTimer) {
1252 MOZ_ASSERT(newShutdownTimer);
1253 sShutdownTimer = newShutdownTimer;
1256 return true;
1259 // static
1260 void ParentImpl::ShutdownBackgroundThread() {
1261 AssertIsInMainOrSocketProcess();
1262 AssertIsOnMainThread();
1263 MOZ_ASSERT(sShutdownHasStarted);
1264 MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
1265 MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
1267 nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
1268 sShutdownTimer = nullptr;
1270 if (sBackgroundThread) {
1271 nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
1272 sBackgroundThread = nullptr;
1274 UniquePtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread);
1275 sLiveActorsForBackgroundThread = nullptr;
1277 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
1279 if (sLiveActorCount) {
1280 // We need to spin the event loop while we wait for all the actors to be
1281 // cleaned up. We also set a timeout to force-kill any hanging actors.
1282 TimerCallbackClosure closure(thread, liveActors.get());
1284 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->InitWithNamedFuncCallback(
1285 &ShutdownTimerCallback, &closure, kShutdownTimerDelayMS,
1286 nsITimer::TYPE_ONE_SHOT, "ParentImpl::ShutdownTimerCallback"));
1288 SpinEventLoopUntil([&]() { return !sLiveActorCount; });
1290 MOZ_ASSERT(liveActors->IsEmpty());
1292 MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
1295 // Dispatch this runnable to unregister the PR thread from the profiler.
1296 MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(NS_NewRunnableFunction(
1297 "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
1298 // It is possible that another background thread was created while
1299 // this thread was shutting down. In that case we can't assert
1300 // anything about sBackgroundPRThread and we should not modify it
1301 // here.
1302 sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1303 })));
1305 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
1309 // static
1310 void ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) {
1311 AssertIsInMainOrSocketProcess();
1312 AssertIsOnMainThread();
1313 MOZ_ASSERT(sShutdownHasStarted);
1314 MOZ_ASSERT(sLiveActorCount);
1316 auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1317 MOZ_ASSERT(closure);
1319 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1320 // finished.
1321 sLiveActorCount++;
1323 InvokeAsync(closure->mThread, __func__,
1324 [liveActors = closure->mLiveActors]() {
1325 MOZ_ASSERT(liveActors);
1327 if (!liveActors->IsEmpty()) {
1328 // Copy the array since calling Close() could mutate the
1329 // actual array.
1330 nsTArray<ParentImpl*> actorsToClose(liveActors->Clone());
1331 for (ParentImpl* actor : actorsToClose) {
1332 actor->Close();
1335 return GenericPromise::CreateAndResolve(true, __func__);
1337 ->Then(GetCurrentSerialEventTarget(), __func__, []() {
1338 MOZ_ASSERT(sLiveActorCount);
1339 sLiveActorCount--;
1343 void ParentImpl::Destroy() {
1344 // May be called on any thread!
1346 AssertIsInMainOrSocketProcess();
1348 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1349 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1350 &ParentImpl::MainThreadActorDestroy)));
1353 void ParentImpl::MainThreadActorDestroy() {
1354 AssertIsInMainOrSocketProcess();
1355 AssertIsOnMainThread();
1356 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1358 mContent = nullptr;
1360 MOZ_ASSERT(sLiveActorCount);
1361 sLiveActorCount--;
1363 // This may be the last reference!
1364 Release();
1367 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy) {
1368 AssertIsInMainOrSocketProcess();
1369 AssertIsOnBackgroundThread();
1370 MOZ_ASSERT(!mActorDestroyed);
1371 MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1373 BackgroundParentImpl::ActorDestroy(aWhy);
1375 mActorDestroyed = true;
1377 if (mLiveActorArray) {
1378 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1379 mLiveActorArray = nullptr;
1382 // This is tricky. We should be able to call Destroy() here directly because
1383 // we're not going to touch 'this' or our MessageChannel any longer on this
1384 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1385 // it runs it will destroy 'this' and our associated MessageChannel. However,
1386 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1387 // racing with the main thread we must ensure that the MessageChannel lives
1388 // long enough to be cleared in this call stack.
1390 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1391 "ParentImpl::Destroy", this, &ParentImpl::Destroy)));
1394 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1396 NS_IMETHODIMP
1397 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1398 const char16_t* aData) {
1399 AssertIsInMainOrSocketProcess();
1400 AssertIsOnMainThread();
1401 MOZ_ASSERT(!sShutdownHasStarted);
1402 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1404 sShutdownHasStarted = true;
1406 // Do this first before calling (and spinning the event loop in)
1407 // ShutdownBackgroundThread().
1408 ChildImpl::Shutdown();
1410 ShutdownBackgroundThread();
1412 return NS_OK;
1415 nsresult ParentImpl::CreateActorHelper::BlockAndGetResults(
1416 nsIEventTarget* aMainEventTarget, RefPtr<ParentImpl>& aParentActor,
1417 nsCOMPtr<nsIThread>& aThread) {
1418 AssertIsNotOnMainThread();
1420 if (aMainEventTarget) {
1421 MOZ_ALWAYS_SUCCEEDS(aMainEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
1422 } else {
1423 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1426 mozilla::MonitorAutoLock lock(mMonitor);
1427 while (mWaiting) {
1428 lock.Wait();
1431 if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) {
1432 return mMainThreadResultCode;
1435 aParentActor = std::move(mParentActor);
1436 aThread = std::move(mThread);
1437 return NS_OK;
1440 nsresult ParentImpl::CreateActorHelper::RunOnMainThread() {
1441 AssertIsOnMainThread();
1443 if (!sBackgroundThread && !CreateBackgroundThread()) {
1444 NS_WARNING("Failed to create background thread!");
1445 return NS_ERROR_FAILURE;
1448 MOZ_ASSERT(!sShutdownHasStarted);
1450 sLiveActorCount++;
1452 mParentActor = new ParentImpl();
1453 mThread = sBackgroundThread;
1455 return NS_OK;
1458 NS_IMETHODIMP
1459 ParentImpl::CreateActorHelper::Run() {
1460 AssertIsOnMainThread();
1462 nsresult rv = RunOnMainThread();
1463 if (NS_WARN_IF(NS_FAILED(rv))) {
1464 mMainThreadResultCode = rv;
1467 mozilla::MonitorAutoLock lock(mMonitor);
1468 MOZ_ASSERT(mWaiting);
1470 mWaiting = false;
1471 lock.Notify();
1473 return NS_OK;
1476 // -----------------------------------------------------------------------------
1477 // ChildImpl Implementation
1478 // -----------------------------------------------------------------------------
1480 // static
1481 void ChildImpl::Startup() {
1482 // This happens on the main thread but before XPCOM has started so we can't
1483 // assert that we're being called on the main thread here.
1485 sParentAndContentProcessThreadInfo.Startup();
1486 sSocketAndContentProcessThreadInfo.Startup();
1487 sSocketAndParentProcessThreadInfo.Startup();
1489 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1490 MOZ_RELEASE_ASSERT(observerService);
1492 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1494 nsresult rv = observerService->AddObserver(
1495 observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1496 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1499 // static
1500 void ChildImpl::Shutdown() {
1501 AssertIsOnMainThread();
1503 sParentAndContentProcessThreadInfo.Shutdown();
1504 sSocketAndContentProcessThreadInfo.Shutdown();
1505 sSocketAndParentProcessThreadInfo.Shutdown();
1507 sShutdownHasStarted = true;
1510 // static
1511 PBackgroundChild* ChildImpl::GetForCurrentThread() {
1512 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1513 kBadThreadLocalIndex);
1515 auto threadLocalInfo =
1516 NS_IsMainThread()
1517 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1518 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1519 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1521 if (!threadLocalInfo) {
1522 return nullptr;
1525 return threadLocalInfo->mActor;
1528 /* static */
1529 PBackgroundChild* ChildImpl::GetFromThreadInfo(
1530 nsIEventTarget* aMainEventTarget, ThreadLocalInfo* aThreadLocalInfo) {
1531 MOZ_ASSERT(aThreadLocalInfo);
1533 if (aThreadLocalInfo->mActor) {
1534 RefPtr<SendInitBackgroundRunnable>& runnable =
1535 aThreadLocalInfo->mSendInitBackgroundRunnable;
1537 if (aMainEventTarget && runnable) {
1538 // The SendInitBackgroundRunnable was already dispatched to the main
1539 // thread to finish initialization of a new background child actor.
1540 // However, the caller passed a custom main event target which indicates
1541 // that synchronous blocking of the main thread is happening (done by
1542 // creating a nested event target and spinning the event loop).
1543 // It can happen that the SendInitBackgroundRunnable didn't have a chance
1544 // to run before the synchronous blocking has occured. Unblocking of the
1545 // main thread can depend on an IPC message received on this thread, so
1546 // we have to dispatch the SendInitBackgroundRunnable to the custom main
1547 // event target too, otherwise IPC will be only queueing messages on this
1548 // thread. The runnable will run twice in the end, but that's a harmless
1549 // race between the main and nested event queue of the main thread.
1550 // There's a guard in the runnable implementation for calling
1551 // SendInitBackground only once.
1553 MOZ_ALWAYS_SUCCEEDS(
1554 aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
1557 return aThreadLocalInfo->mActor;
1560 return nullptr;
1563 /* static */
1564 PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread(
1565 nsIEventTarget* aMainEventTarget) {
1566 return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
1567 aMainEventTarget);
1570 /* static */
1571 PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread(
1572 nsIEventTarget* aMainEventTarget) {
1573 return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
1574 aMainEventTarget);
1577 /* static */
1578 PBackgroundChild* ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
1579 nsIEventTarget* aMainEventTarget) {
1580 return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread(
1581 aMainEventTarget);
1584 // static
1585 void ChildImpl::CloseForCurrentThread() {
1586 MOZ_ASSERT(!NS_IsMainThread(),
1587 "PBackground for the main thread should be shut down via "
1588 "ChildImpl::Shutdown().");
1590 sParentAndContentProcessThreadInfo.CloseForCurrentThread();
1591 sSocketAndContentProcessThreadInfo.CloseForCurrentThread();
1592 sSocketAndParentProcessThreadInfo.CloseForCurrentThread();
1595 // static
1596 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
1597 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1598 kBadThreadLocalIndex,
1599 "BackgroundChild::Startup() was never called!");
1601 auto threadLocalInfo =
1602 NS_IsMainThread()
1603 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1604 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1605 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1607 if (!threadLocalInfo) {
1608 return nullptr;
1611 if (!threadLocalInfo->mConsumerThreadLocal) {
1612 threadLocalInfo->mConsumerThreadLocal =
1613 MakeUnique<BackgroundChildImpl::ThreadLocal>();
1616 return threadLocalInfo->mConsumerThreadLocal.get();
1619 // static
1620 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) {
1621 auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
1623 if (threadLocalInfo) {
1624 MOZ_ASSERT(threadLocalInfo->mClosed);
1626 if (threadLocalInfo->mActor) {
1627 threadLocalInfo->mActor->Close();
1628 threadLocalInfo->mActor->AssertActorDestroyed();
1631 if (threadLocalInfo->mSendInitBackgroundRunnable) {
1632 threadLocalInfo->mSendInitBackgroundRunnable->ClearEventTarget();
1635 delete threadLocalInfo;
1639 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy) {
1640 AssertIsOnOwningThread();
1642 #ifdef DEBUG
1643 MOZ_ASSERT(!mActorDestroyed);
1644 mActorDestroyed = true;
1645 #endif
1647 BackgroundChildImpl::ActorDestroy(aWhy);
1650 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1652 NS_IMETHODIMP
1653 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1654 const char16_t* aData) {
1655 AssertIsOnMainThread();
1656 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1658 ChildImpl::Shutdown();
1660 return NS_OK;
1663 // static
1664 already_AddRefed<ChildImpl::SendInitBackgroundRunnable>
1665 ChildImpl::SendInitBackgroundRunnable::Create(
1666 Endpoint<PBackgroundParent>&& aParent,
1667 std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
1668 unsigned int aThreadLocalIndex) {
1669 MOZ_ASSERT(!NS_IsMainThread());
1671 RefPtr<SendInitBackgroundRunnable> runnable = new SendInitBackgroundRunnable(
1672 std::move(aParent), std::move(aFunc), aThreadLocalIndex);
1674 WorkerPrivate* workerPrivate = mozilla::dom::GetCurrentThreadWorkerPrivate();
1675 if (!workerPrivate) {
1676 return runnable.forget();
1679 workerPrivate->AssertIsOnWorkerThread();
1681 runnable->mWorkerRef = StrongWorkerRef::Create(
1682 workerPrivate, "ChildImpl::SendInitBackgroundRunnable");
1683 if (NS_WARN_IF(!runnable->mWorkerRef)) {
1684 return nullptr;
1687 return runnable.forget();
1690 NS_IMETHODIMP
1691 ChildImpl::SendInitBackgroundRunnable::Run() {
1692 if (NS_IsMainThread()) {
1693 if (mSentInitBackground) {
1694 return NS_OK;
1697 mSentInitBackground = true;
1699 mSendInitfunc(std::move(mParent));
1701 nsCOMPtr<nsISerialEventTarget> owningEventTarget;
1703 mozilla::MutexAutoLock lock(mMutex);
1704 owningEventTarget = mOwningEventTarget;
1707 if (!owningEventTarget) {
1708 return NS_OK;
1711 nsresult rv = owningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
1712 if (NS_WARN_IF(NS_FAILED(rv))) {
1713 return rv;
1716 return NS_OK;
1719 ClearEventTarget();
1721 auto threadLocalInfo =
1722 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
1724 if (!threadLocalInfo) {
1725 return NS_OK;
1728 threadLocalInfo->mSendInitBackgroundRunnable = nullptr;
1730 return NS_OK;