Line data Source code
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/. */
6 :
7 : #include "BackgroundChild.h"
8 : #include "BackgroundParent.h"
9 :
10 : #include "BackgroundChildImpl.h"
11 : #include "BackgroundParentImpl.h"
12 : #include "base/process_util.h"
13 : #include "base/task.h"
14 : #include "FileDescriptor.h"
15 : #include "GeckoProfiler.h"
16 : #include "InputStreamUtils.h"
17 : #include "mozilla/Assertions.h"
18 : #include "mozilla/Atomics.h"
19 : #include "mozilla/ClearOnShutdown.h"
20 : #include "mozilla/DebugOnly.h"
21 : #include "mozilla/Services.h"
22 : #include "mozilla/StaticPtr.h"
23 : #include "mozilla/Unused.h"
24 : #include "mozilla/dom/ContentChild.h"
25 : #include "mozilla/dom/ContentParent.h"
26 : #include "mozilla/dom/File.h"
27 : #include "mozilla/ipc/ProtocolTypes.h"
28 : #include "nsAutoPtr.h"
29 : #include "nsCOMPtr.h"
30 : #include "nsIEventTarget.h"
31 : #include "nsIIPCBackgroundChildCreateCallback.h"
32 : #include "nsIMutable.h"
33 : #include "nsIObserver.h"
34 : #include "nsIObserverService.h"
35 : #include "nsIRunnable.h"
36 : #include "nsISupportsImpl.h"
37 : #include "nsIThread.h"
38 : #include "nsITimer.h"
39 : #include "nsTArray.h"
40 : #include "nsThreadUtils.h"
41 : #include "nsTraceRefcnt.h"
42 : #include "nsXULAppAPI.h"
43 : #include "nsXPCOMPrivate.h"
44 : #include "prthread.h"
45 :
46 : #ifdef RELEASE_OR_BETA
47 : #define THREADSAFETY_ASSERT MOZ_ASSERT
48 : #else
49 : #define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
50 : #endif
51 :
52 : #define CRASH_IN_CHILD_PROCESS(_msg) \
53 : do { \
54 : if (XRE_IsParentProcess()) { \
55 : MOZ_ASSERT(false, _msg); \
56 : } else { \
57 : MOZ_CRASH(_msg); \
58 : } \
59 : } \
60 : while (0)
61 :
62 : using namespace mozilla;
63 : using namespace mozilla::dom;
64 : using namespace mozilla::ipc;
65 :
66 : namespace {
67 :
68 : // -----------------------------------------------------------------------------
69 : // Utility Functions
70 : // -----------------------------------------------------------------------------
71 :
72 :
73 : void
74 30 : AssertIsInMainProcess()
75 : {
76 30 : MOZ_ASSERT(XRE_IsParentProcess());
77 30 : }
78 :
79 : void
80 5 : AssertIsInChildProcess()
81 : {
82 5 : MOZ_ASSERT(!XRE_IsParentProcess());
83 5 : }
84 :
85 : void
86 44 : AssertIsOnMainThread()
87 : {
88 44 : THREADSAFETY_ASSERT(NS_IsMainThread());
89 44 : }
90 :
91 : // -----------------------------------------------------------------------------
92 : // ParentImpl Declaration
93 : // -----------------------------------------------------------------------------
94 :
95 : class ParentImpl final : public BackgroundParentImpl
96 : {
97 : friend class mozilla::ipc::BackgroundParent;
98 :
99 : public:
100 : class CreateCallback;
101 :
102 : private:
103 : class ShutdownObserver;
104 : class RequestMessageLoopRunnable;
105 : class ShutdownBackgroundThreadRunnable;
106 : class ForceCloseBackgroundActorsRunnable;
107 : class CreateCallbackRunnable;
108 : class ConnectActorRunnable;
109 :
110 : struct MOZ_STACK_CLASS TimerCallbackClosure
111 : {
112 : nsIThread* mThread;
113 : nsTArray<ParentImpl*>* mLiveActors;
114 :
115 0 : TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
116 0 : : mThread(aThread), mLiveActors(aLiveActors)
117 : {
118 0 : AssertIsInMainProcess();
119 0 : AssertIsOnMainThread();
120 0 : MOZ_ASSERT(aThread);
121 0 : MOZ_ASSERT(aLiveActors);
122 0 : }
123 : };
124 :
125 : // The length of time we will wait at shutdown for all actors to clean
126 : // themselves up before forcing them to be destroyed.
127 : static const uint32_t kShutdownTimerDelayMS = 10000;
128 :
129 : // This is only modified on the main thread. It is null if the thread does not
130 : // exist or is shutting down.
131 : static StaticRefPtr<nsIThread> sBackgroundThread;
132 :
133 : // This is created and destroyed on the main thread but only modified on the
134 : // background thread. It is specific to each instance of sBackgroundThread.
135 : static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
136 :
137 : // This is only modified on the main thread.
138 : static StaticRefPtr<nsITimer> sShutdownTimer;
139 :
140 : // This exists so that that [Assert]IsOnBackgroundThread() can continue to
141 : // work during shutdown.
142 : static Atomic<PRThread*> sBackgroundPRThread;
143 :
144 : // This is only modified on the main thread. It is null if the thread does not
145 : // exist or is shutting down.
146 : static MessageLoop* sBackgroundThreadMessageLoop;
147 :
148 : // This is only modified on the main thread. It maintains a count of live
149 : // actors so that the background thread can be shut down when it is no longer
150 : // needed.
151 : static uint64_t sLiveActorCount;
152 :
153 : // This is only modified on the main thread. It is true after the shutdown
154 : // observer is registered and is never unset thereafter.
155 : static bool sShutdownObserverRegistered;
156 :
157 : // This is only modified on the main thread. It prevents us from trying to
158 : // create the background thread after application shutdown has started.
159 : static bool sShutdownHasStarted;
160 :
161 : // This is only modified on the main thread. It is a FIFO queue for callbacks
162 : // waiting for the background thread to be created.
163 : static StaticAutoPtr<nsTArray<RefPtr<CreateCallback>>> sPendingCallbacks;
164 :
165 : // Only touched on the main thread, null if this is a same-process actor.
166 : RefPtr<ContentParent> mContent;
167 :
168 : // Set when the actor is opened successfully and used to handle shutdown
169 : // hangs. Only touched on the background thread.
170 : nsTArray<ParentImpl*>* mLiveActorArray;
171 :
172 : // Set at construction to indicate whether this parent actor corresponds to a
173 : // child actor in another process or to a child actor from a different thread
174 : // in the same process.
175 : const bool mIsOtherProcessActor;
176 :
177 : // Set after ActorDestroy has been called. Only touched on the background
178 : // thread.
179 : bool mActorDestroyed;
180 :
181 : public:
182 : static bool
183 : CreateActorForSameProcess(CreateCallback* aCallback);
184 :
185 : static bool
186 179 : IsOnBackgroundThread()
187 : {
188 179 : return PR_GetCurrentThread() == sBackgroundPRThread;
189 : }
190 :
191 : static void
192 98 : AssertIsOnBackgroundThread()
193 : {
194 98 : THREADSAFETY_ASSERT(IsOnBackgroundThread());
195 98 : }
196 :
197 8 : NS_INLINE_DECL_REFCOUNTING(ParentImpl)
198 :
199 : void
200 : Destroy();
201 :
202 : private:
203 : // Forwarded from BackgroundParent.
204 : static bool
205 : IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
206 :
207 : // Forwarded from BackgroundParent.
208 : static already_AddRefed<ContentParent>
209 : GetContentParent(PBackgroundParent* aBackgroundActor);
210 :
211 : // Forwarded from BackgroundParent.
212 : static intptr_t
213 : GetRawContentParentForComparison(PBackgroundParent* aBackgroundActor);
214 :
215 : // Forwarded from BackgroundParent.
216 : static uint64_t
217 : GetChildID(PBackgroundParent* aBackgroundActor);
218 :
219 : // Forwarded from BackgroundParent.
220 : static bool
221 : Alloc(ContentParent* aContent,
222 : Endpoint<PBackgroundParent>&& aEndpoint);
223 :
224 : static bool
225 : CreateBackgroundThread();
226 :
227 : static void
228 : ShutdownBackgroundThread();
229 :
230 : static void
231 : ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
232 :
233 : // For same-process actors.
234 2 : ParentImpl()
235 2 : : mLiveActorArray(nullptr), mIsOtherProcessActor(false),
236 2 : mActorDestroyed(false)
237 : {
238 2 : AssertIsInMainProcess();
239 2 : AssertIsOnMainThread();
240 2 : }
241 :
242 : // For other-process actors.
243 2 : explicit ParentImpl(ContentParent* aContent)
244 2 : : mContent(aContent), mLiveActorArray(nullptr),
245 2 : mIsOtherProcessActor(true), mActorDestroyed(false)
246 : {
247 2 : AssertIsInMainProcess();
248 2 : AssertIsOnMainThread();
249 2 : MOZ_ASSERT(aContent);
250 2 : }
251 :
252 0 : ~ParentImpl()
253 0 : {
254 0 : AssertIsInMainProcess();
255 0 : AssertIsOnMainThread();
256 0 : MOZ_ASSERT(!mContent);
257 0 : }
258 :
259 : void
260 : MainThreadActorDestroy();
261 :
262 : void
263 2 : SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray)
264 : {
265 2 : AssertIsInMainProcess();
266 2 : AssertIsOnBackgroundThread();
267 2 : MOZ_ASSERT(aLiveActorArray);
268 2 : MOZ_ASSERT(!aLiveActorArray->Contains(this));
269 2 : MOZ_ASSERT(!mLiveActorArray);
270 2 : MOZ_ASSERT(mIsOtherProcessActor);
271 :
272 2 : mLiveActorArray = aLiveActorArray;
273 2 : mLiveActorArray->AppendElement(this);
274 2 : }
275 :
276 : // These methods are only called by IPDL.
277 : virtual void
278 : ActorDestroy(ActorDestroyReason aWhy) override;
279 : };
280 :
281 : // -----------------------------------------------------------------------------
282 : // ChildImpl Declaration
283 : // -----------------------------------------------------------------------------
284 :
285 : class ChildImpl final : public BackgroundChildImpl
286 : {
287 : friend class mozilla::ipc::BackgroundChild;
288 : friend class mozilla::ipc::BackgroundChildImpl;
289 :
290 : typedef base::ProcessId ProcessId;
291 : typedef mozilla::ipc::Transport Transport;
292 :
293 : class ShutdownObserver;
294 : class CreateActorRunnable;
295 : class ParentCreateCallback;
296 : class AlreadyCreatedCallbackRunnable;
297 : class FailedCreateCallbackRunnable;
298 : class OpenChildProcessActorRunnable;
299 : class OpenMainProcessActorRunnable;
300 :
301 : // A thread-local index that is not valid.
302 : static const unsigned int kBadThreadLocalIndex =
303 : static_cast<unsigned int>(-1);
304 :
305 : // This is only modified on the main thread. It is the thread-local index that
306 : // we use to store the BackgroundChild for each thread.
307 : static unsigned int sThreadLocalIndex;
308 :
309 0 : struct ThreadLocalInfo
310 : {
311 5 : explicit ThreadLocalInfo(nsIIPCBackgroundChildCreateCallback* aCallback)
312 : #ifdef DEBUG
313 5 : : mClosed(false)
314 : #endif
315 : {
316 5 : mCallbacks.AppendElement(aCallback);
317 5 : }
318 :
319 : RefPtr<ChildImpl> mActor;
320 : nsTArray<nsCOMPtr<nsIIPCBackgroundChildCreateCallback>> mCallbacks;
321 : nsAutoPtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
322 : #ifdef DEBUG
323 : bool mClosed;
324 : #endif
325 : };
326 :
327 : // This is only modified on the main thread. It is a FIFO queue for actors
328 : // that are in the process of construction.
329 : static StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> sPendingTargets;
330 :
331 : // This is only modified on the main thread. It prevents us from trying to
332 : // create the background thread after application shutdown has started.
333 : static bool sShutdownHasStarted;
334 :
335 : #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
336 : nsISerialEventTarget* mBoundEventTarget;
337 : #endif
338 :
339 : #ifdef DEBUG
340 : bool mActorDestroyed;
341 : #endif
342 :
343 : public:
344 : static bool
345 : OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
346 :
347 : static void
348 : Shutdown();
349 :
350 : void
351 0 : AssertIsOnBoundThread()
352 : {
353 0 : THREADSAFETY_ASSERT(mBoundEventTarget);
354 :
355 : #ifdef RELEASE_OR_BETA
356 : DebugOnly<bool> current;
357 : #else
358 : bool current;
359 : #endif
360 0 : THREADSAFETY_ASSERT(
361 : NS_SUCCEEDED(mBoundEventTarget->IsOnCurrentThread(¤t)));
362 0 : THREADSAFETY_ASSERT(current);
363 0 : }
364 :
365 : void
366 0 : AssertActorDestroyed()
367 : {
368 0 : MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
369 0 : }
370 :
371 5 : ChildImpl()
372 : #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
373 5 : : mBoundEventTarget(nullptr)
374 : #endif
375 : #ifdef DEBUG
376 5 : , mActorDestroyed(false)
377 : #endif
378 : {
379 5 : AssertIsOnMainThread();
380 5 : }
381 :
382 5 : NS_INLINE_DECL_REFCOUNTING(ChildImpl)
383 :
384 : private:
385 : // Forwarded from BackgroundChild.
386 : static void
387 : Startup();
388 :
389 : static void
390 : Alloc(Endpoint<PBackgroundChild>&& aEndpoint);
391 :
392 : // Forwarded from BackgroundChild.
393 : static PBackgroundChild*
394 : GetForCurrentThread();
395 :
396 : // Forwarded from BackgroundChild.
397 : static bool
398 : GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
399 :
400 : // Forwarded from BackgroundChild.
401 : static PBackgroundChild*
402 : SynchronouslyCreateForCurrentThread();
403 :
404 : // Forwarded from BackgroundChild.
405 : static void
406 : CloseForCurrentThread();
407 :
408 : // Forwarded from BackgroundChildImpl.
409 : static BackgroundChildImpl::ThreadLocal*
410 : GetThreadLocalForCurrentThread();
411 :
412 : static void
413 0 : ThreadLocalDestructor(void* aThreadLocal)
414 : {
415 0 : auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
416 :
417 0 : if (threadLocalInfo) {
418 0 : MOZ_ASSERT(threadLocalInfo->mClosed);
419 :
420 0 : if (threadLocalInfo->mActor) {
421 0 : threadLocalInfo->mActor->Close();
422 0 : threadLocalInfo->mActor->AssertActorDestroyed();
423 :
424 : // Since the actor is created on the main thread it must only
425 : // be released on the main thread as well.
426 0 : if (!NS_IsMainThread()) {
427 : ChildImpl* actor;
428 0 : threadLocalInfo->mActor.forget(&actor);
429 :
430 0 : MOZ_ALWAYS_SUCCEEDS(
431 : NS_DispatchToMainThread(NewNonOwningRunnableMethod("ChildImpl::Release",
432 : actor, &ChildImpl::Release)));
433 : }
434 : }
435 0 : delete threadLocalInfo;
436 : }
437 0 : }
438 :
439 : static void
440 : DispatchFailureCallback(nsIEventTarget* aEventTarget);
441 :
442 : // This class is reference counted.
443 0 : ~ChildImpl()
444 0 : {
445 0 : AssertActorDestroyed();
446 0 : }
447 :
448 : void
449 4 : SetBoundThread()
450 : {
451 4 : THREADSAFETY_ASSERT(!mBoundEventTarget);
452 :
453 : #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
454 4 : mBoundEventTarget = GetCurrentThreadSerialEventTarget();
455 : #endif
456 :
457 4 : THREADSAFETY_ASSERT(mBoundEventTarget);
458 4 : }
459 :
460 : // Only called by IPDL.
461 : virtual void
462 : ActorDestroy(ActorDestroyReason aWhy) override;
463 :
464 : static already_AddRefed<nsIIPCBackgroundChildCreateCallback>
465 : GetNextCallback();
466 : };
467 :
468 : // -----------------------------------------------------------------------------
469 : // ParentImpl Helper Declarations
470 : // -----------------------------------------------------------------------------
471 :
472 : class ParentImpl::ShutdownObserver final : public nsIObserver
473 : {
474 : public:
475 1 : ShutdownObserver()
476 1 : {
477 1 : AssertIsOnMainThread();
478 1 : }
479 :
480 : NS_DECL_ISUPPORTS
481 : NS_DECL_NSIOBSERVER
482 :
483 : private:
484 0 : ~ShutdownObserver()
485 0 : {
486 0 : AssertIsOnMainThread();
487 0 : }
488 : };
489 :
490 : class ParentImpl::RequestMessageLoopRunnable final : public Runnable
491 : {
492 : nsCOMPtr<nsIThread> mTargetThread;
493 : MessageLoop* mMessageLoop;
494 :
495 : public:
496 1 : explicit RequestMessageLoopRunnable(nsIThread* aTargetThread)
497 1 : : Runnable("Background::ParentImpl::RequestMessageLoopRunnable")
498 : , mTargetThread(aTargetThread)
499 1 : , mMessageLoop(nullptr)
500 : {
501 1 : AssertIsInMainProcess();
502 1 : AssertIsOnMainThread();
503 1 : MOZ_ASSERT(aTargetThread);
504 1 : }
505 :
506 : private:
507 2 : ~RequestMessageLoopRunnable()
508 3 : { }
509 :
510 : NS_DECL_NSIRUNNABLE
511 : };
512 :
513 : class ParentImpl::ShutdownBackgroundThreadRunnable final : public Runnable
514 : {
515 : public:
516 0 : ShutdownBackgroundThreadRunnable()
517 0 : : Runnable("Background::ParentImpl::ShutdownBackgroundThreadRunnable")
518 : {
519 0 : AssertIsInMainProcess();
520 0 : AssertIsOnMainThread();
521 0 : }
522 :
523 : private:
524 0 : ~ShutdownBackgroundThreadRunnable()
525 0 : { }
526 :
527 : NS_DECL_NSIRUNNABLE
528 : };
529 :
530 : class ParentImpl::ForceCloseBackgroundActorsRunnable final : public Runnable
531 : {
532 : nsTArray<ParentImpl*>* mActorArray;
533 :
534 : public:
535 0 : explicit ForceCloseBackgroundActorsRunnable(nsTArray<ParentImpl*>* aActorArray)
536 0 : : Runnable("Background::ParentImpl::ForceCloseBackgroundActorsRunnable")
537 0 : , mActorArray(aActorArray)
538 : {
539 0 : AssertIsInMainProcess();
540 0 : AssertIsOnMainThread();
541 0 : MOZ_ASSERT(aActorArray);
542 0 : }
543 :
544 : private:
545 0 : ~ForceCloseBackgroundActorsRunnable()
546 0 : { }
547 :
548 : NS_DECL_NSIRUNNABLE
549 : };
550 :
551 : class ParentImpl::CreateCallbackRunnable final : public Runnable
552 : {
553 : RefPtr<CreateCallback> mCallback;
554 :
555 : public:
556 2 : explicit CreateCallbackRunnable(CreateCallback* aCallback)
557 2 : : Runnable("Background::ParentImpl::CreateCallbackRunnable")
558 2 : , mCallback(aCallback)
559 : {
560 2 : AssertIsInMainProcess();
561 2 : AssertIsOnMainThread();
562 2 : MOZ_ASSERT(aCallback);
563 2 : }
564 :
565 : private:
566 4 : ~CreateCallbackRunnable()
567 6 : { }
568 :
569 : NS_DECL_NSIRUNNABLE
570 : };
571 :
572 : class ParentImpl::ConnectActorRunnable final : public Runnable
573 : {
574 : RefPtr<ParentImpl> mActor;
575 : Endpoint<PBackgroundParent> mEndpoint;
576 : nsTArray<ParentImpl*>* mLiveActorArray;
577 :
578 : public:
579 2 : ConnectActorRunnable(ParentImpl* aActor,
580 : Endpoint<PBackgroundParent>&& aEndpoint,
581 : nsTArray<ParentImpl*>* aLiveActorArray)
582 2 : : Runnable("Background::ParentImpl::ConnectActorRunnable")
583 : , mActor(aActor)
584 2 : , mEndpoint(Move(aEndpoint))
585 4 : , mLiveActorArray(aLiveActorArray)
586 : {
587 2 : AssertIsInMainProcess();
588 2 : AssertIsOnMainThread();
589 2 : MOZ_ASSERT(mEndpoint.IsValid());
590 2 : MOZ_ASSERT(aLiveActorArray);
591 2 : }
592 :
593 : private:
594 4 : ~ConnectActorRunnable()
595 4 : {
596 2 : AssertIsInMainProcess();
597 6 : }
598 :
599 : NS_DECL_NSIRUNNABLE
600 : };
601 :
602 2 : class NS_NO_VTABLE ParentImpl::CreateCallback
603 : {
604 : public:
605 10 : NS_INLINE_DECL_REFCOUNTING(CreateCallback)
606 :
607 : virtual void
608 : Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop) = 0;
609 :
610 : virtual void
611 : Failure() = 0;
612 :
613 : protected:
614 2 : virtual ~CreateCallback()
615 2 : { }
616 : };
617 :
618 : // -----------------------------------------------------------------------------
619 : // ChildImpl Helper Declarations
620 : // -----------------------------------------------------------------------------
621 :
622 : class ChildImpl::ShutdownObserver final : public nsIObserver
623 : {
624 : public:
625 3 : ShutdownObserver()
626 3 : {
627 3 : AssertIsOnMainThread();
628 3 : }
629 :
630 : NS_DECL_ISUPPORTS
631 : NS_DECL_NSIOBSERVER
632 :
633 : private:
634 0 : ~ShutdownObserver()
635 0 : {
636 0 : AssertIsOnMainThread();
637 0 : }
638 : };
639 :
640 : class ChildImpl::CreateActorRunnable final : public Runnable
641 : {
642 : nsCOMPtr<nsIEventTarget> mEventTarget;
643 :
644 : public:
645 2 : CreateActorRunnable()
646 2 : : Runnable("Background::ChildImpl::CreateActorRunnable")
647 2 : , mEventTarget(NS_GetCurrentThread())
648 : {
649 2 : MOZ_ASSERT(mEventTarget);
650 2 : }
651 :
652 : private:
653 4 : ~CreateActorRunnable()
654 6 : { }
655 :
656 : NS_DECL_NSIRUNNABLE
657 : };
658 :
659 : class ChildImpl::ParentCreateCallback final :
660 : public ParentImpl::CreateCallback
661 : {
662 : nsCOMPtr<nsIEventTarget> mEventTarget;
663 :
664 : public:
665 2 : explicit ParentCreateCallback(nsIEventTarget* aEventTarget)
666 2 : : mEventTarget(aEventTarget)
667 : {
668 2 : AssertIsInMainProcess();
669 2 : AssertIsOnMainThread();
670 2 : MOZ_ASSERT(aEventTarget);
671 2 : }
672 :
673 : private:
674 4 : ~ParentCreateCallback()
675 6 : { }
676 :
677 : virtual void
678 : Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop)
679 : override;
680 :
681 : virtual void
682 : Failure() override;
683 : };
684 :
685 : // Must be cancelable in order to dispatch on active worker threads
686 : class ChildImpl::AlreadyCreatedCallbackRunnable final :
687 : public CancelableRunnable
688 : {
689 : public:
690 2 : AlreadyCreatedCallbackRunnable()
691 2 : : CancelableRunnable("Background::ChildImpl::AlreadyCreatedCallbackRunnable")
692 : {
693 : // May be created on any thread!
694 2 : }
695 :
696 : protected:
697 4 : virtual ~AlreadyCreatedCallbackRunnable()
698 6 : { }
699 :
700 : NS_DECL_NSIRUNNABLE
701 : nsresult Cancel() override;
702 : };
703 :
704 : class ChildImpl::FailedCreateCallbackRunnable final : public Runnable
705 : {
706 : public:
707 0 : FailedCreateCallbackRunnable()
708 0 : : Runnable("Background::ChildImpl::FailedCreateCallbackRunnable")
709 : {
710 : // May be created on any thread!
711 0 : }
712 :
713 : protected:
714 0 : virtual ~FailedCreateCallbackRunnable()
715 0 : { }
716 :
717 : NS_DECL_NSIRUNNABLE
718 : };
719 :
720 : class ChildImpl::OpenChildProcessActorRunnable final : public Runnable
721 : {
722 : RefPtr<ChildImpl> mActor;
723 : Endpoint<PBackgroundChild> mEndpoint;
724 :
725 : public:
726 3 : OpenChildProcessActorRunnable(already_AddRefed<ChildImpl>&& aActor,
727 : Endpoint<PBackgroundChild>&& aEndpoint)
728 3 : : Runnable("Background::ChildImpl::OpenChildProcessActorRunnable")
729 : , mActor(aActor)
730 3 : , mEndpoint(Move(aEndpoint))
731 : {
732 3 : AssertIsOnMainThread();
733 3 : MOZ_ASSERT(mActor);
734 3 : MOZ_ASSERT(mEndpoint.IsValid());
735 3 : }
736 :
737 : private:
738 4 : ~OpenChildProcessActorRunnable()
739 4 : {
740 2 : if (mEndpoint.IsValid()) {
741 0 : CRASH_IN_CHILD_PROCESS("Leaking endpoint!");
742 : }
743 6 : }
744 :
745 : NS_DECL_NSIRUNNABLE
746 : };
747 :
748 : class ChildImpl::OpenMainProcessActorRunnable final : public Runnable
749 : {
750 : RefPtr<ChildImpl> mActor;
751 : RefPtr<ParentImpl> mParentActor;
752 : MessageLoop* mParentMessageLoop;
753 :
754 : public:
755 2 : OpenMainProcessActorRunnable(already_AddRefed<ChildImpl>&& aChildActor,
756 : already_AddRefed<ParentImpl> aParentActor,
757 : MessageLoop* aParentMessageLoop)
758 2 : : Runnable("ChildImpl::OpenMainProcessActorRunnable"),
759 : mActor(aChildActor), mParentActor(aParentActor),
760 2 : mParentMessageLoop(aParentMessageLoop)
761 : {
762 2 : AssertIsOnMainThread();
763 2 : MOZ_ASSERT(mParentActor);
764 2 : MOZ_ASSERT(aParentMessageLoop);
765 2 : }
766 :
767 : private:
768 4 : ~OpenMainProcessActorRunnable()
769 6 : { }
770 :
771 : NS_DECL_NSIRUNNABLE
772 : };
773 :
774 : } // namespace
775 :
776 : namespace mozilla {
777 : namespace ipc {
778 :
779 : bool
780 81 : IsOnBackgroundThread()
781 : {
782 81 : return ParentImpl::IsOnBackgroundThread();
783 : }
784 :
785 : #ifdef DEBUG
786 :
787 : void
788 94 : AssertIsOnBackgroundThread()
789 : {
790 94 : ParentImpl::AssertIsOnBackgroundThread();
791 94 : }
792 :
793 : #endif // DEBUG
794 :
795 : } // namespace ipc
796 : } // namespace mozilla
797 :
798 : // -----------------------------------------------------------------------------
799 : // BackgroundParent Public Methods
800 : // -----------------------------------------------------------------------------
801 :
802 : // static
803 : bool
804 0 : BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
805 : {
806 0 : return ParentImpl::IsOtherProcessActor(aBackgroundActor);
807 : }
808 :
809 : // static
810 : already_AddRefed<ContentParent>
811 0 : BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor)
812 : {
813 0 : return ParentImpl::GetContentParent(aBackgroundActor);
814 : }
815 :
816 : // static
817 : intptr_t
818 0 : BackgroundParent::GetRawContentParentForComparison(
819 : PBackgroundParent* aBackgroundActor)
820 : {
821 0 : return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
822 : }
823 :
824 : // static
825 : uint64_t
826 0 : BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor)
827 : {
828 0 : return ParentImpl::GetChildID(aBackgroundActor);
829 : }
830 :
831 : // static
832 : bool
833 2 : BackgroundParent::Alloc(ContentParent* aContent,
834 : Endpoint<PBackgroundParent>&& aEndpoint)
835 : {
836 2 : return ParentImpl::Alloc(aContent, Move(aEndpoint));
837 : }
838 :
839 : // -----------------------------------------------------------------------------
840 : // BackgroundChild Public Methods
841 : // -----------------------------------------------------------------------------
842 :
843 : // static
844 : void
845 3 : BackgroundChild::Startup()
846 : {
847 3 : ChildImpl::Startup();
848 3 : }
849 :
850 : // static
851 : PBackgroundChild*
852 2 : BackgroundChild::GetForCurrentThread()
853 : {
854 2 : return ChildImpl::GetForCurrentThread();
855 : }
856 :
857 : // static
858 : bool
859 9 : BackgroundChild::GetOrCreateForCurrentThread(
860 : nsIIPCBackgroundChildCreateCallback* aCallback)
861 : {
862 9 : return ChildImpl::GetOrCreateForCurrentThread(aCallback);
863 : }
864 :
865 : // static
866 : PBackgroundChild*
867 1 : BackgroundChild::SynchronouslyCreateForCurrentThread()
868 : {
869 1 : return ChildImpl::SynchronouslyCreateForCurrentThread();
870 : }
871 :
872 : // static
873 : void
874 1 : BackgroundChild::CloseForCurrentThread()
875 : {
876 1 : ChildImpl::CloseForCurrentThread();
877 1 : }
878 :
879 : // -----------------------------------------------------------------------------
880 : // BackgroundChildImpl Public Methods
881 : // -----------------------------------------------------------------------------
882 :
883 : // static
884 : BackgroundChildImpl::ThreadLocal*
885 0 : BackgroundChildImpl::GetThreadLocalForCurrentThread()
886 : {
887 0 : return ChildImpl::GetThreadLocalForCurrentThread();
888 : }
889 :
890 : // -----------------------------------------------------------------------------
891 : // ParentImpl Static Members
892 : // -----------------------------------------------------------------------------
893 :
894 3 : StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
895 :
896 : nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
897 :
898 3 : StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
899 :
900 : Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
901 :
902 : MessageLoop* ParentImpl::sBackgroundThreadMessageLoop = nullptr;
903 :
904 : uint64_t ParentImpl::sLiveActorCount = 0;
905 :
906 : bool ParentImpl::sShutdownObserverRegistered = false;
907 :
908 : bool ParentImpl::sShutdownHasStarted = false;
909 :
910 : StaticAutoPtr<nsTArray<RefPtr<ParentImpl::CreateCallback>>>
911 3 : ParentImpl::sPendingCallbacks;
912 :
913 : // -----------------------------------------------------------------------------
914 : // ChildImpl Static Members
915 : // -----------------------------------------------------------------------------
916 :
917 : unsigned int ChildImpl::sThreadLocalIndex = kBadThreadLocalIndex;
918 :
919 3 : StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> ChildImpl::sPendingTargets;
920 :
921 : bool ChildImpl::sShutdownHasStarted = false;
922 :
923 : // -----------------------------------------------------------------------------
924 : // ParentImpl Implementation
925 : // -----------------------------------------------------------------------------
926 :
927 : // static
928 : bool
929 0 : ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
930 : {
931 0 : AssertIsOnBackgroundThread();
932 0 : MOZ_ASSERT(aBackgroundActor);
933 :
934 0 : return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
935 : }
936 :
937 : // static
938 : already_AddRefed<ContentParent>
939 0 : ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor)
940 : {
941 0 : AssertIsOnBackgroundThread();
942 0 : MOZ_ASSERT(aBackgroundActor);
943 :
944 0 : auto actor = static_cast<ParentImpl*>(aBackgroundActor);
945 0 : if (actor->mActorDestroyed) {
946 0 : MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
947 : return nullptr;
948 : }
949 :
950 0 : if (actor->mContent) {
951 : // We need to hand out a reference to our ContentParent but we also need to
952 : // keep the one we have. We can't call AddRef here because ContentParent is
953 : // not threadsafe so instead we dispatch a runnable to the main thread to do
954 : // it for us. This is safe since we are guaranteed that our AddRef runnable
955 : // will run before the reference we hand out can be released, and the
956 : // ContentParent can't die as long as the existing reference is maintained.
957 0 : MOZ_ALWAYS_SUCCEEDS(
958 : NS_DispatchToMainThread(NewNonOwningRunnableMethod("ContentParent::AddRef",
959 : actor->mContent, &ContentParent::AddRef)));
960 : }
961 :
962 0 : return already_AddRefed<ContentParent>(actor->mContent.get());
963 : }
964 :
965 : // static
966 : intptr_t
967 0 : ParentImpl::GetRawContentParentForComparison(
968 : PBackgroundParent* aBackgroundActor)
969 : {
970 0 : AssertIsOnBackgroundThread();
971 0 : MOZ_ASSERT(aBackgroundActor);
972 :
973 0 : auto actor = static_cast<ParentImpl*>(aBackgroundActor);
974 0 : if (actor->mActorDestroyed) {
975 0 : MOZ_ASSERT(false,
976 : "GetRawContentParentForComparison called after ActorDestroy was "
977 : "called!");
978 : return intptr_t(-1);
979 : }
980 :
981 0 : return intptr_t(static_cast<nsIContentParent*>(actor->mContent.get()));
982 : }
983 :
984 : // static
985 : uint64_t
986 0 : ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor)
987 : {
988 0 : AssertIsOnBackgroundThread();
989 0 : MOZ_ASSERT(aBackgroundActor);
990 :
991 0 : auto actor = static_cast<ParentImpl*>(aBackgroundActor);
992 0 : if (actor->mActorDestroyed) {
993 0 : MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
994 : return 0;
995 : }
996 :
997 0 : if (actor->mContent) {
998 0 : return actor->mContent->ChildID();
999 : }
1000 :
1001 0 : return 0;
1002 : }
1003 :
1004 : // static
1005 : bool
1006 2 : ParentImpl::Alloc(ContentParent* aContent,
1007 : Endpoint<PBackgroundParent>&& aEndpoint)
1008 : {
1009 2 : AssertIsInMainProcess();
1010 2 : AssertIsOnMainThread();
1011 2 : MOZ_ASSERT(aEndpoint.IsValid());
1012 :
1013 2 : if (!sBackgroundThread && !CreateBackgroundThread()) {
1014 0 : NS_WARNING("Failed to create background thread!");
1015 0 : return false;
1016 : }
1017 :
1018 2 : MOZ_ASSERT(sLiveActorsForBackgroundThread);
1019 :
1020 2 : sLiveActorCount++;
1021 :
1022 4 : RefPtr<ParentImpl> actor = new ParentImpl(aContent);
1023 :
1024 : nsCOMPtr<nsIRunnable> connectRunnable =
1025 : new ConnectActorRunnable(actor, Move(aEndpoint),
1026 6 : sLiveActorsForBackgroundThread);
1027 :
1028 2 : if (NS_FAILED(sBackgroundThread->Dispatch(connectRunnable,
1029 : NS_DISPATCH_NORMAL))) {
1030 0 : NS_WARNING("Failed to dispatch connect runnable!");
1031 :
1032 0 : MOZ_ASSERT(sLiveActorCount);
1033 0 : sLiveActorCount--;
1034 :
1035 0 : return false;
1036 : }
1037 :
1038 2 : return true;
1039 : }
1040 :
1041 : // static
1042 : bool
1043 2 : ParentImpl::CreateActorForSameProcess(CreateCallback* aCallback)
1044 : {
1045 2 : AssertIsInMainProcess();
1046 2 : AssertIsOnMainThread();
1047 2 : MOZ_ASSERT(aCallback);
1048 :
1049 2 : if (!sBackgroundThread && !CreateBackgroundThread()) {
1050 0 : NS_WARNING("Failed to create background thread!");
1051 0 : return false;
1052 : }
1053 :
1054 2 : MOZ_ASSERT(!sShutdownHasStarted);
1055 :
1056 2 : sLiveActorCount++;
1057 :
1058 2 : if (sBackgroundThreadMessageLoop) {
1059 : nsCOMPtr<nsIRunnable> callbackRunnable =
1060 2 : new CreateCallbackRunnable(aCallback);
1061 1 : MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(callbackRunnable));
1062 1 : return true;
1063 : }
1064 :
1065 1 : if (!sPendingCallbacks) {
1066 1 : sPendingCallbacks = new nsTArray<RefPtr<CreateCallback>>();
1067 : }
1068 :
1069 1 : sPendingCallbacks->AppendElement(aCallback);
1070 1 : return true;
1071 : }
1072 :
1073 : // static
1074 : bool
1075 1 : ParentImpl::CreateBackgroundThread()
1076 : {
1077 1 : AssertIsInMainProcess();
1078 1 : AssertIsOnMainThread();
1079 1 : MOZ_ASSERT(!sBackgroundThread);
1080 1 : MOZ_ASSERT(!sLiveActorsForBackgroundThread);
1081 :
1082 1 : if (sShutdownHasStarted) {
1083 : NS_WARNING("Trying to create background thread after shutdown has "
1084 0 : "already begun!");
1085 0 : return false;
1086 : }
1087 :
1088 2 : nsCOMPtr<nsITimer> newShutdownTimer;
1089 :
1090 1 : if (!sShutdownTimer) {
1091 : nsresult rv;
1092 1 : newShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1093 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
1094 0 : return false;
1095 : }
1096 : }
1097 :
1098 1 : if (!sShutdownObserverRegistered) {
1099 2 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1100 1 : if (NS_WARN_IF(!obs)) {
1101 0 : return false;
1102 : }
1103 :
1104 2 : nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1105 :
1106 : nsresult rv =
1107 1 : obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1108 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
1109 0 : return false;
1110 : }
1111 :
1112 1 : sShutdownObserverRegistered = true;
1113 : }
1114 :
1115 2 : nsCOMPtr<nsIThread> thread;
1116 1 : if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread)))) {
1117 0 : NS_WARNING("NS_NewNamedThread failed!");
1118 0 : return false;
1119 : }
1120 :
1121 : nsCOMPtr<nsIRunnable> messageLoopRunnable =
1122 3 : new RequestMessageLoopRunnable(thread);
1123 1 : if (NS_FAILED(thread->Dispatch(messageLoopRunnable, NS_DISPATCH_NORMAL))) {
1124 0 : NS_WARNING("Failed to dispatch RequestMessageLoopRunnable!");
1125 0 : return false;
1126 : }
1127 :
1128 1 : sBackgroundThread = thread;
1129 1 : sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
1130 :
1131 1 : if (!sShutdownTimer) {
1132 1 : MOZ_ASSERT(newShutdownTimer);
1133 1 : sShutdownTimer = newShutdownTimer;
1134 : }
1135 :
1136 1 : return true;
1137 : }
1138 :
1139 : // static
1140 : void
1141 0 : ParentImpl::ShutdownBackgroundThread()
1142 : {
1143 0 : AssertIsInMainProcess();
1144 0 : AssertIsOnMainThread();
1145 0 : MOZ_ASSERT_IF(!sBackgroundThread, !sBackgroundThreadMessageLoop);
1146 0 : MOZ_ASSERT(sShutdownHasStarted);
1147 0 : MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
1148 0 : MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
1149 :
1150 0 : if (sPendingCallbacks) {
1151 0 : if (!sPendingCallbacks->IsEmpty()) {
1152 0 : nsTArray<RefPtr<CreateCallback>> callbacks;
1153 0 : sPendingCallbacks->SwapElements(callbacks);
1154 :
1155 0 : for (uint32_t index = 0; index < callbacks.Length(); index++) {
1156 0 : RefPtr<CreateCallback> callback;
1157 0 : callbacks[index].swap(callback);
1158 0 : MOZ_ASSERT(callback);
1159 :
1160 0 : callback->Failure();
1161 : }
1162 : }
1163 :
1164 0 : sPendingCallbacks = nullptr;
1165 : }
1166 :
1167 0 : nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
1168 0 : sShutdownTimer = nullptr;
1169 :
1170 0 : if (sBackgroundThread) {
1171 0 : nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
1172 0 : sBackgroundThread = nullptr;
1173 :
1174 0 : nsAutoPtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread);
1175 0 : sLiveActorsForBackgroundThread = nullptr;
1176 :
1177 0 : sBackgroundThreadMessageLoop = nullptr;
1178 :
1179 0 : MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
1180 :
1181 0 : if (sLiveActorCount) {
1182 : // We need to spin the event loop while we wait for all the actors to be
1183 : // cleaned up. We also set a timeout to force-kill any hanging actors.
1184 0 : TimerCallbackClosure closure(thread, liveActors);
1185 :
1186 0 : MOZ_ALWAYS_SUCCEEDS(
1187 : shutdownTimer->InitWithNamedFuncCallback(&ShutdownTimerCallback,
1188 : &closure,
1189 : kShutdownTimerDelayMS,
1190 : nsITimer::TYPE_ONE_SHOT,
1191 : "ParentImpl::ShutdownTimerCallback"));
1192 :
1193 0 : SpinEventLoopUntil([&]() { return !sLiveActorCount; });
1194 :
1195 0 : MOZ_ASSERT(liveActors->IsEmpty());
1196 :
1197 0 : MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
1198 : }
1199 :
1200 : // Dispatch this runnable to unregister the thread from the profiler.
1201 : nsCOMPtr<nsIRunnable> shutdownRunnable =
1202 0 : new ShutdownBackgroundThreadRunnable();
1203 0 : MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
1204 :
1205 0 : MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
1206 : }
1207 0 : }
1208 :
1209 : // static
1210 : void
1211 0 : ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure)
1212 : {
1213 0 : AssertIsInMainProcess();
1214 0 : AssertIsOnMainThread();
1215 0 : MOZ_ASSERT(sShutdownHasStarted);
1216 0 : MOZ_ASSERT(sLiveActorCount);
1217 :
1218 0 : auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1219 0 : MOZ_ASSERT(closure);
1220 :
1221 : // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1222 : // finished.
1223 0 : sLiveActorCount++;
1224 :
1225 : nsCOMPtr<nsIRunnable> forceCloseRunnable =
1226 0 : new ForceCloseBackgroundActorsRunnable(closure->mLiveActors);
1227 0 : MOZ_ALWAYS_SUCCEEDS(closure->mThread->Dispatch(forceCloseRunnable,
1228 : NS_DISPATCH_NORMAL));
1229 0 : }
1230 :
1231 : void
1232 0 : ParentImpl::Destroy()
1233 : {
1234 : // May be called on any thread!
1235 :
1236 0 : AssertIsInMainProcess();
1237 :
1238 0 : MOZ_ALWAYS_SUCCEEDS(
1239 : NS_DispatchToMainThread(NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy",
1240 : this, &ParentImpl::MainThreadActorDestroy)));
1241 0 : }
1242 :
1243 : void
1244 0 : ParentImpl::MainThreadActorDestroy()
1245 : {
1246 0 : AssertIsInMainProcess();
1247 0 : AssertIsOnMainThread();
1248 0 : MOZ_ASSERT_IF(mIsOtherProcessActor, mContent);
1249 0 : MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1250 :
1251 0 : mContent = nullptr;
1252 :
1253 0 : MOZ_ASSERT(sLiveActorCount);
1254 0 : sLiveActorCount--;
1255 :
1256 : // This may be the last reference!
1257 0 : Release();
1258 0 : }
1259 :
1260 : void
1261 0 : ParentImpl::ActorDestroy(ActorDestroyReason aWhy)
1262 : {
1263 0 : AssertIsInMainProcess();
1264 0 : AssertIsOnBackgroundThread();
1265 0 : MOZ_ASSERT(!mActorDestroyed);
1266 0 : MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1267 :
1268 0 : BackgroundParentImpl::ActorDestroy(aWhy);
1269 :
1270 0 : mActorDestroyed = true;
1271 :
1272 0 : if (mLiveActorArray) {
1273 0 : MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1274 0 : mLiveActorArray = nullptr;
1275 : }
1276 :
1277 : // This is tricky. We should be able to call Destroy() here directly because
1278 : // we're not going to touch 'this' or our MessageChannel any longer on this
1279 : // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1280 : // it runs it will destroy 'this' and our associated MessageChannel. However,
1281 : // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1282 : // racing with the main thread we must ensure that the MessageChannel lives
1283 : // long enough to be cleared in this call stack.
1284 :
1285 0 : MOZ_ALWAYS_SUCCEEDS(
1286 : NS_DispatchToCurrentThread(NewNonOwningRunnableMethod("ParentImpl::Destroy",
1287 : this, &ParentImpl::Destroy)));
1288 0 : }
1289 :
1290 6 : NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1291 :
1292 : NS_IMETHODIMP
1293 0 : ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject,
1294 : const char* aTopic,
1295 : const char16_t* aData)
1296 : {
1297 0 : AssertIsInMainProcess();
1298 0 : AssertIsOnMainThread();
1299 0 : MOZ_ASSERT(!sShutdownHasStarted);
1300 0 : MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1301 :
1302 0 : sShutdownHasStarted = true;
1303 :
1304 : // Do this first before calling (and spinning the event loop in)
1305 : // ShutdownBackgroundThread().
1306 0 : ChildImpl::Shutdown();
1307 :
1308 0 : ShutdownBackgroundThread();
1309 :
1310 0 : return NS_OK;
1311 : }
1312 :
1313 : NS_IMETHODIMP
1314 2 : ParentImpl::RequestMessageLoopRunnable::Run()
1315 : {
1316 2 : AssertIsInMainProcess();
1317 2 : MOZ_ASSERT(mTargetThread);
1318 :
1319 2 : if (NS_IsMainThread()) {
1320 1 : MOZ_ASSERT(mMessageLoop);
1321 :
1322 2 : if (!sBackgroundThread ||
1323 1 : !SameCOMIdentity(mTargetThread.get(), sBackgroundThread.get())) {
1324 0 : return NS_OK;
1325 : }
1326 :
1327 1 : MOZ_ASSERT(!sBackgroundThreadMessageLoop);
1328 1 : sBackgroundThreadMessageLoop = mMessageLoop;
1329 :
1330 1 : if (sPendingCallbacks && !sPendingCallbacks->IsEmpty()) {
1331 2 : nsTArray<RefPtr<CreateCallback>> callbacks;
1332 1 : sPendingCallbacks->SwapElements(callbacks);
1333 :
1334 2 : for (uint32_t index = 0; index < callbacks.Length(); index++) {
1335 1 : MOZ_ASSERT(callbacks[index]);
1336 :
1337 : nsCOMPtr<nsIRunnable> callbackRunnable =
1338 3 : new CreateCallbackRunnable(callbacks[index]);
1339 1 : if (NS_FAILED(NS_DispatchToCurrentThread(callbackRunnable))) {
1340 0 : NS_WARNING("Failed to dispatch callback runnable!");
1341 : }
1342 : }
1343 : }
1344 :
1345 1 : return NS_OK;
1346 : }
1347 :
1348 : #ifdef DEBUG
1349 : {
1350 : bool correctThread;
1351 1 : MOZ_ASSERT(NS_SUCCEEDED(mTargetThread->IsOnCurrentThread(&correctThread)));
1352 1 : MOZ_ASSERT(correctThread);
1353 : }
1354 : #endif
1355 :
1356 : DebugOnly<PRThread*> oldBackgroundThread =
1357 2 : sBackgroundPRThread.exchange(PR_GetCurrentThread());
1358 :
1359 1 : MOZ_ASSERT_IF(oldBackgroundThread,
1360 : PR_GetCurrentThread() != oldBackgroundThread);
1361 :
1362 1 : MOZ_ASSERT(!mMessageLoop);
1363 :
1364 1 : mMessageLoop = MessageLoop::current();
1365 1 : MOZ_ASSERT(mMessageLoop);
1366 :
1367 1 : if (NS_FAILED(NS_DispatchToMainThread(this))) {
1368 0 : NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!");
1369 0 : return NS_ERROR_FAILURE;
1370 : }
1371 :
1372 1 : return NS_OK;
1373 : }
1374 :
1375 : NS_IMETHODIMP
1376 0 : ParentImpl::ShutdownBackgroundThreadRunnable::Run()
1377 : {
1378 0 : AssertIsInMainProcess();
1379 :
1380 : // It is possible that another background thread was created while this thread
1381 : // was shutting down. In that case we can't assert anything about
1382 : // sBackgroundPRThread and we should not modify it here.
1383 0 : sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1384 :
1385 0 : return NS_OK;
1386 : }
1387 :
1388 : NS_IMETHODIMP
1389 0 : ParentImpl::ForceCloseBackgroundActorsRunnable::Run()
1390 : {
1391 0 : AssertIsInMainProcess();
1392 0 : MOZ_ASSERT(mActorArray);
1393 :
1394 0 : if (NS_IsMainThread()) {
1395 0 : MOZ_ASSERT(sLiveActorCount);
1396 0 : sLiveActorCount--;
1397 0 : return NS_OK;
1398 : }
1399 :
1400 0 : AssertIsOnBackgroundThread();
1401 :
1402 0 : if (!mActorArray->IsEmpty()) {
1403 : // Copy the array since calling Close() could mutate the actual array.
1404 0 : nsTArray<ParentImpl*> actorsToClose(*mActorArray);
1405 :
1406 0 : for (uint32_t index = 0; index < actorsToClose.Length(); index++) {
1407 0 : actorsToClose[index]->Close();
1408 : }
1409 : }
1410 :
1411 0 : MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1412 :
1413 0 : return NS_OK;
1414 : }
1415 :
1416 : NS_IMETHODIMP
1417 2 : ParentImpl::CreateCallbackRunnable::Run()
1418 : {
1419 2 : AssertIsInMainProcess();
1420 2 : AssertIsOnMainThread();
1421 2 : MOZ_ASSERT(sBackgroundThreadMessageLoop);
1422 2 : MOZ_ASSERT(mCallback);
1423 :
1424 4 : RefPtr<CreateCallback> callback;
1425 2 : mCallback.swap(callback);
1426 :
1427 4 : RefPtr<ParentImpl> actor = new ParentImpl();
1428 :
1429 2 : callback->Success(actor.forget(), sBackgroundThreadMessageLoop);
1430 :
1431 4 : return NS_OK;
1432 : }
1433 :
1434 : NS_IMETHODIMP
1435 2 : ParentImpl::ConnectActorRunnable::Run()
1436 : {
1437 2 : AssertIsInMainProcess();
1438 2 : AssertIsOnBackgroundThread();
1439 :
1440 : // Transfer ownership to this thread. If Open() fails then we will release
1441 : // this reference in Destroy.
1442 : ParentImpl* actor;
1443 2 : mActor.forget(&actor);
1444 :
1445 4 : Endpoint<PBackgroundParent> endpoint = Move(mEndpoint);
1446 :
1447 2 : if (!endpoint.Bind(actor)) {
1448 0 : actor->Destroy();
1449 0 : return NS_ERROR_FAILURE;
1450 : }
1451 :
1452 2 : actor->SetLiveActorArray(mLiveActorArray);
1453 :
1454 2 : return NS_OK;
1455 : }
1456 :
1457 : // -----------------------------------------------------------------------------
1458 : // ChildImpl Implementation
1459 : // -----------------------------------------------------------------------------
1460 :
1461 : // static
1462 : void
1463 3 : ChildImpl::Startup()
1464 : {
1465 : // This happens on the main thread but before XPCOM has started so we can't
1466 : // assert that we're being called on the main thread here.
1467 :
1468 3 : MOZ_ASSERT(sThreadLocalIndex == kBadThreadLocalIndex,
1469 : "BackgroundChild::Startup() called more than once!");
1470 :
1471 : PRStatus status =
1472 3 : PR_NewThreadPrivateIndex(&sThreadLocalIndex, ThreadLocalDestructor);
1473 3 : MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
1474 :
1475 3 : MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1476 :
1477 6 : nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1478 3 : MOZ_RELEASE_ASSERT(observerService);
1479 :
1480 6 : nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1481 :
1482 : nsresult rv =
1483 6 : observerService->AddObserver(observer,
1484 : NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
1485 6 : false);
1486 3 : MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1487 3 : }
1488 :
1489 : // static
1490 : void
1491 0 : ChildImpl::Shutdown()
1492 : {
1493 0 : AssertIsOnMainThread();
1494 :
1495 0 : if (sShutdownHasStarted) {
1496 0 : MOZ_ASSERT_IF(sThreadLocalIndex != kBadThreadLocalIndex,
1497 : !PR_GetThreadPrivate(sThreadLocalIndex));
1498 0 : return;
1499 : }
1500 :
1501 0 : sShutdownHasStarted = true;
1502 :
1503 : #ifdef DEBUG
1504 0 : MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1505 :
1506 : auto threadLocalInfo =
1507 0 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1508 :
1509 0 : if (threadLocalInfo) {
1510 0 : MOZ_ASSERT(!threadLocalInfo->mClosed);
1511 0 : threadLocalInfo->mClosed = true;
1512 : }
1513 : #endif
1514 :
1515 0 : DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
1516 0 : MOZ_ASSERT(status == PR_SUCCESS);
1517 : }
1518 :
1519 : // static
1520 : void
1521 3 : ChildImpl::Alloc(Endpoint<PBackgroundChild>&& aEndpoint)
1522 : {
1523 3 : AssertIsInChildProcess();
1524 3 : AssertIsOnMainThread();
1525 3 : MOZ_ASSERT(aEndpoint.IsValid());
1526 3 : MOZ_ASSERT(sPendingTargets);
1527 3 : MOZ_ASSERT(!sPendingTargets->IsEmpty());
1528 :
1529 6 : nsCOMPtr<nsIEventTarget> eventTarget;
1530 3 : sPendingTargets->ElementAt(0).swap(eventTarget);
1531 :
1532 3 : sPendingTargets->RemoveElementAt(0);
1533 :
1534 6 : RefPtr<ChildImpl> actor = new ChildImpl();
1535 :
1536 : nsCOMPtr<nsIRunnable> openRunnable =
1537 9 : new OpenChildProcessActorRunnable(actor.forget(), Move(aEndpoint));
1538 3 : if (NS_FAILED(eventTarget->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) {
1539 0 : MOZ_CRASH("Failed to dispatch OpenActorRunnable!");
1540 : }
1541 3 : }
1542 :
1543 : // static
1544 : PBackgroundChild*
1545 6 : ChildImpl::GetForCurrentThread()
1546 : {
1547 6 : MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1548 :
1549 : auto threadLocalInfo =
1550 6 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1551 :
1552 6 : if (!threadLocalInfo) {
1553 1 : return nullptr;
1554 : }
1555 :
1556 5 : return threadLocalInfo->mActor;
1557 : }
1558 :
1559 : // static
1560 : bool
1561 10 : ChildImpl::GetOrCreateForCurrentThread(
1562 : nsIIPCBackgroundChildCreateCallback* aCallback)
1563 : {
1564 10 : MOZ_ASSERT(aCallback);
1565 10 : MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
1566 : "BackgroundChild::Startup() was never called!");
1567 :
1568 10 : bool created = false;
1569 :
1570 : auto threadLocalInfo =
1571 10 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1572 :
1573 10 : if (threadLocalInfo) {
1574 5 : threadLocalInfo->mCallbacks.AppendElement(aCallback);
1575 : } else {
1576 10 : nsAutoPtr<ThreadLocalInfo> newInfo(new ThreadLocalInfo(aCallback));
1577 :
1578 5 : if (PR_SetThreadPrivate(sThreadLocalIndex, newInfo) != PR_SUCCESS) {
1579 0 : CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
1580 : return false;
1581 : }
1582 :
1583 5 : created = true;
1584 5 : threadLocalInfo = newInfo.forget();
1585 : }
1586 :
1587 10 : if (threadLocalInfo->mActor) {
1588 : // Runnable will use GetForCurrentThread() to retrieve actor again. This
1589 : // allows us to avoid addref'ing on the wrong thread.
1590 4 : nsCOMPtr<nsIRunnable> runnable = new AlreadyCreatedCallbackRunnable();
1591 2 : MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(runnable));
1592 :
1593 2 : return true;
1594 : }
1595 :
1596 8 : if (!created) {
1597 : // We have already started the sequence for opening the actor so there's
1598 : // nothing else we need to do here. This callback will be called after the
1599 : // first callback in the schedule runnable.
1600 3 : return true;
1601 : }
1602 :
1603 5 : if (NS_IsMainThread()) {
1604 3 : if (NS_WARN_IF(!OpenProtocolOnMainThread(NS_GetCurrentThread()))) {
1605 0 : return false;
1606 : }
1607 :
1608 3 : return true;
1609 : }
1610 :
1611 4 : RefPtr<CreateActorRunnable> runnable = new CreateActorRunnable();
1612 2 : if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
1613 0 : CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
1614 : return false;
1615 : }
1616 :
1617 2 : return true;
1618 : }
1619 :
1620 : namespace {
1621 :
1622 : class Callback final : public nsIIPCBackgroundChildCreateCallback
1623 : {
1624 : bool* mDone;
1625 :
1626 : public:
1627 1 : explicit Callback(bool* aDone)
1628 1 : : mDone(aDone)
1629 : {
1630 1 : MOZ_ASSERT(mDone);
1631 1 : }
1632 :
1633 : NS_DECL_ISUPPORTS
1634 :
1635 : private:
1636 1 : ~Callback()
1637 1 : { }
1638 :
1639 : virtual void
1640 1 : ActorCreated(PBackgroundChild* aActor) override
1641 : {
1642 1 : *mDone = true;
1643 1 : }
1644 :
1645 : virtual void
1646 0 : ActorFailed() override
1647 : {
1648 0 : *mDone = true;
1649 0 : }
1650 : };
1651 :
1652 14 : NS_IMPL_ISUPPORTS(Callback, nsIIPCBackgroundChildCreateCallback)
1653 :
1654 : } // anonymous namespace
1655 :
1656 : /* static */
1657 : PBackgroundChild*
1658 1 : ChildImpl::SynchronouslyCreateForCurrentThread()
1659 : {
1660 1 : MOZ_ASSERT(!GetForCurrentThread());
1661 :
1662 1 : bool done = false;
1663 2 : nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = new Callback(&done);
1664 :
1665 1 : if (NS_WARN_IF(!GetOrCreateForCurrentThread(callback))) {
1666 0 : return nullptr;
1667 : }
1668 :
1669 3 : if (NS_WARN_IF(!SpinEventLoopUntil([&]() { return done; }))) {
1670 0 : return nullptr;
1671 : }
1672 :
1673 1 : return GetForCurrentThread();
1674 : }
1675 :
1676 : // static
1677 : void
1678 1 : ChildImpl::CloseForCurrentThread()
1679 : {
1680 1 : if (sThreadLocalIndex == kBadThreadLocalIndex) {
1681 1 : return;
1682 : }
1683 :
1684 : auto threadLocalInfo =
1685 1 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1686 :
1687 1 : if (!threadLocalInfo) {
1688 1 : return;
1689 : }
1690 :
1691 : #ifdef DEBUG
1692 0 : MOZ_ASSERT(!threadLocalInfo->mClosed);
1693 0 : threadLocalInfo->mClosed = true;
1694 : #endif
1695 :
1696 : // Clearing the thread local will synchronously close the actor.
1697 0 : DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
1698 0 : MOZ_ASSERT(status == PR_SUCCESS);
1699 : }
1700 :
1701 : // static
1702 : BackgroundChildImpl::ThreadLocal*
1703 0 : ChildImpl::GetThreadLocalForCurrentThread()
1704 : {
1705 0 : MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
1706 : "BackgroundChild::Startup() was never called!");
1707 :
1708 : auto threadLocalInfo =
1709 0 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1710 :
1711 0 : if (!threadLocalInfo) {
1712 0 : return nullptr;
1713 : }
1714 :
1715 0 : if (!threadLocalInfo->mConsumerThreadLocal) {
1716 : threadLocalInfo->mConsumerThreadLocal =
1717 0 : new BackgroundChildImpl::ThreadLocal();
1718 : }
1719 :
1720 0 : return threadLocalInfo->mConsumerThreadLocal;
1721 : }
1722 :
1723 : // static
1724 : already_AddRefed<nsIIPCBackgroundChildCreateCallback>
1725 14 : ChildImpl::GetNextCallback()
1726 : {
1727 : // May run on any thread!
1728 :
1729 : auto threadLocalInfo =
1730 14 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1731 14 : MOZ_ASSERT(threadLocalInfo);
1732 :
1733 14 : if (threadLocalInfo->mCallbacks.IsEmpty()) {
1734 6 : return nullptr;
1735 : }
1736 :
1737 16 : nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback;
1738 8 : threadLocalInfo->mCallbacks[0].swap(callback);
1739 :
1740 8 : threadLocalInfo->mCallbacks.RemoveElementAt(0);
1741 :
1742 8 : return callback.forget();
1743 : }
1744 :
1745 : NS_IMETHODIMP
1746 2 : ChildImpl::AlreadyCreatedCallbackRunnable::Run()
1747 : {
1748 : // May run on any thread!
1749 :
1750 : // Report the current actor back in the callback.
1751 2 : PBackgroundChild* actor = ChildImpl::GetForCurrentThread();
1752 :
1753 : // If the current actor is null, do not create a new actor here. This likely
1754 : // means we are in the process of cleaning up a worker thread and do not want
1755 : // a new actor created. Unfortunately we cannot report back to the callback
1756 : // because the thread local is gone at this point. Instead simply do nothing
1757 : // and return.
1758 2 : if (NS_WARN_IF(!actor)) {
1759 0 : return NS_OK;
1760 : }
1761 :
1762 : nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
1763 4 : ChildImpl::GetNextCallback();
1764 6 : while (callback) {
1765 2 : callback->ActorCreated(actor);
1766 2 : callback = ChildImpl::GetNextCallback();
1767 : }
1768 :
1769 2 : return NS_OK;
1770 : }
1771 :
1772 : nsresult
1773 0 : ChildImpl::AlreadyCreatedCallbackRunnable::Cancel()
1774 : {
1775 : // These are IPC infrastructure objects and need to run unconditionally.
1776 0 : Run();
1777 0 : return NS_OK;
1778 : }
1779 :
1780 : NS_IMETHODIMP
1781 0 : ChildImpl::FailedCreateCallbackRunnable::Run()
1782 : {
1783 : // May run on any thread!
1784 :
1785 : nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
1786 0 : ChildImpl::GetNextCallback();
1787 0 : while (callback) {
1788 0 : callback->ActorFailed();
1789 0 : callback = ChildImpl::GetNextCallback();
1790 : }
1791 :
1792 0 : return NS_OK;
1793 : }
1794 :
1795 : NS_IMETHODIMP
1796 2 : ChildImpl::OpenChildProcessActorRunnable::Run()
1797 : {
1798 : // May be run on any thread!
1799 :
1800 2 : AssertIsInChildProcess();
1801 2 : MOZ_ASSERT(mActor);
1802 2 : MOZ_ASSERT(mEndpoint.IsValid());
1803 :
1804 : nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
1805 4 : ChildImpl::GetNextCallback();
1806 2 : MOZ_ASSERT(callback,
1807 : "There should be at least one callback when first creating the "
1808 : "actor!");
1809 :
1810 4 : RefPtr<ChildImpl> strongActor;
1811 2 : mActor.swap(strongActor);
1812 4 : Endpoint<PBackgroundChild> endpoint = Move(mEndpoint);
1813 :
1814 2 : if (!endpoint.Bind(strongActor)) {
1815 0 : CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
1816 :
1817 : while (callback) {
1818 : callback->ActorFailed();
1819 : callback = ChildImpl::GetNextCallback();
1820 : }
1821 :
1822 : return NS_OK;
1823 : }
1824 :
1825 : // Now that Open() has succeeded transfer the ownership of the actor to IPDL.
1826 : auto threadLocalInfo =
1827 2 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1828 :
1829 2 : MOZ_ASSERT(threadLocalInfo);
1830 2 : MOZ_ASSERT(!threadLocalInfo->mActor);
1831 :
1832 2 : RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
1833 2 : strongActor.swap(actor);
1834 :
1835 2 : actor->SetBoundThread();
1836 :
1837 8 : while (callback) {
1838 3 : callback->ActorCreated(actor);
1839 3 : callback = ChildImpl::GetNextCallback();
1840 : }
1841 :
1842 2 : return NS_OK;
1843 : }
1844 :
1845 : NS_IMETHODIMP
1846 2 : ChildImpl::OpenMainProcessActorRunnable::Run()
1847 : {
1848 : // May run on any thread!
1849 :
1850 2 : AssertIsInMainProcess();
1851 2 : MOZ_ASSERT(mActor);
1852 2 : MOZ_ASSERT(mParentActor);
1853 2 : MOZ_ASSERT(mParentMessageLoop);
1854 :
1855 : nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
1856 4 : ChildImpl::GetNextCallback();
1857 2 : MOZ_ASSERT(callback,
1858 : "There should be at least one callback when first creating the "
1859 : "actor!");
1860 :
1861 4 : RefPtr<ChildImpl> strongChildActor;
1862 2 : mActor.swap(strongChildActor);
1863 :
1864 4 : RefPtr<ParentImpl> parentActor;
1865 2 : mParentActor.swap(parentActor);
1866 :
1867 2 : MessageChannel* parentChannel = parentActor->GetIPCChannel();
1868 2 : MOZ_ASSERT(parentChannel);
1869 :
1870 2 : if (!strongChildActor->Open(parentChannel, mParentMessageLoop, ChildSide)) {
1871 0 : NS_WARNING("Failed to open ChildImpl!");
1872 :
1873 0 : parentActor->Destroy();
1874 :
1875 0 : while (callback) {
1876 0 : callback->ActorFailed();
1877 0 : callback = ChildImpl::GetNextCallback();
1878 : }
1879 :
1880 0 : return NS_OK;
1881 : }
1882 :
1883 : // Make sure the parent knows it is same process.
1884 2 : parentActor->SetOtherProcessId(base::GetCurrentProcId());
1885 :
1886 : // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
1887 2 : Unused << parentActor.forget();
1888 :
1889 : auto threadLocalInfo =
1890 2 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1891 :
1892 2 : MOZ_ASSERT(threadLocalInfo);
1893 2 : MOZ_ASSERT(!threadLocalInfo->mActor);
1894 :
1895 2 : RefPtr<ChildImpl>& childActor = threadLocalInfo->mActor;
1896 2 : strongChildActor.swap(childActor);
1897 :
1898 2 : childActor->SetBoundThread();
1899 :
1900 8 : while (callback) {
1901 3 : callback->ActorCreated(childActor);
1902 3 : callback = ChildImpl::GetNextCallback();
1903 : }
1904 :
1905 2 : return NS_OK;
1906 : }
1907 :
1908 : NS_IMETHODIMP
1909 2 : ChildImpl::CreateActorRunnable::Run()
1910 : {
1911 2 : AssertIsOnMainThread();
1912 :
1913 2 : if (!OpenProtocolOnMainThread(mEventTarget)) {
1914 0 : NS_WARNING("OpenProtocolOnMainThread failed!");
1915 0 : return NS_ERROR_FAILURE;
1916 : }
1917 :
1918 2 : return NS_OK;
1919 : }
1920 :
1921 : void
1922 2 : ChildImpl::ParentCreateCallback::Success(
1923 : already_AddRefed<ParentImpl> aParentActor,
1924 : MessageLoop* aParentMessageLoop)
1925 : {
1926 2 : AssertIsInMainProcess();
1927 2 : AssertIsOnMainThread();
1928 :
1929 4 : RefPtr<ParentImpl> parentActor = aParentActor;
1930 2 : MOZ_ASSERT(parentActor);
1931 2 : MOZ_ASSERT(aParentMessageLoop);
1932 2 : MOZ_ASSERT(mEventTarget);
1933 :
1934 4 : RefPtr<ChildImpl> childActor = new ChildImpl();
1935 :
1936 4 : nsCOMPtr<nsIEventTarget> target;
1937 2 : mEventTarget.swap(target);
1938 :
1939 : nsCOMPtr<nsIRunnable> openRunnable =
1940 8 : new OpenMainProcessActorRunnable(childActor.forget(), parentActor.forget(),
1941 10 : aParentMessageLoop);
1942 2 : if (NS_FAILED(target->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) {
1943 0 : NS_WARNING("Failed to dispatch open runnable!");
1944 : }
1945 2 : }
1946 :
1947 : void
1948 0 : ChildImpl::ParentCreateCallback::Failure()
1949 : {
1950 0 : AssertIsInMainProcess();
1951 0 : AssertIsOnMainThread();
1952 0 : MOZ_ASSERT(mEventTarget);
1953 :
1954 0 : nsCOMPtr<nsIEventTarget> target;
1955 0 : mEventTarget.swap(target);
1956 :
1957 0 : DispatchFailureCallback(target);
1958 0 : }
1959 :
1960 : // static
1961 : bool
1962 5 : ChildImpl::OpenProtocolOnMainThread(nsIEventTarget* aEventTarget)
1963 : {
1964 5 : AssertIsOnMainThread();
1965 5 : MOZ_ASSERT(aEventTarget);
1966 :
1967 5 : if (sShutdownHasStarted) {
1968 0 : MOZ_CRASH("Called BackgroundChild::GetOrCreateForCurrentThread after "
1969 : "shutdown has started!");
1970 : }
1971 :
1972 5 : if (XRE_IsParentProcess()) {
1973 : RefPtr<ParentImpl::CreateCallback> parentCallback =
1974 4 : new ParentCreateCallback(aEventTarget);
1975 :
1976 2 : if (!ParentImpl::CreateActorForSameProcess(parentCallback)) {
1977 0 : NS_WARNING("BackgroundParent::CreateActor() failed!");
1978 0 : DispatchFailureCallback(aEventTarget);
1979 0 : return false;
1980 : }
1981 :
1982 2 : return true;
1983 : }
1984 :
1985 3 : ContentChild* content = ContentChild::GetSingleton();
1986 3 : MOZ_ASSERT(content);
1987 :
1988 3 : if (content->IsShuttingDown()) {
1989 : // The transport for ContentChild is shut down and can't be used to open
1990 : // PBackground.
1991 0 : DispatchFailureCallback(aEventTarget);
1992 0 : return false;
1993 : }
1994 :
1995 6 : Endpoint<PBackgroundParent> parent;
1996 6 : Endpoint<PBackgroundChild> child;
1997 : nsresult rv;
1998 3 : rv = PBackground::CreateEndpoints(content->OtherPid(),
1999 : base::GetCurrentProcId(),
2000 3 : &parent, &child);
2001 3 : if (NS_FAILED(rv)) {
2002 0 : MOZ_CRASH("Failed to create top level actor!");
2003 : return false;
2004 : }
2005 :
2006 3 : if (!content->SendInitBackground(Move(parent))) {
2007 0 : MOZ_CRASH("Failed to create top level actor!");
2008 : return false;
2009 : }
2010 :
2011 3 : if (!sPendingTargets) {
2012 2 : sPendingTargets = new nsTArray<nsCOMPtr<nsIEventTarget>>(1);
2013 2 : ClearOnShutdown(&sPendingTargets);
2014 : }
2015 :
2016 3 : sPendingTargets->AppendElement(aEventTarget);
2017 :
2018 3 : Alloc(Move(child));
2019 :
2020 3 : return true;
2021 : }
2022 :
2023 : // static
2024 : void
2025 0 : ChildImpl::DispatchFailureCallback(nsIEventTarget* aEventTarget)
2026 : {
2027 0 : MOZ_ASSERT(aEventTarget);
2028 :
2029 0 : nsCOMPtr<nsIRunnable> callbackRunnable = new FailedCreateCallbackRunnable();
2030 0 : if (NS_FAILED(aEventTarget->Dispatch(callbackRunnable, NS_DISPATCH_NORMAL))) {
2031 0 : NS_WARNING("Failed to dispatch CreateCallbackRunnable!");
2032 : }
2033 0 : }
2034 :
2035 : void
2036 0 : ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
2037 : {
2038 0 : AssertIsOnBoundThread();
2039 :
2040 : #ifdef DEBUG
2041 0 : MOZ_ASSERT(!mActorDestroyed);
2042 0 : mActorDestroyed = true;
2043 : #endif
2044 :
2045 0 : BackgroundChildImpl::ActorDestroy(aWhy);
2046 0 : }
2047 :
2048 18 : NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
2049 :
2050 : NS_IMETHODIMP
2051 0 : ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject,
2052 : const char* aTopic,
2053 : const char16_t* aData)
2054 : {
2055 0 : AssertIsOnMainThread();
2056 0 : MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
2057 :
2058 0 : ChildImpl::Shutdown();
2059 :
2060 0 : return NS_OK;
2061 : }
|