Bug 1037360 - Fix SharedBufferManagerParent's destruction. r=jrmuizel, r=bjacob, a=2.0+
authorSotaro Ikeda <sikeda@mozilla.com>
Wed, 16 Jul 2014 06:48:00 -0400
changeset 209181 69302cccb87799a11bb6fb84b64227d3a94b4c86
parent 209180 5c4008fe0967c4cde819f146b1c76138c6cc591e
child 209182 c82cd497bd9b0d2188e670eb3323b11b4966fbdf
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, bjacob, 2
bugs1037360
milestone32.0a2
Bug 1037360 - Fix SharedBufferManagerParent's destruction. r=jrmuizel, r=bjacob, a=2.0+
gfx/layers/ipc/SharedBufferManagerParent.cpp
gfx/layers/ipc/SharedBufferManagerParent.h
gfx/layers/opengl/GrallocTextureHost.cpp
--- a/gfx/layers/ipc/SharedBufferManagerParent.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerParent.cpp
@@ -68,23 +68,38 @@ void InitGralloc() {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   RegisterStrongMemoryReporter(new GrallocReporter());
 }
 
 map<base::ProcessId, SharedBufferManagerParent* > SharedBufferManagerParent::sManagers;
 StaticAutoPtr<Monitor> SharedBufferManagerParent::sManagerMonitor;
 uint64_t SharedBufferManagerParent::sBufferKey = 0;
 
+/**
+ * Task that deletes SharedBufferManagerParent on a specified thread.
+ */
+class DeleteSharedBufferManagerParentTask : public Task
+{
+public:
+    DeleteSharedBufferManagerParentTask(SharedBufferManagerParent* aSharedBufferManager)
+        : mSharedBufferManager(aSharedBufferManager) {
+    }
+    virtual void Run() MOZ_OVERRIDE {}
+private:
+    nsAutoPtr<SharedBufferManagerParent> mSharedBufferManager;
+};
+
 SharedBufferManagerParent::SharedBufferManagerParent(Transport* aTransport, base::ProcessId aOwner, base::Thread* aThread)
   : mTransport(aTransport)
   , mThread(aThread)
-#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
-  , mBuffersMutex("BuffersMonitor")
-#endif
+  , mMainMessageLoop(MessageLoop::current())
+  , mDestroyed(false)
+  , mLock("SharedBufferManagerParent.mLock")
 {
+  MOZ_ASSERT(NS_IsMainThread());
   if (!sManagerMonitor) {
     sManagerMonitor = new Monitor("Manager Monitor");
   }
 
   MonitorAutoLock lock(*sManagerMonitor.get());
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread");
   if (!aThread->IsRunning()) {
     aThread->Start();
@@ -106,20 +121,23 @@ SharedBufferManagerParent::~SharedBuffer
   }
   sManagers.erase(mOwner);
   delete mThread;
 }
 
 void
 SharedBufferManagerParent::ActorDestroy(ActorDestroyReason aWhy)
 {
+  MutexAutoLock lock(mLock);
+  mDestroyed = true;
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
-  MutexAutoLock lock(mBuffersMutex);
   mBuffers.clear();
 #endif
+  DeleteSharedBufferManagerParentTask* task = new DeleteSharedBufferManagerParentTask(this);
+  mMainMessageLoop->PostTask(FROM_HERE, task);
 }
 
 static void
 ConnectSharedBufferManagerInParentProcess(SharedBufferManagerParent* aManager,
                                           Transport* aTransport,
                                           base::ProcessHandle aOtherProcess)
 {
   aManager->Open(aTransport, aOtherProcess, XRE_GetIOMessageLoop(), ipc::ParentSide);
@@ -185,31 +203,31 @@ bool SharedBufferManagerParent::RecvAllo
   int bpp = 0;
   bpp = android::bytesPerPixel(outgoingBuffer->getPixelFormat());
   if (bpp > 0)
     GrallocReporter::sAmount += outgoingBuffer->getStride() * outgoingBuffer->getHeight() * bpp;
   else // Specical case for BSP specific formats(mainly YUV formats, count it as normal YUV buffer)
     GrallocReporter::sAmount += outgoingBuffer->getStride() * outgoingBuffer->getHeight() * 3 / 2;
 
   {
-    MutexAutoLock lock(mBuffersMutex);
+    MutexAutoLock lock(mLock);
     mBuffers[bufferKey] = outgoingBuffer;
   }
 #endif
   return true;
 }
 
 bool SharedBufferManagerParent::RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle)
 {
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   NS_ASSERTION(handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef, "We shouldn't interact with the real buffer!");
   int64_t bufferKey = handle.get_GrallocBufferRef().mKey;
   sp<GraphicBuffer> buf = GetGraphicBuffer(bufferKey);
   MOZ_ASSERT(buf.get());
-  MutexAutoLock lock(mBuffersMutex);
+  MutexAutoLock lock(mLock);
   NS_ASSERTION(mBuffers.count(bufferKey) == 1, "How can you drop others buffer");
   mBuffers.erase(bufferKey);
 
   if(!buf.get()) {
     printf_stderr("SharedBufferManagerParent::RecvDropGrallocBuffer -- invalid buffer key.");
     return true;
   }
 
@@ -219,40 +237,56 @@ bool SharedBufferManagerParent::RecvDrop
     GrallocReporter::sAmount -= buf->getStride() * buf->getHeight() * bpp;
   else // Specical case for BSP specific formats(mainly YUV formats, count it as normal YUV buffer)
     GrallocReporter::sAmount -= buf->getStride() * buf->getHeight() * 3 / 2;
 
 #endif
   return true;
 }
 
+/*static*/
 void SharedBufferManagerParent::DropGrallocBufferSync(SharedBufferManagerParent* mgr, mozilla::layers::SurfaceDescriptor aDesc)
 {
   mgr->DropGrallocBufferImpl(aDesc);
 }
 
-void SharedBufferManagerParent::DropGrallocBuffer(mozilla::layers::SurfaceDescriptor aDesc)
+/*static*/
+void SharedBufferManagerParent::DropGrallocBuffer(ProcessId id, mozilla::layers::SurfaceDescriptor aDesc)
 {
   if (aDesc.type() != SurfaceDescriptor::TNewSurfaceDescriptorGralloc) {
     return;
   }
 
-  if (PlatformThread::CurrentId() == mThread->thread_id()) {
-    DropGrallocBufferImpl(aDesc);
+  MonitorAutoLock lock(*sManagerMonitor.get());
+  SharedBufferManagerParent* mgr = SharedBufferManagerParent::GetInstance(id);
+  if (!mgr) {
+    return;
+  }
+
+  MutexAutoLock mgrlock(mgr->mLock);
+  if (mgr->mDestroyed) {
+    return;
+  }
+
+  if (PlatformThread::CurrentId() == mgr->mThread->thread_id()) {
+    MOZ_CRASH("SharedBufferManagerParent::DropGrallocBuffer should not be called on SharedBufferManagerParent thread");
   } else {
-    mThread->message_loop()->PostTask(FROM_HERE,
-                                      NewRunnableFunction(&DropGrallocBufferSync, this, aDesc));
+    mgr->mThread->message_loop()->PostTask(FROM_HERE,
+                                      NewRunnableFunction(&DropGrallocBufferSync, mgr, aDesc));
   }
   return;
 }
 
 void SharedBufferManagerParent::DropGrallocBufferImpl(mozilla::layers::SurfaceDescriptor aDesc)
 {
+  MutexAutoLock lock(mLock);
+  if (mDestroyed) {
+    return;
+  }
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
-  MutexAutoLock lock(mBuffersMutex);
   int64_t key = -1;
   MaybeMagicGrallocBufferHandle handle;
   if (aDesc.type() == SurfaceDescriptor::TNewSurfaceDescriptorGralloc) {
     handle = aDesc.get_NewSurfaceDescriptorGralloc().buffer();
   } else {
     return;
   }
 
@@ -271,38 +305,38 @@ void SharedBufferManagerParent::DropGral
 
 MessageLoop* SharedBufferManagerParent::GetMessageLoop()
 {
   return mThread->message_loop();
 }
 
 SharedBufferManagerParent* SharedBufferManagerParent::GetInstance(ProcessId id)
 {
-  MonitorAutoLock lock(*sManagerMonitor.get());
   NS_ASSERTION(sManagers.count(id) == 1, "No BufferManager for the process");
   return sManagers[id];
 }
 
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
 android::sp<android::GraphicBuffer>
 SharedBufferManagerParent::GetGraphicBuffer(int64_t key)
 {
-  MutexAutoLock lock(mBuffersMutex);
+  MutexAutoLock lock(mLock);
   if (mBuffers.count(key) == 1) {
     return mBuffers[key];
   } else {
     // The buffer can be dropped, or invalid
     printf_stderr("SharedBufferManagerParent::GetGraphicBuffer -- invalid key");
     return nullptr;
   }
 }
 
 android::sp<android::GraphicBuffer>
 SharedBufferManagerParent::GetGraphicBuffer(GrallocBufferRef aRef)
 {
+  MonitorAutoLock lock(*sManagerMonitor.get());
   return GetInstance(aRef.mOwner)->GetGraphicBuffer(aRef.mKey);
 }
 #endif
 
 IToplevelProtocol*
 SharedBufferManagerParent::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
                                  base::ProcessHandle aPeerProcess,
                                  mozilla::ipc::ProtocolCloneContext* aCtx)
--- a/gfx/layers/ipc/SharedBufferManagerParent.h
+++ b/gfx/layers/ipc/SharedBufferManagerParent.h
@@ -33,21 +33,16 @@ namespace layers {
 class SharedBufferManagerParent : public PSharedBufferManagerParent
 {
 public:
   /**
    * Create a SharedBufferManagerParent for child process, and link to the child side before leaving
    */
   static PSharedBufferManagerParent* Create(Transport* aTransport, ProcessId aOtherProcess);
 
-  /**
-   * Function for find the buffer owner, most buffer passing on IPC contains only owner/key pair.
-   * Use these function to access the real buffer.
-   */
-  static SharedBufferManagerParent* GetInstance(ProcessId id);
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t key);
   static android::sp<android::GraphicBuffer> GetGraphicBuffer(GrallocBufferRef aRef);
 #endif
   /**
    * Create a SharedBufferManagerParent but do not open the link
    */
   SharedBufferManagerParent(Transport* aTransport, ProcessId aOwner, base::Thread* aThread);
@@ -59,52 +54,62 @@ public:
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool RecvAllocateGrallocBuffer(const IntSize&, const uint32_t&, const uint32_t&, mozilla::layers::MaybeMagicGrallocBufferHandle*);
   virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
 
   /**
    * Break the buffer's sharing state, decrease buffer reference for both side
    */
-  void DropGrallocBuffer(mozilla::layers::SurfaceDescriptor aDesc);
+  static void DropGrallocBuffer(ProcessId id, mozilla::layers::SurfaceDescriptor aDesc);
 
   // Overriden from IToplevelProtocol
   IToplevelProtocol*
   CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
                 base::ProcessHandle aPeerProcess,
                 mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
   MessageLoop* GetMessageLoop();
 
 protected:
-  /**
-   * All living SharedBufferManager instances used to find the buffer owner, and parent->child IPCs
-   */
-  static std::map<base::ProcessId, SharedBufferManagerParent*> sManagers;
 
   /**
    * Break the buffer's sharing state, decrease buffer reference for both side
    *
    * Must be called from SharedBufferManagerParent's thread
    */
   void DropGrallocBufferImpl(mozilla::layers::SurfaceDescriptor aDesc);
 
   // dispatched function
   static void DropGrallocBufferSync(SharedBufferManagerParent* mgr, mozilla::layers::SurfaceDescriptor aDesc);
 
+  /**
+   * Function for find the buffer owner, most buffer passing on IPC contains only owner/key pair.
+   * Use these function to access the real buffer.
+   * Caller needs to hold sManagerMonitor.
+   */
+  static SharedBufferManagerParent* GetInstance(ProcessId id);
+
+  /**
+   * All living SharedBufferManager instances used to find the buffer owner, and parent->child IPCs
+   */
+  static std::map<base::ProcessId, SharedBufferManagerParent*> sManagers;
+
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   /**
    * Buffers owned by this SharedBufferManager pair
    */
   std::map<int64_t, android::sp<android::GraphicBuffer> > mBuffers;
-  Mutex mBuffersMutex;
 #endif
   
   Transport* mTransport;
   base::ProcessId mOwner;
   base::Thread* mThread;
+  MessageLoop* mMainMessageLoop;
+  bool mDestroyed;
+  Mutex mLock;
+
   static uint64_t sBufferKey;
-
   static StaticAutoPtr<Monitor> sManagerMonitor;
 };
 
 } /* namespace layers */
 } /* namespace mozilla */
 #endif /* SharedBufferManagerPARENT_H_ */
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -373,17 +373,17 @@ GrallocTextureHostOGL::DeallocateSharedD
     base::ProcessId owner;
     if (handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef) {
       owner = handle.get_GrallocBufferRef().mOwner;
     }
     else {
       owner = handle.get_MagicGrallocBufferHandle().mRef.mOwner;
     }
 
-    SharedBufferManagerParent::GetInstance(owner)->DropGrallocBuffer(mGrallocHandle);
+    SharedBufferManagerParent::DropGrallocBuffer(owner, mGrallocHandle);
   }
 }
 
 void
 GrallocTextureHostOGL::ForgetSharedData()
 {
   if (mTextureSource) {
     mTextureSource->ForgetBuffer();