Bug 1526891 - Part 10: Fix a content process leak by closing databases at xpcom-shutdown; r=asuth
authorJan Varga <jan.varga@gmail.com>
Sat, 23 Feb 2019 17:19:35 +0100
changeset 520823 1afb51b4bf31dfe076221a9c45d4eeeffa7c5dfa
parent 520822 5d0241e1bc0a0a9ac9693e9406633161d6f8b6aa
child 520824 c8434f83fb5964672d4d2e221f11013a49055f0e
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1526891
milestone67.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 1526891 - Part 10: Fix a content process leak by closing databases at xpcom-shutdown; r=asuth Differential Revision: https://phabricator.services.mozilla.com/D20919
dom/localstorage/LSDatabase.cpp
dom/localstorage/LSDatabase.h
--- a/dom/localstorage/LSDatabase.cpp
+++ b/dom/localstorage/LSDatabase.cpp
@@ -4,34 +4,61 @@
  * 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 "LSDatabase.h"
 
 namespace mozilla {
 namespace dom {
 
+using namespace mozilla::services;
+
 namespace {
 
+#define XPCOM_SHUTDOWN_OBSERVER_TOPIC "xpcom-shutdown"
+
 typedef nsDataHashtable<nsCStringHashKey, LSDatabase*> LSDatabaseHashtable;
 
 StaticAutoPtr<LSDatabaseHashtable> gLSDatabases;
 
 }  // namespace
 
+StaticRefPtr<LSDatabase::Observer> LSDatabase::sObserver;
+
+class LSDatabase::Observer final : public nsIObserver {
+ public:
+  Observer() { MOZ_ASSERT(NS_IsMainThread()); }
+
+ private:
+  ~Observer() { MOZ_ASSERT(NS_IsMainThread()); }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+};
+
 LSDatabase::LSDatabase(const nsACString& aOrigin)
     : mActor(nullptr),
       mSnapshot(nullptr),
       mOrigin(aOrigin),
       mAllowedToClose(false),
       mRequestedAllowToClose(false) {
   AssertIsOnOwningThread();
 
   if (!gLSDatabases) {
     gLSDatabases = new LSDatabaseHashtable();
+
+    MOZ_ASSERT(!sObserver);
+
+    sObserver = new Observer();
+
+    nsCOMPtr<nsIObserverService> obsSvc = GetObserverService();
+    MOZ_ASSERT(obsSvc);
+
+    MOZ_ALWAYS_SUCCEEDS(
+        obsSvc->AddObserver(sObserver, XPCOM_SHUTDOWN_OBSERVER_TOPIC, false));
   }
 
   MOZ_ASSERT(!gLSDatabases->Get(mOrigin));
   gLSDatabases->Put(mOrigin, this);
 }
 
 LSDatabase::~LSDatabase() {
   AssertIsOnOwningThread();
@@ -57,17 +84,20 @@ void LSDatabase::SetActor(LSDatabaseChil
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(!mActor);
 
   mActor = aActor;
 }
 
 void LSDatabase::RequestAllowToClose() {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(!mRequestedAllowToClose);
+
+  if (mRequestedAllowToClose) {
+    return;
+  }
 
   mRequestedAllowToClose = true;
 
   if (mSnapshot) {
     mSnapshot->MarkDirty();
   } else {
     AllowToClose();
   }
@@ -310,13 +340,48 @@ void LSDatabase::AllowToClose() {
   }
 
   MOZ_ASSERT(gLSDatabases);
   MOZ_ASSERT(gLSDatabases->Get(mOrigin));
   gLSDatabases->Remove(mOrigin);
 
   if (!gLSDatabases->Count()) {
     gLSDatabases = nullptr;
+
+    MOZ_ASSERT(sObserver);
+
+    nsCOMPtr<nsIObserverService> obsSvc = GetObserverService();
+    MOZ_ASSERT(obsSvc);
+
+    MOZ_ALWAYS_SUCCEEDS(
+        obsSvc->RemoveObserver(sObserver, XPCOM_SHUTDOWN_OBSERVER_TOPIC));
+
+    sObserver = nullptr;
   }
 }
 
+NS_IMPL_ISUPPORTS(LSDatabase::Observer, nsIObserver)
+
+NS_IMETHODIMP
+LSDatabase::Observer::Observe(nsISupports* aSubject, const char* aTopic,
+                              const char16_t* aData) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!strcmp(aTopic, XPCOM_SHUTDOWN_OBSERVER_TOPIC));
+  MOZ_ASSERT(gLSDatabases);
+
+  nsTArray<RefPtr<LSDatabase>> databases;
+
+  for (auto iter = gLSDatabases->ConstIter(); !iter.Done(); iter.Next()) {
+    LSDatabase* database = iter.Data();
+    MOZ_ASSERT(database);
+
+    databases.AppendElement(database);
+  }
+
+  for (RefPtr<LSDatabase>& database : databases) {
+    database->RequestAllowToClose();
+  }
+
+  return NS_OK;
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/localstorage/LSDatabase.h
+++ b/dom/localstorage/LSDatabase.h
@@ -9,25 +9,29 @@
 
 namespace mozilla {
 namespace dom {
 
 class LSDatabaseChild;
 class LSSnapshot;
 
 class LSDatabase final {
+  class Observer;
+
   LSDatabaseChild* mActor;
 
   LSSnapshot* mSnapshot;
 
   const nsCString mOrigin;
 
   bool mAllowedToClose;
   bool mRequestedAllowToClose;
 
+  static StaticRefPtr<Observer> sObserver;
+
  public:
   explicit LSDatabase(const nsACString& aOrigin);
 
   static LSDatabase* Get(const nsACString& aOrigin);
 
   NS_INLINE_DECL_REFCOUNTING(LSDatabase)
 
   void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(LSDatabase); }