ipc/glue/BackgroundImpl.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "base/process_util.h"
     6 #include "mozilla/Assertions.h"
     7 #include "mozilla/Atomics.h"
     8 #include "mozilla/ClearOnShutdown.h"
     9 #include "mozilla/DebugOnly.h"
    10 #include "mozilla/Services.h"
    11 #include "mozilla/StaticPtr.h"
    12 #include "mozilla/unused.h"
    13 #include "mozilla/dom/ContentChild.h"
    14 #include "mozilla/dom/ContentParent.h"
    15 #include "mozilla/ipc/ProtocolTypes.h"
    16 #include "BackgroundChild.h"
    17 #include "BackgroundChildImpl.h"
    18 #include "BackgroundParent.h"
    19 #include "BackgroundParentImpl.h"
    20 #include "GeckoProfiler.h"
    21 #include "nsAutoPtr.h"
    22 #include "nsCOMPtr.h"
    23 #include "nsIEventTarget.h"
    24 #include "nsIIPCBackgroundChildCreateCallback.h"
    25 #include "nsIObserver.h"
    26 #include "nsIObserverService.h"
    27 #include "nsIRunnable.h"
    28 #include "nsISupportsImpl.h"
    29 #include "nsIThread.h"
    30 #include "nsITimer.h"
    31 #include "nsTArray.h"
    32 #include "nsThreadUtils.h"
    33 #include "nsTraceRefcnt.h"
    34 #include "nsXULAppAPI.h"
    35 #include "nsXPCOMPrivate.h"
    36 #include "prthread.h"
    38 #ifdef RELEASE_BUILD
    39 #define THREADSAFETY_ASSERT MOZ_ASSERT
    40 #else
    41 #define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
    42 #endif
    44 #define CRASH_IN_CHILD_PROCESS(_msg)                                           \
    45   do {                                                                         \
    46     if (IsMainProcess()) {                                                     \
    47       MOZ_ASSERT(false, _msg);                                                 \
    48     } else {                                                                   \
    49       MOZ_CRASH(_msg);                                                         \
    50     }                                                                          \
    51   }                                                                            \
    52   while (0)
    54 using namespace mozilla;
    55 using namespace mozilla::ipc;
    57 using mozilla::dom::ContentChild;
    58 using mozilla::dom::ContentParent;
    60 namespace {
    62 // -----------------------------------------------------------------------------
    63 // Utility Functions
    64 // -----------------------------------------------------------------------------
    66 bool
    67 IsMainProcess()
    68 {
    69   static const bool isMainProcess =
    70     XRE_GetProcessType() == GeckoProcessType_Default;
    71   return isMainProcess;
    72 }
    74 bool
    75 IsChildProcess()
    76 {
    77   return !IsMainProcess();
    78 }
    80 void
    81 AssertIsInMainProcess()
    82 {
    83   MOZ_ASSERT(IsMainProcess());
    84 }
    86 void
    87 AssertIsInChildProcess()
    88 {
    89   MOZ_ASSERT(IsChildProcess());
    90 }
    92 void
    93 AssertIsOnMainThread()
    94 {
    95   THREADSAFETY_ASSERT(NS_IsMainThread());
    96 }
    98 // -----------------------------------------------------------------------------
    99 // ParentImpl Declaration
   100 // -----------------------------------------------------------------------------
   102 class ParentImpl MOZ_FINAL : public BackgroundParentImpl
   103 {
   104   friend class mozilla::ipc::BackgroundParent;
   106 public:
   107   class CreateCallback;
   109 private:
   110   class ShutdownObserver;
   111   class RequestMessageLoopRunnable;
   112   class ShutdownBackgroundThreadRunnable;
   113   class ForceCloseBackgroundActorsRunnable;
   114   class CreateCallbackRunnable;
   115   class ConnectActorRunnable;
   117   struct MOZ_STACK_CLASS TimerCallbackClosure
   118   {
   119     nsIThread* mThread;
   120     nsTArray<ParentImpl*>* mLiveActors;
   122     TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
   123       : mThread(aThread), mLiveActors(aLiveActors)
   124     {
   125       AssertIsInMainProcess();
   126       AssertIsOnMainThread();
   127       MOZ_ASSERT(aThread);
   128       MOZ_ASSERT(aLiveActors);
   129     }
   130   };
   132   // A handle that is invalid on any platform.
   133   static const ProcessHandle kInvalidProcessHandle;
   135   // The length of time we will wait at shutdown for all actors to clean
   136   // themselves up before forcing them to be destroyed.
   137   static const uint32_t kShutdownTimerDelayMS = 10000;
   139   // This is only modified on the main thread. It is null if the thread does not
   140   // exist or is shutting down.
   141   static StaticRefPtr<nsIThread> sBackgroundThread;
   143   // This is created and destroyed on the main thread but only modified on the
   144   // background thread. It is specific to each instance of sBackgroundThread.
   145   static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
   147   // This is only modified on the main thread.
   148   static StaticRefPtr<nsITimer> sShutdownTimer;
   150   // This exists so that that [Assert]IsOnBackgroundThread() can continue to
   151   // work during shutdown.
   152   static Atomic<PRThread*> sBackgroundPRThread;
   154   // This is only modified on the main thread. It is null if the thread does not
   155   // exist or is shutting down.
   156   static MessageLoop* sBackgroundThreadMessageLoop;
   158   // This is only modified on the main thread. It maintains a count of live
   159   // actors so that the background thread can be shut down when it is no longer
   160   // needed.
   161   static uint64_t sLiveActorCount;
   163   // This is only modified on the main thread. It is true after the shutdown
   164   // observer is registered and is never unset thereafter.
   165   static bool sShutdownObserverRegistered;
   167   // This is only modified on the main thread. It prevents us from trying to
   168   // create the background thread after application shutdown has started.
   169   static bool sShutdownHasStarted;
   171   // This is only modified on the main thread. It is a FIFO queue for callbacks
   172   // waiting for the background thread to be created.
   173   static StaticAutoPtr<nsTArray<nsRefPtr<CreateCallback>>> sPendingCallbacks;
   175   // Only touched on the main thread, null if this is a same-process actor.
   176   nsRefPtr<ContentParent> mContent;
   178   // mTransport is "owned" by this object but it must only be released on the
   179   // IPC thread. It's left as a raw pointer here to prevent accidentally
   180   // deleting it on the wrong thread. Only non-null for other-process actors.
   181   Transport* mTransport;
   183   // Set when the actor is opened successfully and used to handle shutdown
   184   // hangs. Only touched on the background thread.
   185   nsTArray<ParentImpl*>* mLiveActorArray;
   187   // Set at construction to indicate whether this parent actor corresponds to a
   188   // child actor in another process or to a child actor from a different thread
   189   // in the same process.
   190   const bool mIsOtherProcessActor;
   192   // Set after ActorDestroy has been called. Only touched on the background
   193   // thread.
   194   bool mActorDestroyed;
   196 public:
   197   static bool
   198   CreateActorForSameProcess(CreateCallback* aCallback);
   200   static bool
   201   IsOnBackgroundThread()
   202   {
   203     return PR_GetCurrentThread() == sBackgroundPRThread;
   204   }
   206   static void
   207   AssertIsOnBackgroundThread()
   208   {
   209     THREADSAFETY_ASSERT(IsOnBackgroundThread());
   210   }
   212   NS_INLINE_DECL_REFCOUNTING(ParentImpl)
   214   void
   215   Destroy();
   217 private:
   218   // Forwarded from BackgroundParent.
   219   static bool
   220   IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
   222   // Forwarded from BackgroundParent.
   223   static already_AddRefed<ContentParent>
   224   GetContentParent(PBackgroundParent* aBackgroundActor);
   226   // Forwarded from BackgroundParent.
   227   static PBackgroundParent*
   228   Alloc(ContentParent* aContent,
   229         Transport* aTransport,
   230         ProcessId aOtherProcess);
   232   static bool
   233   CreateBackgroundThread();
   235   static void
   236   ShutdownBackgroundThread();
   238   static void
   239   ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
   241   // For same-process actors.
   242   ParentImpl()
   243   : mTransport(nullptr), mLiveActorArray(nullptr), mIsOtherProcessActor(false),
   244     mActorDestroyed(false)
   245   {
   246     AssertIsInMainProcess();
   247     AssertIsOnMainThread();
   249     SetOtherProcess(kInvalidProcessHandle);
   250   }
   252   // For other-process actors.
   253   ParentImpl(ContentParent* aContent, Transport* aTransport)
   254   : mContent(aContent), mTransport(aTransport), mLiveActorArray(nullptr),
   255     mIsOtherProcessActor(true), mActorDestroyed(false)
   256   {
   257     AssertIsInMainProcess();
   258     AssertIsOnMainThread();
   259     MOZ_ASSERT(aContent);
   260     MOZ_ASSERT(aTransport);
   261   }
   263   ~ParentImpl()
   264   {
   265     AssertIsInMainProcess();
   266     AssertIsOnMainThread();
   267     MOZ_ASSERT(!mContent);
   268     MOZ_ASSERT(!mTransport);
   269   }
   271   void
   272   MainThreadActorDestroy();
   274   void
   275   SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray)
   276   {
   277     AssertIsInMainProcess();
   278     AssertIsOnBackgroundThread();
   279     MOZ_ASSERT(aLiveActorArray);
   280     MOZ_ASSERT(!aLiveActorArray->Contains(this));
   281     MOZ_ASSERT(!mLiveActorArray);
   282     MOZ_ASSERT(mIsOtherProcessActor);
   284     mLiveActorArray = aLiveActorArray;
   285     mLiveActorArray->AppendElement(this);
   286   }
   288   // These methods are only called by IPDL.
   289   virtual IToplevelProtocol*
   290   CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
   291                 ProcessHandle aPeerProcess,
   292                 ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
   294   virtual void
   295   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   296 };
   298 // -----------------------------------------------------------------------------
   299 // ChildImpl Declaration
   300 // -----------------------------------------------------------------------------
   302 class ChildImpl MOZ_FINAL : public BackgroundChildImpl
   303 {
   304   friend class mozilla::ipc::BackgroundChild;
   305   friend class mozilla::ipc::BackgroundChildImpl;
   307   typedef base::ProcessId ProcessId;
   308   typedef mozilla::ipc::Transport Transport;
   310   class ShutdownObserver;
   311   class CreateActorRunnable;
   312   class ParentCreateCallback;
   313   class CreateCallbackRunnable;
   314   class OpenChildProcessActorRunnable;
   315   class OpenMainProcessActorRunnable;
   317   // A thread-local index that is not valid.
   318   static const unsigned int kBadThreadLocalIndex =
   319     static_cast<unsigned int>(-1);
   321   // This is only modified on the main thread. It is the thread-local index that
   322   // we use to store the BackgroundChild for each thread.
   323   static unsigned int sThreadLocalIndex;
   325   struct ThreadLocalInfo
   326   {
   327     ThreadLocalInfo(nsIIPCBackgroundChildCreateCallback* aCallback)
   328     {
   329       mCallbacks.AppendElement(aCallback);
   330     }
   332     nsRefPtr<ChildImpl> mActor;
   333     nsTArray<nsCOMPtr<nsIIPCBackgroundChildCreateCallback>> mCallbacks;
   334     nsAutoPtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
   335   };
   337   // This is only modified on the main thread. It is a FIFO queue for actors
   338   // that are in the process of construction.
   339   static StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> sPendingTargets;
   341   // This is only modified on the main thread. It prevents us from trying to
   342   // create the background thread after application shutdown has started.
   343   static bool sShutdownHasStarted;
   345 #ifdef RELEASE_BUILD
   346   DebugOnly<nsIThread*> mBoundThread;
   347 #else
   348   nsIThread* mBoundThread;
   349 #endif
   351 public:
   352   static bool
   353   OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
   355   static void
   356   Shutdown();
   358   void
   359   AssertIsOnBoundThread()
   360   {
   361     THREADSAFETY_ASSERT(mBoundThread);
   363 #ifdef RELEASE_BUILD
   364     DebugOnly<bool> current;
   365 #else
   366     bool current;
   367 #endif
   368     THREADSAFETY_ASSERT(
   369       NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
   370     THREADSAFETY_ASSERT(current);
   371   }
   373   ChildImpl()
   374   : mBoundThread(nullptr)
   375   {
   376     AssertIsOnMainThread();
   377   }
   379   NS_INLINE_DECL_REFCOUNTING(ChildImpl)
   381 private:
   382   // Forwarded from BackgroundChild.
   383   static void
   384   Startup();
   386   // Forwarded from BackgroundChild.
   387   static PBackgroundChild*
   388   Alloc(Transport* aTransport, ProcessId aOtherProcess);
   390   // Forwarded from BackgroundChild.
   391   static PBackgroundChild*
   392   GetForCurrentThread();
   394   // Forwarded from BackgroundChild.
   395   static bool
   396   GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
   398   // Forwarded from BackgroundChildImpl.
   399   static BackgroundChildImpl::ThreadLocal*
   400   GetThreadLocalForCurrentThread();
   402   static void
   403   ThreadLocalDestructor(void* aThreadLocal)
   404   {
   405     auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
   407     if (threadLocalInfo) {
   408       if (threadLocalInfo->mActor) {
   409         threadLocalInfo->mActor->Close();
   410       }
   411       delete threadLocalInfo;
   412     }
   413   }
   415   static void
   416   DispatchFailureCallback(nsIEventTarget* aEventTarget);
   418   // This class is reference counted.
   419   ~ChildImpl()
   420   { }
   422   void
   423   SetBoundThread()
   424   {
   425     THREADSAFETY_ASSERT(!mBoundThread);
   427 #if defined(DEBUG) || !defined(RELEASE_BUILD)
   428     mBoundThread = NS_GetCurrentThread();
   429 #endif
   431     THREADSAFETY_ASSERT(mBoundThread);
   432   }
   434   // Only called by IPDL.
   435   virtual void
   436   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   437 };
   439 // -----------------------------------------------------------------------------
   440 // ParentImpl Helper Declarations
   441 // -----------------------------------------------------------------------------
   443 class ParentImpl::ShutdownObserver MOZ_FINAL : public nsIObserver
   444 {
   445 public:
   446   ShutdownObserver()
   447   {
   448     AssertIsOnMainThread();
   449   }
   451   NS_DECL_ISUPPORTS
   452   NS_DECL_NSIOBSERVER
   454 private:
   455   ~ShutdownObserver()
   456   {
   457     AssertIsOnMainThread();
   458   }
   459 };
   461 class ParentImpl::RequestMessageLoopRunnable MOZ_FINAL :
   462   public nsRunnable
   463 {
   464   nsCOMPtr<nsIThread> mTargetThread;
   465   MessageLoop* mMessageLoop;
   467 public:
   468   RequestMessageLoopRunnable(nsIThread* aTargetThread)
   469   : mTargetThread(aTargetThread), mMessageLoop(nullptr)
   470   {
   471     AssertIsInMainProcess();
   472     AssertIsOnMainThread();
   473     MOZ_ASSERT(aTargetThread);
   474   }
   476   NS_DECL_ISUPPORTS_INHERITED
   478 private:
   479   ~RequestMessageLoopRunnable()
   480   { }
   482   NS_DECL_NSIRUNNABLE
   483 };
   485 class ParentImpl::ShutdownBackgroundThreadRunnable MOZ_FINAL : public nsRunnable
   486 {
   487 public:
   488   ShutdownBackgroundThreadRunnable()
   489   {
   490     AssertIsInMainProcess();
   491     AssertIsOnMainThread();
   492   }
   494   NS_DECL_ISUPPORTS_INHERITED
   496 private:
   497   ~ShutdownBackgroundThreadRunnable()
   498   { }
   500   NS_DECL_NSIRUNNABLE
   501 };
   503 class ParentImpl::ForceCloseBackgroundActorsRunnable MOZ_FINAL : public nsRunnable
   504 {
   505   nsTArray<ParentImpl*>* mActorArray;
   507 public:
   508   ForceCloseBackgroundActorsRunnable(nsTArray<ParentImpl*>* aActorArray)
   509   : mActorArray(aActorArray)
   510   {
   511     AssertIsInMainProcess();
   512     AssertIsOnMainThread();
   513     MOZ_ASSERT(aActorArray);
   514   }
   516   NS_DECL_ISUPPORTS_INHERITED
   518 private:
   519   ~ForceCloseBackgroundActorsRunnable()
   520   { }
   522   NS_DECL_NSIRUNNABLE
   523 };
   525 class ParentImpl::CreateCallbackRunnable MOZ_FINAL : public nsRunnable
   526 {
   527   nsRefPtr<CreateCallback> mCallback;
   529 public:
   530   CreateCallbackRunnable(CreateCallback* aCallback)
   531   : mCallback(aCallback)
   532   {
   533     AssertIsInMainProcess();
   534     AssertIsOnMainThread();
   535     MOZ_ASSERT(aCallback);
   536   }
   538   NS_DECL_ISUPPORTS_INHERITED
   540 private:
   541   ~CreateCallbackRunnable()
   542   { }
   544   NS_DECL_NSIRUNNABLE
   545 };
   547 class ParentImpl::ConnectActorRunnable MOZ_FINAL : public nsRunnable
   548 {
   549   nsRefPtr<ParentImpl> mActor;
   550   Transport* mTransport;
   551   ProcessHandle mProcessHandle;
   552   nsTArray<ParentImpl*>* mLiveActorArray;
   554 public:
   555   ConnectActorRunnable(ParentImpl* aActor,
   556                        Transport* aTransport,
   557                        ProcessHandle aProcessHandle,
   558                        nsTArray<ParentImpl*>* aLiveActorArray)
   559   : mActor(aActor), mTransport(aTransport), mProcessHandle(aProcessHandle),
   560     mLiveActorArray(aLiveActorArray)
   561   {
   562     AssertIsInMainProcess();
   563     AssertIsOnMainThread();
   564     MOZ_ASSERT(aActor);
   565     MOZ_ASSERT(aTransport);
   566     MOZ_ASSERT(aLiveActorArray);
   567   }
   569   NS_DECL_ISUPPORTS_INHERITED
   571 private:
   572   ~ConnectActorRunnable()
   573   {
   574     AssertIsInMainProcess();
   575   }
   577   NS_DECL_NSIRUNNABLE
   578 };
   580 class NS_NO_VTABLE ParentImpl::CreateCallback
   581 {
   582 public:
   583   NS_INLINE_DECL_REFCOUNTING(CreateCallback)
   585   virtual void
   586   Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop) = 0;
   588   virtual void
   589   Failure() = 0;
   591 protected:
   592   virtual ~CreateCallback()
   593   { }
   594 };
   596 // -----------------------------------------------------------------------------
   597 // ChildImpl Helper Declarations
   598 // -----------------------------------------------------------------------------
   600 class ChildImpl::ShutdownObserver MOZ_FINAL : public nsIObserver
   601 {
   602 public:
   603   ShutdownObserver()
   604   {
   605     AssertIsOnMainThread();
   606   }
   608   NS_DECL_ISUPPORTS
   609   NS_DECL_NSIOBSERVER
   611 private:
   612   ~ShutdownObserver()
   613   {
   614     AssertIsOnMainThread();
   615   }
   616 };
   618 class ChildImpl::CreateActorRunnable MOZ_FINAL : public nsRunnable
   619 {
   620   nsCOMPtr<nsIEventTarget> mEventTarget;
   622 public:
   623   CreateActorRunnable()
   624   : mEventTarget(NS_GetCurrentThread())
   625   {
   626     MOZ_ASSERT(mEventTarget);
   627   }
   629   NS_DECL_ISUPPORTS_INHERITED
   631 private:
   632   ~CreateActorRunnable()
   633   { }
   635   NS_DECL_NSIRUNNABLE
   636 };
   638 class ChildImpl::ParentCreateCallback MOZ_FINAL :
   639   public ParentImpl::CreateCallback
   640 {
   641   nsCOMPtr<nsIEventTarget> mEventTarget;
   643 public:
   644   ParentCreateCallback(nsIEventTarget* aEventTarget)
   645   : mEventTarget(aEventTarget)
   646   {
   647     AssertIsInMainProcess();
   648     AssertIsOnMainThread();
   649     MOZ_ASSERT(aEventTarget);
   650   }
   652 private:
   653   ~ParentCreateCallback()
   654   { }
   656   virtual void
   657   Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop)
   658           MOZ_OVERRIDE;
   660   virtual void
   661   Failure() MOZ_OVERRIDE;
   662 };
   664 class ChildImpl::CreateCallbackRunnable : public nsRunnable
   665 {
   666 protected:
   667   nsRefPtr<ChildImpl> mActor;
   669 public:
   670   CreateCallbackRunnable(already_AddRefed<ChildImpl>&& aActor)
   671   : mActor(aActor)
   672   {
   673     // May be created on any thread!
   675     MOZ_ASSERT(mActor);
   676   }
   678   CreateCallbackRunnable()
   679   {
   680     // May be created on any thread!
   681   }
   683   NS_DECL_ISUPPORTS_INHERITED
   685 protected:
   686   virtual ~CreateCallbackRunnable();
   688   static already_AddRefed<nsIIPCBackgroundChildCreateCallback>
   689   GetNextCallback();
   691   NS_DECL_NSIRUNNABLE
   692 };
   694 class ChildImpl::OpenChildProcessActorRunnable MOZ_FINAL :
   695   public ChildImpl::CreateCallbackRunnable
   696 {
   697   nsAutoPtr<Transport> mTransport;
   698   ProcessHandle mProcessHandle;
   700 public:
   701   OpenChildProcessActorRunnable(already_AddRefed<ChildImpl>&& aActor,
   702                                 Transport* aTransport,
   703                                 ProcessHandle aProcessHandle)
   704   : CreateCallbackRunnable(Move(aActor)), mTransport(aTransport),
   705     mProcessHandle(aProcessHandle)
   706   {
   707     AssertIsOnMainThread();
   708     MOZ_ASSERT(aTransport);
   709   }
   711   NS_DECL_ISUPPORTS_INHERITED
   713 private:
   714   ~OpenChildProcessActorRunnable()
   715   {
   716     if (mTransport) {
   717       CRASH_IN_CHILD_PROCESS("Leaking transport!");
   718       unused << mTransport.forget();
   719     }
   720   }
   722   NS_DECL_NSIRUNNABLE
   723 };
   725 class ChildImpl::OpenMainProcessActorRunnable MOZ_FINAL :
   726   public ChildImpl::CreateCallbackRunnable
   727 {
   728   nsRefPtr<ParentImpl> mParentActor;
   729   MessageLoop* mParentMessageLoop;
   731 public:
   732   OpenMainProcessActorRunnable(already_AddRefed<ChildImpl>&& aChildActor,
   733                                already_AddRefed<ParentImpl> aParentActor,
   734                                MessageLoop* aParentMessageLoop)
   735   : CreateCallbackRunnable(Move(aChildActor)), mParentActor(aParentActor),
   736     mParentMessageLoop(aParentMessageLoop)
   737   {
   738     AssertIsOnMainThread();
   739     MOZ_ASSERT(mParentActor);
   740     MOZ_ASSERT(aParentMessageLoop);
   741   }
   743   NS_DECL_ISUPPORTS_INHERITED
   745 private:
   746   ~OpenMainProcessActorRunnable()
   747   { }
   749   NS_DECL_NSIRUNNABLE
   750 };
   752 } // anonymous namespace
   754 namespace mozilla {
   755 namespace ipc {
   757 bool
   758 IsOnBackgroundThread()
   759 {
   760   return ParentImpl::IsOnBackgroundThread();
   761 }
   763 #ifdef DEBUG
   765 void
   766 AssertIsOnBackgroundThread()
   767 {
   768   ParentImpl::AssertIsOnBackgroundThread();
   769 }
   771 #endif // DEBUG
   773 } // namespace ipc
   774 } // namespace mozilla
   776 // -----------------------------------------------------------------------------
   777 // BackgroundParent Public Methods
   778 // -----------------------------------------------------------------------------
   780 // static
   781 bool
   782 BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
   783 {
   784   return ParentImpl::IsOtherProcessActor(aBackgroundActor);
   785 }
   787 // static
   788 already_AddRefed<ContentParent>
   789 BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor)
   790 {
   791   return ParentImpl::GetContentParent(aBackgroundActor);
   792 }
   794 // static
   795 PBackgroundParent*
   796 BackgroundParent::Alloc(ContentParent* aContent,
   797                         Transport* aTransport,
   798                         ProcessId aOtherProcess)
   799 {
   800   return ParentImpl::Alloc(aContent, aTransport, aOtherProcess);
   801 }
   803 // -----------------------------------------------------------------------------
   804 // BackgroundChild Public Methods
   805 // -----------------------------------------------------------------------------
   807 // static
   808 void
   809 BackgroundChild::Startup()
   810 {
   811   ChildImpl::Startup();
   812 }
   814 // static
   815 PBackgroundChild*
   816 BackgroundChild::Alloc(Transport* aTransport, ProcessId aOtherProcess)
   817 {
   818   return ChildImpl::Alloc(aTransport, aOtherProcess);
   819 }
   821 // static
   822 PBackgroundChild*
   823 BackgroundChild::GetForCurrentThread()
   824 {
   825   return ChildImpl::GetForCurrentThread();
   826 }
   828 // static
   829 bool
   830 BackgroundChild::GetOrCreateForCurrentThread(
   831                                  nsIIPCBackgroundChildCreateCallback* aCallback)
   832 {
   833   return ChildImpl::GetOrCreateForCurrentThread(aCallback);
   834 }
   836 // -----------------------------------------------------------------------------
   837 // BackgroundChildImpl Public Methods
   838 // -----------------------------------------------------------------------------
   840 // static
   841 BackgroundChildImpl::ThreadLocal*
   842 BackgroundChildImpl::GetThreadLocalForCurrentThread()
   843 {
   844   return ChildImpl::GetThreadLocalForCurrentThread();
   845 }
   847 // -----------------------------------------------------------------------------
   848 // ParentImpl Static Members
   849 // -----------------------------------------------------------------------------
   851 const ParentImpl::ProcessHandle ParentImpl::kInvalidProcessHandle =
   852 #ifdef XP_WIN
   853   ProcessHandle(INVALID_HANDLE_VALUE);
   854 #else
   855   ProcessHandle(-1);
   856 #endif
   858 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
   860 nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
   862 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
   864 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
   866 MessageLoop* ParentImpl::sBackgroundThreadMessageLoop = nullptr;
   868 uint64_t ParentImpl::sLiveActorCount = 0;
   870 bool ParentImpl::sShutdownObserverRegistered = false;
   872 bool ParentImpl::sShutdownHasStarted = false;
   874 StaticAutoPtr<nsTArray<nsRefPtr<ParentImpl::CreateCallback>>>
   875   ParentImpl::sPendingCallbacks;
   877 // -----------------------------------------------------------------------------
   878 // ChildImpl Static Members
   879 // -----------------------------------------------------------------------------
   881 unsigned int ChildImpl::sThreadLocalIndex = kBadThreadLocalIndex;
   883 StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> ChildImpl::sPendingTargets;
   885 bool ChildImpl::sShutdownHasStarted = false;
   887 // -----------------------------------------------------------------------------
   888 // ParentImpl Implementation
   889 // -----------------------------------------------------------------------------
   891 // static
   892 bool
   893 ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
   894 {
   895   AssertIsOnBackgroundThread();
   896   MOZ_ASSERT(aBackgroundActor);
   898   return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
   899 }
   901 // static
   902 already_AddRefed<ContentParent>
   903 ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor)
   904 {
   905   AssertIsOnBackgroundThread();
   906   MOZ_ASSERT(aBackgroundActor);
   908   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
   909   if (actor->mActorDestroyed) {
   910     MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
   911     return nullptr;
   912   }
   914   if (actor->mContent) {
   915     // We need to hand out a reference to our ContentParent but we also need to
   916     // keep the one we have. We can't call AddRef here because ContentParent is
   917     // not threadsafe so instead we dispatch a runnable to the main thread to do
   918     // it for us. This is safe since we are guaranteed that our AddRef runnable
   919     // will run before the reference we hand out can be released, and the
   920     // ContentParent can't die as long as the existing reference is maintained.
   921     nsCOMPtr<nsIRunnable> runnable =
   922       NS_NewNonOwningRunnableMethod(actor->mContent, &ContentParent::AddRef);
   923     MOZ_ASSERT(runnable);
   925     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
   926   }
   928   return actor->mContent.get();
   929 }
   931 // static
   932 PBackgroundParent*
   933 ParentImpl::Alloc(ContentParent* aContent,
   934                   Transport* aTransport,
   935                   ProcessId aOtherProcess)
   936 {
   937   AssertIsInMainProcess();
   938   AssertIsOnMainThread();
   939   MOZ_ASSERT(aTransport);
   941   ProcessHandle processHandle;
   942   if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
   943     // Process has already died?
   944     return nullptr;
   945   }
   947   if (!sBackgroundThread && !CreateBackgroundThread()) {
   948     NS_WARNING("Failed to create background thread!");
   949     return nullptr;
   950   }
   952   MOZ_ASSERT(sLiveActorsForBackgroundThread);
   954   sLiveActorCount++;
   956   nsRefPtr<ParentImpl> actor = new ParentImpl(aContent, aTransport);
   958   nsCOMPtr<nsIRunnable> connectRunnable =
   959     new ConnectActorRunnable(actor, aTransport, processHandle,
   960                              sLiveActorsForBackgroundThread);
   962   if (NS_FAILED(sBackgroundThread->Dispatch(connectRunnable,
   963                                             NS_DISPATCH_NORMAL))) {
   964     NS_WARNING("Failed to dispatch connect runnable!");
   966     MOZ_ASSERT(sLiveActorCount);
   967     sLiveActorCount--;
   969     if (!sLiveActorCount) {
   970       ShutdownBackgroundThread();
   971     }
   973     return nullptr;
   974   }
   976   return actor;
   977 }
   979 // static
   980 bool
   981 ParentImpl::CreateActorForSameProcess(CreateCallback* aCallback)
   982 {
   983   AssertIsInMainProcess();
   984   AssertIsOnMainThread();
   985   MOZ_ASSERT(aCallback);
   987   if (!sBackgroundThread && !CreateBackgroundThread()) {
   988     NS_WARNING("Failed to create background thread!");
   989     return false;
   990   }
   992   MOZ_ASSERT(!sShutdownHasStarted);
   994   sLiveActorCount++;
   996   if (sBackgroundThreadMessageLoop) {
   997     nsCOMPtr<nsIRunnable> callbackRunnable =
   998       new CreateCallbackRunnable(aCallback);
   999     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(callbackRunnable)));
  1000     return true;
  1003   if (!sPendingCallbacks) {
  1004     sPendingCallbacks = new nsTArray<nsRefPtr<CreateCallback>>();
  1007   sPendingCallbacks->AppendElement(aCallback);
  1008   return true;
  1011 // static
  1012 bool
  1013 ParentImpl::CreateBackgroundThread()
  1015   AssertIsInMainProcess();
  1016   AssertIsOnMainThread();
  1017   MOZ_ASSERT(!sBackgroundThread);
  1018   MOZ_ASSERT(!sLiveActorsForBackgroundThread);
  1020   if (sShutdownHasStarted) {
  1021     NS_WARNING("Trying to create background thread after shutdown has "
  1022                "already begun!");
  1023     return false;
  1026   nsCOMPtr<nsITimer> newShutdownTimer;
  1028   if (!sShutdownTimer) {
  1029     nsresult rv;
  1030     newShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
  1031     if (NS_WARN_IF(NS_FAILED(rv))) {
  1032       return false;
  1036   if (!sShutdownObserverRegistered) {
  1037     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  1038     if (NS_WARN_IF(!obs)) {
  1039       return false;
  1042     nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
  1044     nsresult rv =
  1045       obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
  1046     if (NS_WARN_IF(NS_FAILED(rv))) {
  1047       return false;
  1050     sShutdownObserverRegistered = true;
  1053   nsCOMPtr<nsIThread> thread;
  1054   if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread)))) {
  1055     NS_WARNING("NS_NewNamedThread failed!");
  1056     return false;
  1059   nsCOMPtr<nsIRunnable> messageLoopRunnable =
  1060     new RequestMessageLoopRunnable(thread);
  1061   if (NS_FAILED(thread->Dispatch(messageLoopRunnable, NS_DISPATCH_NORMAL))) {
  1062     NS_WARNING("Failed to dispatch RequestMessageLoopRunnable!");
  1063     return false;
  1066   sBackgroundThread = thread;
  1067   sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
  1069   if (!sShutdownTimer) {
  1070     MOZ_ASSERT(newShutdownTimer);
  1071     sShutdownTimer = newShutdownTimer;
  1074   return true;
  1077 // static
  1078 void
  1079 ParentImpl::ShutdownBackgroundThread()
  1081   AssertIsInMainProcess();
  1082   AssertIsOnMainThread();
  1083   MOZ_ASSERT_IF(!sBackgroundThread, !sBackgroundThreadMessageLoop);
  1084   MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
  1085   MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
  1086   MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
  1088   if (sPendingCallbacks) {
  1089     if (!sPendingCallbacks->IsEmpty()) {
  1090       nsTArray<nsRefPtr<CreateCallback>> callbacks;
  1091       sPendingCallbacks->SwapElements(callbacks);
  1093       for (uint32_t index = 0; index < callbacks.Length(); index++) {
  1094         nsRefPtr<CreateCallback> callback;
  1095         callbacks[index].swap(callback);
  1096         MOZ_ASSERT(callback);
  1098         callback->Failure();
  1102     if (sShutdownHasStarted) {
  1103       sPendingCallbacks = nullptr;
  1107   nsCOMPtr<nsITimer> shutdownTimer;
  1108   if (sShutdownHasStarted) {
  1109     shutdownTimer = sShutdownTimer.get();
  1110     sShutdownTimer = nullptr;
  1113   if (sBackgroundThread) {
  1114     nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
  1115     nsAutoPtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread);
  1117     sBackgroundThread = nullptr;
  1118     sLiveActorsForBackgroundThread = nullptr;
  1119     sBackgroundThreadMessageLoop = nullptr;
  1121     MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
  1123     if (sShutdownHasStarted) {
  1124       // If this is final shutdown then we need to spin the event loop while we
  1125       // wait for all the actors to be cleaned up. We also set a timeout to
  1126       // force-kill any hanging actors.
  1128       if (sLiveActorCount) {
  1129         TimerCallbackClosure closure(thread, liveActors);
  1131         MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
  1132           shutdownTimer->InitWithFuncCallback(&ShutdownTimerCallback, &closure,
  1133                                               kShutdownTimerDelayMS,
  1134                                               nsITimer::TYPE_ONE_SHOT)));
  1136         nsIThread* currentThread = NS_GetCurrentThread();
  1137         MOZ_ASSERT(currentThread);
  1139         while (sLiveActorCount) {
  1140           NS_ProcessNextEvent(currentThread);
  1143         MOZ_ASSERT(liveActors->IsEmpty());
  1145         MOZ_ALWAYS_TRUE(NS_SUCCEEDED(shutdownTimer->Cancel()));
  1149     // Dispatch this runnable to unregister the thread from the profiler.
  1150     nsCOMPtr<nsIRunnable> shutdownRunnable =
  1151       new ShutdownBackgroundThreadRunnable();
  1152     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Dispatch(shutdownRunnable,
  1153                                                   NS_DISPATCH_NORMAL)));
  1155     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Shutdown()));
  1159 // static
  1160 void
  1161 ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure)
  1163   AssertIsInMainProcess();
  1164   AssertIsOnMainThread();
  1165   MOZ_ASSERT(sShutdownHasStarted);
  1166   MOZ_ASSERT(sLiveActorCount);
  1168   auto closure = static_cast<TimerCallbackClosure*>(aClosure);
  1169   MOZ_ASSERT(closure);
  1171   // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
  1172   // finished.
  1173   sLiveActorCount++;
  1175   nsCOMPtr<nsIRunnable> forceCloseRunnable =
  1176     new ForceCloseBackgroundActorsRunnable(closure->mLiveActors);
  1177   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(closure->mThread->Dispatch(forceCloseRunnable,
  1178                                                           NS_DISPATCH_NORMAL)));
  1181 void
  1182 ParentImpl::Destroy()
  1184   // May be called on any thread!
  1186   AssertIsInMainProcess();
  1188   nsCOMPtr<nsIRunnable> destroyRunnable =
  1189     NS_NewNonOwningRunnableMethod(this, &ParentImpl::MainThreadActorDestroy);
  1190   MOZ_ASSERT(destroyRunnable);
  1192   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(destroyRunnable)));
  1195 void
  1196 ParentImpl::MainThreadActorDestroy()
  1198   AssertIsInMainProcess();
  1199   AssertIsOnMainThread();
  1200   MOZ_ASSERT_IF(mIsOtherProcessActor, mContent);
  1201   MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
  1202   MOZ_ASSERT_IF(mIsOtherProcessActor, mTransport);
  1203   MOZ_ASSERT_IF(!mIsOtherProcessActor, !mTransport);
  1205   if (mTransport) {
  1206     XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
  1207                                      new DeleteTask<Transport>(mTransport));
  1208     mTransport = nullptr;
  1211   ProcessHandle otherProcess = OtherProcess();
  1212   if (otherProcess != kInvalidProcessHandle) {
  1213     base::CloseProcessHandle(otherProcess);
  1214 #ifdef DEBUG
  1215     SetOtherProcess(kInvalidProcessHandle);
  1216 #endif
  1219   mContent = nullptr;
  1221   MOZ_ASSERT(sLiveActorCount);
  1222   sLiveActorCount--;
  1224   if (!sLiveActorCount) {
  1225     ShutdownBackgroundThread();
  1228   // This may be the last reference!
  1229   Release();
  1232 IToplevelProtocol*
  1233 ParentImpl::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
  1234                           ProcessHandle aPeerProcess,
  1235                           ProtocolCloneContext* aCtx)
  1237   AssertIsInMainProcess();
  1238   AssertIsOnMainThread();
  1240   const ProtocolId protocolId = GetProtocolId();
  1242   for (unsigned int i = 0; i < aFds.Length(); i++) {
  1243     if (static_cast<ProtocolId>(aFds[i].protocolId()) != protocolId) {
  1244       continue;
  1247     Transport* transport = OpenDescriptor(aFds[i].fd(),
  1248                                           Transport::MODE_SERVER);
  1249     if (!transport) {
  1250       NS_WARNING("Failed to open transport!");
  1251       break;
  1254     PBackgroundParent* clonedActor =
  1255       Alloc(mContent, transport, base::GetProcId(aPeerProcess));
  1256     MOZ_ASSERT(clonedActor);
  1258     clonedActor->CloneManagees(this, aCtx);
  1259     clonedActor->SetTransport(transport);
  1261     return clonedActor;
  1264   return nullptr;
  1267 void
  1268 ParentImpl::ActorDestroy(ActorDestroyReason aWhy)
  1270   AssertIsInMainProcess();
  1271   AssertIsOnBackgroundThread();
  1272   MOZ_ASSERT(!mActorDestroyed);
  1273   MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
  1275   BackgroundParentImpl::ActorDestroy(aWhy);
  1277   mActorDestroyed = true;
  1279   if (mLiveActorArray) {
  1280     MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
  1281     mLiveActorArray = nullptr;
  1284   // This is tricky. We should be able to call Destroy() here directly because
  1285   // we're not going to touch 'this' or our MessageChannel any longer on this
  1286   // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
  1287   // it runs it will destroy 'this' and our associated MessageChannel. However,
  1288   // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
  1289   // racing with the main thread we must ensure that the MessageChannel lives
  1290   // long enough to be cleared in this call stack.
  1291   nsCOMPtr<nsIRunnable> destroyRunnable =
  1292     NS_NewNonOwningRunnableMethod(this, &ParentImpl::Destroy);
  1293   MOZ_ASSERT(destroyRunnable);
  1295   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(destroyRunnable)));
  1298 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
  1300 NS_IMETHODIMP
  1301 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject,
  1302                                       const char* aTopic,
  1303                                       const char16_t* aData)
  1305   AssertIsInMainProcess();
  1306   AssertIsOnMainThread();
  1307   MOZ_ASSERT(!sShutdownHasStarted);
  1308   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
  1310   sShutdownHasStarted = true;
  1312   // Do this first before calling (and spinning the event loop in)
  1313   // ShutdownBackgroundThread().
  1314   ChildImpl::Shutdown();
  1316   ShutdownBackgroundThread();
  1318   return NS_OK;
  1321 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::RequestMessageLoopRunnable,
  1322                              nsRunnable)
  1324 NS_IMETHODIMP
  1325 ParentImpl::RequestMessageLoopRunnable::Run()
  1327   AssertIsInMainProcess();
  1328   MOZ_ASSERT(mTargetThread);
  1330   if (NS_IsMainThread()) {
  1331     MOZ_ASSERT(mMessageLoop);
  1333     if (!sBackgroundThread ||
  1334         !SameCOMIdentity(mTargetThread.get(), sBackgroundThread.get())) {
  1335       return NS_OK;
  1338     MOZ_ASSERT(!sBackgroundThreadMessageLoop);
  1339     sBackgroundThreadMessageLoop = mMessageLoop;
  1341     if (sPendingCallbacks && !sPendingCallbacks->IsEmpty()) {
  1342       nsTArray<nsRefPtr<CreateCallback>> callbacks;
  1343       sPendingCallbacks->SwapElements(callbacks);
  1345       for (uint32_t index = 0; index < callbacks.Length(); index++) {
  1346         MOZ_ASSERT(callbacks[index]);
  1348         nsCOMPtr<nsIRunnable> callbackRunnable =
  1349           new CreateCallbackRunnable(callbacks[index]);
  1350         if (NS_FAILED(NS_DispatchToCurrentThread(callbackRunnable))) {
  1351           NS_WARNING("Failed to dispatch callback runnable!");
  1356     return NS_OK;
  1359   char stackBaseGuess;
  1360   profiler_register_thread("IPDL Background", &stackBaseGuess);
  1362 #ifdef DEBUG
  1364     bool correctThread;
  1365     MOZ_ASSERT(NS_SUCCEEDED(mTargetThread->IsOnCurrentThread(&correctThread)));
  1366     MOZ_ASSERT(correctThread);
  1368 #endif
  1370   DebugOnly<PRThread*> oldBackgroundThread =
  1371     sBackgroundPRThread.exchange(PR_GetCurrentThread());
  1373   MOZ_ASSERT_IF(oldBackgroundThread,
  1374                 PR_GetCurrentThread() != oldBackgroundThread);
  1376   MOZ_ASSERT(!mMessageLoop);
  1378   mMessageLoop = MessageLoop::current();
  1379   MOZ_ASSERT(mMessageLoop);
  1381   if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
  1382     NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!");
  1383     return NS_ERROR_FAILURE;
  1386   return NS_OK;
  1389 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ShutdownBackgroundThreadRunnable,
  1390                              nsRunnable)
  1392 NS_IMETHODIMP
  1393 ParentImpl::ShutdownBackgroundThreadRunnable::Run()
  1395   AssertIsInMainProcess();
  1397   // It is possible that another background thread was created while this thread
  1398   // was shutting down. In that case we can't assert anything about
  1399   // sBackgroundPRThread and we should not modify it here.
  1400   sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
  1402   profiler_unregister_thread();
  1404   return NS_OK;
  1407 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ForceCloseBackgroundActorsRunnable,
  1408                              nsRunnable)
  1410 NS_IMETHODIMP
  1411 ParentImpl::ForceCloseBackgroundActorsRunnable::Run()
  1413   AssertIsInMainProcess();
  1414   MOZ_ASSERT(mActorArray);
  1416   if (NS_IsMainThread()) {
  1417     MOZ_ASSERT(sLiveActorCount);
  1418     sLiveActorCount--;
  1419     return NS_OK;
  1422   AssertIsOnBackgroundThread();
  1424   if (!mActorArray->IsEmpty()) {
  1425     // Copy the array since calling Close() could mutate the actual array.
  1426     nsTArray<ParentImpl*> actorsToClose(*mActorArray);
  1428     for (uint32_t index = 0; index < actorsToClose.Length(); index++) {
  1429       actorsToClose[index]->Close();
  1433   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this)));
  1435   return NS_OK;
  1438 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::CreateCallbackRunnable, nsRunnable)
  1440 NS_IMETHODIMP
  1441 ParentImpl::CreateCallbackRunnable::Run()
  1443   AssertIsInMainProcess();
  1444   AssertIsOnMainThread();
  1445   MOZ_ASSERT(sBackgroundThreadMessageLoop);
  1446   MOZ_ASSERT(mCallback);
  1448   nsRefPtr<CreateCallback> callback;
  1449   mCallback.swap(callback);
  1451   nsRefPtr<ParentImpl> actor = new ParentImpl();
  1453   callback->Success(actor.forget(), sBackgroundThreadMessageLoop);
  1455   return NS_OK;
  1458 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ConnectActorRunnable, nsRunnable)
  1460 NS_IMETHODIMP
  1461 ParentImpl::ConnectActorRunnable::Run()
  1463   AssertIsInMainProcess();
  1464   AssertIsOnBackgroundThread();
  1466   // Transfer ownership to this thread. If Open() fails then we will release
  1467   // this reference in Destroy.
  1468   ParentImpl* actor;
  1469   mActor.forget(&actor);
  1471   if (!actor->Open(mTransport, mProcessHandle, XRE_GetIOMessageLoop(),
  1472                    ParentSide)) {
  1473     actor->Destroy();
  1474     return NS_ERROR_FAILURE;
  1477   actor->SetLiveActorArray(mLiveActorArray);
  1479   return NS_OK;
  1482 // -----------------------------------------------------------------------------
  1483 // ChildImpl Implementation
  1484 // -----------------------------------------------------------------------------
  1486 // static
  1487 void
  1488 ChildImpl::Startup()
  1490   // This happens on the main thread but before XPCOM has started so we can't
  1491   // assert that we're being called on the main thread here.
  1493   MOZ_ASSERT(sThreadLocalIndex == kBadThreadLocalIndex,
  1494              "BackgroundChild::Startup() called more than once!");
  1496   PRStatus status =
  1497     PR_NewThreadPrivateIndex(&sThreadLocalIndex, ThreadLocalDestructor);
  1498   MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
  1500   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
  1502   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
  1503   MOZ_RELEASE_ASSERT(observerService);
  1505   nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
  1507   nsresult rv =
  1508     observerService->AddObserver(observer,
  1509                                  NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
  1510                                  false);
  1511   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
  1514 // static
  1515 void
  1516 ChildImpl::Shutdown()
  1518   AssertIsOnMainThread();
  1520   if (sShutdownHasStarted) {
  1521     MOZ_ASSERT_IF(sThreadLocalIndex != kBadThreadLocalIndex,
  1522                   !PR_GetThreadPrivate(sThreadLocalIndex));
  1523     return;
  1526   sShutdownHasStarted = true;
  1528   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
  1530   DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
  1531   MOZ_ASSERT(status == PR_SUCCESS);
  1534 // static
  1535 PBackgroundChild*
  1536 ChildImpl::Alloc(Transport* aTransport, ProcessId aOtherProcess)
  1538   AssertIsInChildProcess();
  1539   AssertIsOnMainThread();
  1540   MOZ_ASSERT(aTransport);
  1541   MOZ_ASSERT(sPendingTargets);
  1542   MOZ_ASSERT(!sPendingTargets->IsEmpty());
  1544   nsCOMPtr<nsIEventTarget> eventTarget;
  1545   sPendingTargets->ElementAt(0).swap(eventTarget);
  1547   sPendingTargets->RemoveElementAt(0);
  1549   ProcessHandle processHandle;
  1550   if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
  1551     MOZ_CRASH("Failed to open process handle!");
  1554   nsRefPtr<ChildImpl> actor = new ChildImpl();
  1556   ChildImpl* weakActor = actor;
  1558   nsCOMPtr<nsIRunnable> openRunnable =
  1559     new OpenChildProcessActorRunnable(actor.forget(), aTransport,
  1560                                       processHandle);
  1561   if (NS_FAILED(eventTarget->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) {
  1562     MOZ_CRASH("Failed to dispatch OpenActorRunnable!");
  1565   // This value is only checked against null to determine success/failure, so
  1566   // there is no need to worry about the reference count here.
  1567   return weakActor;
  1570 // static
  1571 PBackgroundChild*
  1572 ChildImpl::GetForCurrentThread()
  1574   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
  1576   auto threadLocalInfo =
  1577     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
  1579   return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
  1582 // static
  1583 bool
  1584 ChildImpl::GetOrCreateForCurrentThread(
  1585                                  nsIIPCBackgroundChildCreateCallback* aCallback)
  1587   MOZ_ASSERT(aCallback);
  1588   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
  1589              "BackgroundChild::Startup() was never called!");
  1591   bool created = false;
  1593   auto threadLocalInfo =
  1594     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
  1596   if (threadLocalInfo) {
  1597     threadLocalInfo->mCallbacks.AppendElement(aCallback);
  1598   } else {
  1599     nsAutoPtr<ThreadLocalInfo> newInfo(new ThreadLocalInfo(aCallback));
  1601     if (PR_SetThreadPrivate(sThreadLocalIndex, newInfo) != PR_SUCCESS) {
  1602       CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
  1603       return false;
  1606     created = true;
  1607     threadLocalInfo = newInfo.forget();
  1610   if (threadLocalInfo->mActor) {
  1611     nsRefPtr<ChildImpl> actor = threadLocalInfo->mActor;
  1613     nsCOMPtr<nsIRunnable> runnable = new CreateCallbackRunnable(actor.forget());
  1614     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
  1616     return true;
  1619   if (!created) {
  1620     // We have already started the sequence for opening the actor so there's
  1621     // nothing else we need to do here. This callback will be called after the
  1622     // first callback in CreateCallbackRunnable::Run().
  1623     return true;
  1626   if (NS_IsMainThread()) {
  1627     if (NS_WARN_IF(!OpenProtocolOnMainThread(NS_GetCurrentThread()))) {
  1628       return false;
  1631     return true;
  1634   nsRefPtr<CreateActorRunnable> runnable = new CreateActorRunnable();
  1635   if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
  1636     CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
  1637     return false;
  1640   return true;
  1643 // static
  1644 BackgroundChildImpl::ThreadLocal*
  1645 ChildImpl::GetThreadLocalForCurrentThread()
  1647   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
  1648              "BackgroundChild::Startup() was never called!");
  1650   auto threadLocalInfo =
  1651     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
  1653   if (!threadLocalInfo) {
  1654     return nullptr;
  1657   if (!threadLocalInfo->mConsumerThreadLocal) {
  1658     threadLocalInfo->mConsumerThreadLocal =
  1659       new BackgroundChildImpl::ThreadLocal();
  1662   return threadLocalInfo->mConsumerThreadLocal;
  1665 ChildImpl::CreateCallbackRunnable::~CreateCallbackRunnable()
  1667   if (mActor) {
  1668     CRASH_IN_CHILD_PROCESS("Leaking actor!");
  1669     unused << mActor.forget();
  1673 // static
  1674 already_AddRefed<nsIIPCBackgroundChildCreateCallback>
  1675 ChildImpl::CreateCallbackRunnable::GetNextCallback()
  1677   // May run on any thread!
  1679   auto threadLocalInfo =
  1680     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
  1681   MOZ_ASSERT(threadLocalInfo);
  1683   if (threadLocalInfo->mCallbacks.IsEmpty()) {
  1684     return nullptr;
  1687   nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback;
  1688   threadLocalInfo->mCallbacks[0].swap(callback);
  1690   threadLocalInfo->mCallbacks.RemoveElementAt(0);
  1692   return callback.forget();
  1695 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateCallbackRunnable, nsRunnable)
  1697 NS_IMETHODIMP
  1698 ChildImpl::CreateCallbackRunnable::Run()
  1700   // May run on any thread!
  1702   nsRefPtr<ChildImpl> actor;
  1703   mActor.swap(actor);
  1705   nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback();
  1706   while (callback) {
  1707     if (actor) {
  1708       callback->ActorCreated(actor);
  1709     } else {
  1710       callback->ActorFailed();
  1713     callback = GetNextCallback();
  1716   return NS_OK;
  1719 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenChildProcessActorRunnable,
  1720                              ChildImpl::CreateCallbackRunnable)
  1722 NS_IMETHODIMP
  1723 ChildImpl::OpenChildProcessActorRunnable::Run()
  1725   // May be run on any thread!
  1727   AssertIsInChildProcess();
  1728   MOZ_ASSERT(mActor);
  1729   MOZ_ASSERT(mTransport);
  1731   nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback();
  1732   MOZ_ASSERT(callback,
  1733              "There should be at least one callback when first creating the "
  1734              "actor!");
  1736   nsRefPtr<ChildImpl> strongActor;
  1737   mActor.swap(strongActor);
  1739   if (!strongActor->Open(mTransport.forget(), mProcessHandle,
  1740                          XRE_GetIOMessageLoop(), ChildSide)) {
  1741     CRASH_IN_CHILD_PROCESS("Failed to open ChildImpl!");
  1743     while (callback) {
  1744       callback->ActorFailed();
  1745       callback = GetNextCallback();
  1748     return NS_OK;
  1751   // Now that Open() has succeeded transfer the ownership of the actor to IPDL.
  1752   auto threadLocalInfo =
  1753     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
  1755   MOZ_ASSERT(threadLocalInfo);
  1756   MOZ_ASSERT(!threadLocalInfo->mActor);
  1758   nsRefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
  1759   strongActor.swap(actor);
  1761   actor->SetBoundThread();
  1763   while (callback) {
  1764     callback->ActorCreated(actor);
  1765     callback = GetNextCallback();
  1768   return NS_OK;
  1771 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenMainProcessActorRunnable,
  1772                              ChildImpl::CreateCallbackRunnable)
  1774 NS_IMETHODIMP
  1775 ChildImpl::OpenMainProcessActorRunnable::Run()
  1777   // May run on any thread!
  1779   AssertIsInMainProcess();
  1780   MOZ_ASSERT(mActor);
  1781   MOZ_ASSERT(mParentActor);
  1782   MOZ_ASSERT(mParentMessageLoop);
  1784   nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback();
  1785   MOZ_ASSERT(callback,
  1786              "There should be at least one callback when first creating the "
  1787              "actor!");
  1789   nsRefPtr<ChildImpl> strongChildActor;
  1790   mActor.swap(strongChildActor);
  1792   nsRefPtr<ParentImpl> parentActor;
  1793   mParentActor.swap(parentActor);
  1795   MessageChannel* parentChannel = parentActor->GetIPCChannel();
  1796   MOZ_ASSERT(parentChannel);
  1798   if (!strongChildActor->Open(parentChannel, mParentMessageLoop, ChildSide)) {
  1799     NS_WARNING("Failed to open ChildImpl!");
  1801     parentActor->Destroy();
  1803     while (callback) {
  1804       callback->ActorFailed();
  1805       callback = GetNextCallback();
  1808     return NS_OK;
  1811   // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
  1812   unused << parentActor.forget();
  1814   auto threadLocalInfo =
  1815     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
  1817   MOZ_ASSERT(threadLocalInfo);
  1818   MOZ_ASSERT(!threadLocalInfo->mActor);
  1820   nsRefPtr<ChildImpl>& childActor = threadLocalInfo->mActor;
  1821   strongChildActor.swap(childActor);
  1823   childActor->SetBoundThread();
  1825   while (callback) {
  1826     callback->ActorCreated(childActor);
  1827     callback = GetNextCallback();
  1830   return NS_OK;
  1833 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateActorRunnable, nsRunnable)
  1835 NS_IMETHODIMP
  1836 ChildImpl::CreateActorRunnable::Run()
  1838   AssertIsOnMainThread();
  1840   if (!OpenProtocolOnMainThread(mEventTarget)) {
  1841     NS_WARNING("OpenProtocolOnMainThread failed!");
  1842     return NS_ERROR_FAILURE;
  1845   return NS_OK;
  1848 void
  1849 ChildImpl::ParentCreateCallback::Success(
  1850                                       already_AddRefed<ParentImpl> aParentActor,
  1851                                       MessageLoop* aParentMessageLoop)
  1853   AssertIsInMainProcess();
  1854   AssertIsOnMainThread();
  1856   nsRefPtr<ParentImpl> parentActor = aParentActor;
  1857   MOZ_ASSERT(parentActor);
  1858   MOZ_ASSERT(aParentMessageLoop);
  1859   MOZ_ASSERT(mEventTarget);
  1861   nsRefPtr<ChildImpl> childActor = new ChildImpl();
  1863   nsCOMPtr<nsIEventTarget> target;
  1864   mEventTarget.swap(target);
  1866   nsCOMPtr<nsIRunnable> openRunnable =
  1867     new OpenMainProcessActorRunnable(childActor.forget(), parentActor.forget(),
  1868                                      aParentMessageLoop);
  1869   if (NS_FAILED(target->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) {
  1870     NS_WARNING("Failed to dispatch open runnable!");
  1874 void
  1875 ChildImpl::ParentCreateCallback::Failure()
  1877   AssertIsInMainProcess();
  1878   AssertIsOnMainThread();
  1879   MOZ_ASSERT(mEventTarget);
  1881   nsCOMPtr<nsIEventTarget> target;
  1882   mEventTarget.swap(target);
  1884   DispatchFailureCallback(target);
  1887 // static
  1888 bool
  1889 ChildImpl::OpenProtocolOnMainThread(nsIEventTarget* aEventTarget)
  1891   AssertIsOnMainThread();
  1892   MOZ_ASSERT(aEventTarget);
  1894   if (sShutdownHasStarted) {
  1895     MOZ_CRASH("Called BackgroundChild::GetOrCreateForCurrentThread after "
  1896               "shutdown has started!");
  1899   if (IsMainProcess()) {
  1900     nsRefPtr<ParentImpl::CreateCallback> parentCallback =
  1901       new ParentCreateCallback(aEventTarget);
  1903     if (!ParentImpl::CreateActorForSameProcess(parentCallback)) {
  1904       NS_WARNING("BackgroundParent::CreateActor() failed!");
  1905       DispatchFailureCallback(aEventTarget);
  1906       return false;
  1909     return true;
  1912   ContentChild* content = ContentChild::GetSingleton();
  1913   MOZ_ASSERT(content);
  1915   if (!PBackground::Open(content)) {
  1916     MOZ_CRASH("Failed to create top level actor!");
  1917     return false;
  1920   if (!sPendingTargets) {
  1921     sPendingTargets = new nsTArray<nsCOMPtr<nsIEventTarget>>(1);
  1922     ClearOnShutdown(&sPendingTargets);
  1925   sPendingTargets->AppendElement(aEventTarget);
  1927   return true;
  1930 // static
  1931 void
  1932 ChildImpl::DispatchFailureCallback(nsIEventTarget* aEventTarget)
  1934   MOZ_ASSERT(aEventTarget);
  1936   nsCOMPtr<nsIRunnable> callbackRunnable = new CreateCallbackRunnable();
  1937   if (NS_FAILED(aEventTarget->Dispatch(callbackRunnable, NS_DISPATCH_NORMAL))) {
  1938     NS_WARNING("Failed to dispatch CreateCallbackRunnable!");
  1942 void
  1943 ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
  1945   AssertIsOnBoundThread();
  1947   BackgroundChildImpl::ActorDestroy(aWhy);
  1950 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
  1952 NS_IMETHODIMP
  1953 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject,
  1954                                      const char* aTopic,
  1955                                      const char16_t* aData)
  1957   AssertIsOnMainThread();
  1958   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
  1960   ChildImpl::Shutdown();
  1962   return NS_OK;

mercurial