Bug 1020090 - Ensure we don't report leaking the GMP free list. r=jesup
authorChris Pearce <cpearce@mozilla.com>
Fri, 11 Jul 2014 15:35:28 +1200
changeset 215442 b1ba940ea14bde7c2a198c85c785eda39c0b4d85
parent 215441 c928106052fe2d0bb92ac678e8122a52f6a508a5
child 215443 54bd83c54daf91ea8df2799e9122c28c489cfeb3
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1020090
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 1020090 - Ensure we don't report leaking the GMP free list. r=jesup
content/media/gmp/GMPSharedMemManager.cpp
content/media/gmp/GMPSharedMemManager.h
--- a/content/media/gmp/GMPSharedMemManager.cpp
+++ b/content/media/gmp/GMPSharedMemManager.cpp
@@ -1,43 +1,74 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "GMPSharedMemManager.h"
 #include "GMPMessageUtils.h"
 #include "mozilla/ipc/SharedMemory.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/ClearOnShutdown.h"
 
 namespace mozilla {
 namespace gmp {
 
 // Really one set of pools on each side of the plugin API.
 
 // YUV buffers go from Encoder parent to child; pool there, and then return
 // with Decoded() frames to the Decoder parent and goes into the parent pool.
 // Compressed (encoded) data goes from the Decoder parent to the child;
 // pool there, and then return with Encoded() frames and goes into the parent
 // pool.
-static nsTArray<ipc::Shmem> sGmpFreelist[GMPSharedMemManager::kGMPNumTypes];
+static StaticAutoPtr<nsTArray<ipc::Shmem>> sGmpFreelist[GMPSharedMemManager::kGMPNumTypes];
+static uint32_t sGMPShmemManagerCount = 0;
+
+GMPSharedMemManager::GMPSharedMemManager()
+{
+  if (!sGMPShmemManagerCount) {
+    for (uint32_t i = 0; i < GMPSharedMemManager::kGMPNumTypes; i++) {
+      sGmpFreelist[i] = new nsTArray<ipc::Shmem>();
+    }
+  }
+  sGMPShmemManagerCount++;
+}
+
+GMPSharedMemManager::~GMPSharedMemManager()
+{
+  MOZ_ASSERT(sGMPShmemManagerCount > 0);
+  sGMPShmemManagerCount--;
+  if (!sGMPShmemManagerCount) {
+    for (uint32_t i = 0; i < GMPSharedMemManager::kGMPNumTypes; i++) {
+      sGmpFreelist[i] = nullptr;
+    }
+  }
+}
+
+static nsTArray<ipc::Shmem>&
+GetGmpFreelist(GMPSharedMemManager::GMPMemoryClasses aTypes)
+{
+  return *(sGmpFreelist[aTypes]);
+}
+
 static uint32_t sGmpAllocated[GMPSharedMemManager::kGMPNumTypes]; // 0's
 
 bool
 GMPSharedMemManager::MgrAllocShmem(GMPMemoryClasses aClass, size_t aSize,
                                    ipc::Shmem::SharedMemory::SharedMemoryType aType,
                                    ipc::Shmem* aMem)
 {
   CheckThread();
 
   // first look to see if we have a free buffer large enough
-  for (uint32_t i = 0; i < sGmpFreelist[aClass].Length(); i++) {
-    MOZ_ASSERT(sGmpFreelist[aClass][i].IsWritable());
-    if (aSize <= sGmpFreelist[aClass][i].Size<uint8_t>()) {
-      *aMem = sGmpFreelist[aClass][i];
-      sGmpFreelist[aClass].RemoveElementAt(i);
+  for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
+    MOZ_ASSERT(GetGmpFreelist(aClass)[i].IsWritable());
+    if (aSize <= GetGmpFreelist(aClass)[i].Size<uint8_t>()) {
+      *aMem = GetGmpFreelist(aClass)[i];
+      GetGmpFreelist(aClass).RemoveElementAt(i);
       return true;
     }
   }
 
   // Didn't find a buffer free with enough space; allocate one
   size_t pagesize = ipc::SharedMemory::SystemPageSize();
   aSize = (aSize + (pagesize-1)) & ~(pagesize-1); // round up to page size
   bool retval = Alloc(aSize, aType, aMem);
@@ -51,35 +82,35 @@ bool
 GMPSharedMemManager::MgrDeallocShmem(GMPMemoryClasses aClass, ipc::Shmem& aMem)
 {
   CheckThread();
 
   size_t size = aMem.Size<uint8_t>();
   size_t total = 0;
   // XXX This works; there are better pool algorithms.  We need to avoid
   // "falling off a cliff" with too low a number
-  if (sGmpFreelist[aClass].Length() > 10) {
-    Dealloc(sGmpFreelist[aClass][0]);
-    sGmpFreelist[aClass].RemoveElementAt(0);
+  if (GetGmpFreelist(aClass).Length() > 10) {
+    Dealloc(GetGmpFreelist(aClass)[0]);
+    GetGmpFreelist(aClass).RemoveElementAt(0);
     // The allocation numbers will be fubar on the Child!
     sGmpAllocated[aClass]--;
   }
-  for (uint32_t i = 0; i < sGmpFreelist[aClass].Length(); i++) {
-    MOZ_ASSERT(sGmpFreelist[aClass][i].IsWritable());
-    total += sGmpFreelist[aClass][i].Size<uint8_t>();
-    if (size < sGmpFreelist[aClass][i].Size<uint8_t>()) {
-      sGmpFreelist[aClass].InsertElementAt(i, aMem);
+  for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
+    MOZ_ASSERT(GetGmpFreelist(aClass)[i].IsWritable());
+    total += GetGmpFreelist(aClass)[i].Size<uint8_t>();
+    if (size < GetGmpFreelist(aClass)[i].Size<uint8_t>()) {
+      GetGmpFreelist(aClass).InsertElementAt(i, aMem);
       return true;
     }
   }
-  sGmpFreelist[aClass].AppendElement(aMem);
+  GetGmpFreelist(aClass).AppendElement(aMem);
 
   return true;
 }
 
 uint32_t
 GMPSharedMemManager::NumInUse(GMPMemoryClasses aClass)
 {
-  return sGmpAllocated[aClass] - sGmpFreelist[aClass].Length();
+  return sGmpAllocated[aClass] - GetGmpFreelist(aClass).Length();
 }
 
 }
 }
--- a/content/media/gmp/GMPSharedMemManager.h
+++ b/content/media/gmp/GMPSharedMemManager.h
@@ -23,21 +23,18 @@ public:
 
   // This is a heuristic - max of 10 free in the Child pool, plus those
   // in-use for the encoder and decoder at the given moment and not yet
   // returned to the parent pool (which is not included).  If more than
   // this are needed, we presume the client has either crashed or hung
   // (perhaps temporarily).
   static const uint32_t kGMPBufLimit = 20;
 
-  GMPSharedMemManager() {}
-
-  virtual ~GMPSharedMemManager() {
-    // XXX free everything in the freelist
-  }
+  GMPSharedMemManager();
+  virtual ~GMPSharedMemManager();
 
   virtual bool MgrAllocShmem(GMPMemoryClasses aClass, size_t aSize,
                              ipc::Shmem::SharedMemory::SharedMemoryType aType,
                              ipc::Shmem* aMem);
   virtual bool MgrDeallocShmem(GMPMemoryClasses aClass, ipc::Shmem& aMem);
 
   // So we can know if data is "piling up" for the plugin - I.e. it's hung or crashed
   virtual uint32_t NumInUse(GMPMemoryClasses aClass);