Bug 774388 - Patch 9: Introduce NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION - r=mattwoodrow
authorBenoit Jacob <bjacob@mozilla.com>
Fri, 04 Jul 2014 14:04:12 -0400
changeset 213320 629840cfa32847aa8cb3a1071e4f144c199d7bfb
parent 213319 e79664633662927bcb37a09d7a6e0b0687764e70
child 213321 c7be5077fab0ad1f6493e93f8ddd99e0ed006558
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs774388
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 774388 - Patch 9: Introduce NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION - r=mattwoodrow
gfx/layers/ipc/CompositorChild.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
gfx/layers/moz.build
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -12,29 +12,31 @@
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsClassHashtable.h"           // for nsClassHashtable
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsHashKeys.h"                 // for nsUint64HashKey
 #include "nsISupportsImpl.h"            // for NS_INLINE_DECL_REFCOUNTING
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 class nsIObserver;
 
 namespace mozilla {
 namespace layers {
 
 class ClientLayerManager;
 class CompositorParent;
 struct FrameMetrics;
 
 class CompositorChild MOZ_FINAL : public PCompositorChild
 {
-  NS_INLINE_DECL_REFCOUNTING(CompositorChild)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorChild)
+
 public:
   CompositorChild(ClientLayerManager *aLayerManager);
 
   void Destroy();
 
   /**
    * Lookup the FrameMetrics shared by the compositor process with the
    * associated FrameMetrics::ViewID. The returned FrameMetrics is used
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -98,17 +98,17 @@ static void DestroyCompositorMap()
   sCompositorMap = nullptr;
 }
 
 // See ImageBridgeChild.cpp
 void ReleaseImageBridgeParentSingleton();
 
 class CompositorThreadHolder MOZ_FINAL
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorThreadHolder)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder)
 
 public:
   CompositorThreadHolder()
     : mCompositorThread(CreateCompositorThread())
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_COUNT_CTOR(CompositorThreadHolder);
   }
@@ -133,23 +133,20 @@ private:
   static void DestroyCompositorThread(Thread* aCompositorThread);
 
   friend class CompositorParent;
 };
 
 static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
 static bool sFinishedCompositorShutDown = false;
 
-static MessageLoop* sMainLoop = nullptr;
-
 /* static */ Thread*
 CompositorThreadHolder::CreateCompositorThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  sMainLoop = MessageLoop::current();
 
   MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
 
   Thread* compositorThread = new Thread("Compositor");
 
   Thread::Options options;
   /* Timeout values are powers-of-two to enable us get better data.
      128ms is chosen for transient hangs because 8Hz should be the minimally
@@ -316,45 +313,35 @@ CompositorParent::RecvWillStop()
     mLayerManager->Destroy();
     mLayerManager = nullptr;
     mCompositionManager = nullptr;
   }
 
   return true;
 }
 
-void DeferredDeleteCompositorParentOnMainThread(CompositorParent* aNowReadyToDie)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  aNowReadyToDie->mCompositorThreadHolder = nullptr;
-  aNowReadyToDie->Release();
-}
-
-static void DeferredDeleteCompositorParentOnIOThread(CompositorParent* aToBeDeletedOnMainThread)
+void CompositorParent::DeferredDestroy()
 {
   MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(sMainLoop);
-  sMainLoop->PostTask(FROM_HERE,
-                      NewRunnableFunction(&DeferredDeleteCompositorParentOnMainThread,
-                                          aToBeDeletedOnMainThread));
+  mCompositorThreadHolder = nullptr;
+  Release();
 }
 
 bool
 CompositorParent::RecvStop()
 {
   Destroy();
   // There are chances that the ref count reaches zero on the main thread shortly
   // after this function returns while some ipdl code still needs to run on
   // this thread.
   // We must keep the compositor parent alive untill the code handling message
   // reception is finished on this thread.
-  this->AddRef(); // Corresponds to DeferredDeleteCompositorParentOnMainThread's Release
+  this->AddRef(); // Corresponds to DeferredDestroy's Release
   MessageLoop::current()->PostTask(FROM_HERE,
-                                   NewRunnableFunction(&DeferredDeleteCompositorParentOnIOThread,
-                                                       this));
+                                   NewRunnableMethod(this,&CompositorParent::DeferredDestroy));
   return true;
 }
 
 bool
 CompositorParent::RecvPause()
 {
   PauseComposition();
   return true;
@@ -1124,17 +1111,17 @@ CompositorParent::ComputeRenderIntegrity
  * drive compositing itself.  For that it hands off work to the
  * CompositorParent it's associated with.
  */
 class CrossProcessCompositorParent MOZ_FINAL : public PCompositorParent,
                                                public ShadowLayersManager
 {
   friend class CompositorParent;
 
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CrossProcessCompositorParent)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorParent)
 public:
   CrossProcessCompositorParent(Transport* aTransport, ProcessId aOtherProcess)
     : mTransport(aTransport)
     , mChildProcessId(aOtherProcess)
     , mCompositorThreadHolder(sCompositorThreadHolder)
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
@@ -1196,17 +1183,17 @@ private:
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
   // ourself.  This is released (deferred) in ActorDestroy().
   nsRefPtr<CrossProcessCompositorParent> mSelfRef;
   Transport* mTransport;
   // Child side's process Id.
   base::ProcessId mChildProcessId;
 
-  const nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+  nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
 };
 
 void
 CompositorParent::DidComposite()
 {
   if (mPendingTransaction) {
     unused << SendDidComposite(0, mPendingTransaction);
     mPendingTransaction = 0;
@@ -1458,22 +1445,18 @@ CrossProcessCompositorParent::GetComposi
 
   MOZ_ASSERT(state->mParent);
   return state->mParent->GetCompositionManager(aLayerTree);
 }
 
 void
 CrossProcessCompositorParent::DeferredDestroy()
 {
-  CrossProcessCompositorParent* self;
-  mSelfRef.forget(&self);
-
-  MOZ_ASSERT(sMainLoop);
-  sMainLoop->PostTask(FROM_HERE,
-                      NewRunnableMethod(self, &CrossProcessCompositorParent::Release));
+  mCompositorThreadHolder = nullptr;
+  mSelfRef = nullptr;
 }
 
 CrossProcessCompositorParent::~CrossProcessCompositorParent()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(XRE_GetIOMessageLoop());
   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
                                    new DeleteTask<Transport>(mTransport));
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -28,16 +28,17 @@
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/PCompositorParent.h"
 #include "mozilla/layers/APZTestData.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"
 #include "nsSize.h"                     // for nsIntSize
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 class CancelableTask;
 class MessageLoop;
 class gfxContext;
 class nsIWidget;
 
 namespace mozilla {
 namespace gfx {
@@ -63,17 +64,17 @@ private:
   uint64_t mLayersId;
 };
 
 class CompositorThreadHolder;
 
 class CompositorParent : public PCompositorParent,
                          public ShadowLayersManager
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorParent)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
 
 public:
   CompositorParent(nsIWidget* aWidget,
                    bool aUseExternalSurfaceSize = false,
                    int aSurfaceWidth = -1, int aSurfaceHeight = -1);
 
   // IToplevelProtocol::CloneToplevel()
   virtual IToplevelProtocol*
@@ -239,16 +240,18 @@ public:
    * Returns true if the calling thread is the compositor thread.
    */
   static bool IsInCompositorThread();
 
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~CompositorParent();
 
+  void DeferredDestroy();
+
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
                                  const uint64_t& aId,
                                  TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                  bool* aSuccess) MOZ_OVERRIDE;
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
   virtual void ScheduleTask(CancelableTask*, int);
   void CompositeCallback();
@@ -309,16 +312,14 @@ protected:
   bool mOverrideComposeReadiness;
   CancelableTask* mForceCompositionTask;
 
   nsRefPtr<APZCTreeManager> mApzcTreeManager;
 
   nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
 
   DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
-
-  friend void DeferredDeleteCompositorParentOnMainThread(CompositorParent* aNowReadyToDie);
 };
 
 } // layers
 } // mozilla
 
 #endif // mozilla_layers_CompositorParent_h
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -12,16 +12,17 @@
 #include "mozilla/RefPtr.h"             // for TemporaryRef
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureIdentifier, etc
 #include "mozilla/layers/PImageBridgeChild.h"
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsRegion.h"                   // for nsIntRegion
+
 class MessageLoop;
 struct nsIntPoint;
 struct nsIntRect;
 
 namespace base {
 class Thread;
 }
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
+#define THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
+
+#include "MainThreadUtils.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+
+namespace mozilla {
+namespace layers {
+
+inline MessageLoop* GetMainLoopAssertingMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  return MessageLoop::current();
+}
+
+inline MessageLoop* GetMainLoop()
+{
+  static MessageLoop* sMainLoop = GetMainLoopAssertingMainThread();
+  return sMainLoop;
+}
+
+struct HelperForMainThreadDestruction
+{
+  HelperForMainThreadDestruction()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    GetMainLoop();
+  }
+
+  ~HelperForMainThreadDestruction()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+  }
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(_class) \
+public:                                                                       \
+  NS_METHOD_(MozExternalRefCountType) AddRef(void) {                          \
+    MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                \
+    MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                      \
+    nsrefcnt count = ++mRefCnt;                                               \
+    NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
+    return (nsrefcnt) count;                                                  \
+  }                                                                           \
+  static void DestroyToBeCalledOnMainThread(_class* ptr) {                    \
+    MOZ_ASSERT(NS_IsMainThread());                                            \
+    NS_LOG_RELEASE(ptr, 0, #_class);                                          \
+    delete ptr;                                                               \
+  }                                                                           \
+  NS_METHOD_(MozExternalRefCountType) Release(void) {                         \
+    MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                          \
+    nsrefcnt count = --mRefCnt;                                               \
+    if (count == 0) {                                                         \
+      if (NS_IsMainThread()) {                                                \
+        NS_LOG_RELEASE(this, 0, #_class);                                     \
+        delete this;                                                          \
+      } else {                                                                \
+        /* no NS_LOG_RELEASE here, will be in the runnable */                 \
+        MessageLoop *l = ::mozilla::layers::GetMainLoop();                    \
+        l->PostTask(FROM_HERE,                                                \
+                    NewRunnableFunction(&DestroyToBeCalledOnMainThread,       \
+                                        this));                               \
+      }                                                                       \
+    } else {                                                                  \
+      NS_LOG_RELEASE(this, count, #_class);                                   \
+    }                                                                         \
+    return count;                                                             \
+  }                                                                           \
+protected:                                                                    \
+  ::mozilla::ThreadSafeAutoRefCnt mRefCnt;                                    \
+private:                                                                      \
+  ::mozilla::layers::HelperForMainThreadDestruction mHelperForMainThreadDestruction; \
+public:
+
+#endif
\ No newline at end of file
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -22,16 +22,17 @@ EXPORTS += [
     'FrameMetrics.h',
     'GrallocImages.h',
     'ImageContainer.h',
     'ImageLayers.h',
     'ImageTypes.h',
     'ipc/CompositorChild.h',
     'ipc/CompositorParent.h',
     'ipc/ShadowLayersManager.h',
+    'ipc/ThreadSafeRefcountingWithMainThreadDestruction.h',
     'Layers.h',
     'LayerScope.h',
     'LayersLogging.h',
     'LayerSorter.h',
     'LayerTreeInvalidation.h',
     'opengl/Composer2D.h',
     'opengl/OGLShaderProgram.h',
     'opengl/TexturePoolOGL.h',