Bug 774388 - Patch 9: Introduce NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION - r=mattwoodrow
☠☠ backed out by 1fd5a864e81d ☠ ☠
authorBenoit Jacob <bjacob@mozilla.com>
Thu, 03 Jul 2014 14:53:31 -0400
changeset 213049 9f14b17f358c21712f442a4fb4f3a595b9c12884
parent 213048 2d347d6aa9bcc6cf6c796c3dacdb98b4e7c4027e
child 213050 d075217290772151a579d3edb1ce0d0c912c6fc6
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',