Bug 774388 - Patch 12: make ImageBridgeParent 's refcounting implementation automatically defer destruction to the main thread - r=nical
authorBenoit Jacob <bjacob@mozilla.com>
Fri, 04 Jul 2014 14:04:12 -0400
changeset 192527 a27e869f58447fa5c40bf01b801483ee4855a7fd
parent 192526 04ed499f96ecae4201a29628bc37ed456d221395
child 192528 fdfcb86cc3c897a751c260c2778a65a7fbd1ca9f
push id27088
push usercbook@mozilla.com
push dateMon, 07 Jul 2014 12:19:04 +0000
treeherdermozilla-central@699348fd356b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
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 12: make ImageBridgeParent 's refcounting implementation automatically defer destruction to the main thread - r=nical
gfx/layers/AtomicRefCountedWithFinalize.h
gfx/layers/ipc/ImageBridgeParent.cpp
--- a/gfx/layers/AtomicRefCountedWithFinalize.h
+++ b/gfx/layers/AtomicRefCountedWithFinalize.h
@@ -3,30 +3,45 @@
  * 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 MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
 #define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/NullPtr.h"
+#include "mozilla/Likely.h"
+#include "MainThreadUtils.h"
+#include "base/message_loop.h"
+#include "base/task.h"
 
 namespace mozilla {
 
 template<typename T>
 class AtomicRefCountedWithFinalize
 {
   protected:
     AtomicRefCountedWithFinalize()
       : mRecycleCallback(nullptr)
       , mRefCount(0)
+      , mMessageLoopToPostDestructionTo(nullptr)
     {}
 
     ~AtomicRefCountedWithFinalize() {}
 
+    void SetMessageLoopToPostDestructionTo(MessageLoop* l) {
+      MOZ_ASSERT(NS_IsMainThread());
+      mMessageLoopToPostDestructionTo = l;
+    }
+
+    static void DestroyToBeCalledOnMainThread(T* ptr) {
+      MOZ_ASSERT(NS_IsMainThread());
+      delete ptr;
+    }
+
   public:
     void AddRef() {
       MOZ_ASSERT(mRefCount >= 0);
       ++mRefCount;
     }
 
     void Release() {
       MOZ_ASSERT(mRefCount > 0);
@@ -38,17 +53,27 @@ class AtomicRefCountedWithFinalize
         // Recycle listeners must call ClearRecycleCallback
         // before releasing their strong reference.
         MOZ_ASSERT(mRecycleCallback == nullptr);
 #ifdef DEBUG
         mRefCount = detail::DEAD;
 #endif
         T* derived = static_cast<T*>(this);
         derived->Finalize();
-        delete derived;
+        if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) {
+          delete derived;
+        } else {
+          if (MOZ_LIKELY(NS_IsMainThread())) {
+            delete derived;
+          } else {
+            mMessageLoopToPostDestructionTo->PostTask(
+              FROM_HERE,
+              NewRunnableFunction(&DestroyToBeCalledOnMainThread, derived));
+          }
+        }
       } else if (1 == currCount && recycleCallback) {
         T* derived = static_cast<T*>(this);
         recycleCallback(derived, mClosure);
       }
     }
 
     typedef void (*RecycleCallback)(T* aObject, void* aClosure);
     /**
@@ -66,13 +91,14 @@ class AtomicRefCountedWithFinalize
     {
       return !!mRecycleCallback;
     }
 
 private:
     RecycleCallback mRecycleCallback;
     void *mClosure;
     Atomic<int> mRefCount;
+    MessageLoop *mMessageLoopToPostDestructionTo;
 };
 
 }
 
 #endif
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -49,22 +49,25 @@ MessageLoop* ImageBridgeParent::sMainLoo
 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
                                      Transport* aTransport,
                                      ProcessId aChildProcessId)
   : mMessageLoop(aLoop)
   , mTransport(aTransport)
   , mChildProcessId(aChildProcessId)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  sMainLoop = MessageLoop::current();
+
+  // top-level actors must be destroyed on the main thread.
+  SetMessageLoopToPostDestructionTo(sMainLoop);
 
   // creates the map only if it has not been created already, so it is safe
   // with several bridges
   CompositableMap::Create();
   sImageBridges[aChildProcessId] = this;
-  sMainLoop = MessageLoop::current();
 }
 
 ImageBridgeParent::~ImageBridgeParent()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mTransport) {
     MOZ_ASSERT(XRE_GetIOMessageLoop());
@@ -269,31 +272,20 @@ ImageBridgeParent::RecvChildAsyncMessage
   }
   return true;
 }
 
 MessageLoop * ImageBridgeParent::GetMessageLoop() const {
   return mMessageLoop;
 }
 
-static void
-DeferredReleaseImageBridgeParentOnMainThread(ImageBridgeParent* aDyingImageBridgeParent)
-{
-  aDyingImageBridgeParent->Release();
-}
-
 void
 ImageBridgeParent::DeferredDestroy()
 {
-  ImageBridgeParent* self;
-  mSelfRef.forget(&self);
-
-  sMainLoop->PostTask(
-    FROM_HERE,
-    NewRunnableFunction(&DeferredReleaseImageBridgeParentOnMainThread, this));
+  mSelfRef = nullptr;
 }
 
 ImageBridgeParent*
 ImageBridgeParent::GetInstance(ProcessId aId)
 {
   NS_ASSERTION(sImageBridges.count(aId) == 1, "ImageBridgeParent for the process");
   return sImageBridges[aId];
 }