Bug 1526891 - Part 12: Merge ShutdownObserver with Observer; r=asuth
authorJan Varga <jan.varga@gmail.com>
Sat, 23 Feb 2019 17:28:10 +0100
changeset 520825 3aea75627220e61d802e4af99bd790ebc1a1d6a1
parent 520824 c8434f83fb5964672d4d2e221f11013a49055f0e
child 520826 992bfd5a7b28e5ef2709bb32eb7c464c8c580a1c
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 12: Merge ShutdownObserver with Observer; r=asuth Differential Revision: https://phabricator.services.mozilla.com/D20921
dom/quota/ActorsParent.cpp
dom/quota/QuotaManager.h
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -23,16 +23,17 @@
 #include "nsISupportsPrimitives.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
 #include "GeckoProfiler.h"
 #include "mozilla/Atomics.h"
+#include "mozilla/AutoRestore.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/PContent.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/QuotaClient.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/dom/localstorage/ActorsParent.h"
@@ -475,38 +476,30 @@ class QuotaManager::ShutdownRunnable fin
   }
 
  private:
   ~ShutdownRunnable() {}
 
   NS_DECL_NSIRUNNABLE
 };
 
-class QuotaManager::ShutdownObserver final : public nsIObserver {
-  nsCOMPtr<nsIEventTarget> mBackgroundThread;
+class QuotaManager::Observer final : public nsIObserver {
+  static Observer* sInstance;
+
+  nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
+  bool mPendingProfileChange;
 
  public:
-  explicit ShutdownObserver(nsIEventTarget* aBackgroundThread)
-      : mBackgroundThread(aBackgroundThread) {
-    MOZ_ASSERT(NS_IsMainThread());
-  }
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
+  static nsresult Initialize();
+
+  static nsresult SetBackgroundEventTarget(
+      nsIEventTarget* aBackgroundEventTarget);
 
  private:
-  ~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); }
-};
-
-class QuotaManager::Observer final : public nsIObserver {
- public:
-  static nsresult Initialize();
-
- private:
-  Observer() { MOZ_ASSERT(NS_IsMainThread()); }
+  Observer() : mPendingProfileChange(false) { MOZ_ASSERT(NS_IsMainThread()); }
 
   ~Observer() { MOZ_ASSERT(NS_IsMainThread()); }
 
   nsresult Init();
 
   nsresult Shutdown();
 
   NS_DECL_ISUPPORTS
@@ -2341,26 +2334,17 @@ nsresult QuotaManager::CreateRunnable::I
 
   return NS_OK;
 }
 
 nsresult QuotaManager::CreateRunnable::RegisterObserver() {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == State::RegisteringObserver);
 
-  nsCOMPtr<nsIObserverService> observerService =
-      mozilla::services::GetObserverService();
-  if (NS_WARN_IF(!observerService)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mOwningThread);
-
-  nsresult rv = observerService->AddObserver(
-      observer, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID, false);
+  nsresult rv = Observer::SetBackgroundEventTarget(mOwningThread);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // This service has to be started on the main thread currently.
   nsCOMPtr<mozIStorageService> ss =
       do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -2472,61 +2456,42 @@ QuotaManager::ShutdownRunnable::Run() {
     gInstance = nullptr;
   }
 
   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
 
   return NS_OK;
 }
 
-NS_IMPL_ISUPPORTS(QuotaManager::ShutdownObserver, nsIObserver)
-
-NS_IMETHODIMP
-QuotaManager::ShutdownObserver::Observe(nsISupports* aSubject,
-                                        const char* aTopic,
-                                        const char16_t* aData) {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!strcmp(aTopic, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID));
-  MOZ_ASSERT(gInstance);
-
-  nsCOMPtr<nsIObserverService> observerService =
-      mozilla::services::GetObserverService();
-  if (NS_WARN_IF(!observerService)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // Unregister ourselves from the observer service first to make sure the
-  // nested event loop below will not cause re-entrancy issues.
-  Unused << observerService->RemoveObserver(
-      this, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID);
-
-  bool done = false;
-
-  RefPtr<ShutdownRunnable> shutdownRunnable = new ShutdownRunnable(done);
-  MOZ_ALWAYS_SUCCEEDS(
-      mBackgroundThread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
-
-  MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; }));
-
-  gBaseDirPath.Truncate();
-
-  return NS_OK;
-}
+QuotaManager::Observer* QuotaManager::Observer::sInstance = nullptr;
 
 // static
 nsresult QuotaManager::Observer::Initialize() {
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<Observer> observer = new Observer();
 
   nsresult rv = observer->Init();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  sInstance = observer;
+
+  return NS_OK;
+}
+
+// static
+nsresult QuotaManager::Observer::SetBackgroundEventTarget(
+    nsIEventTarget* aBackgroundEventTarget) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(sInstance);
+
+  sInstance->mBackgroundEventTarget = aBackgroundEventTarget;
+
   return NS_OK;
 }
 
 nsresult QuotaManager::Observer::Init() {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (NS_WARN_IF(!obs)) {
@@ -2539,30 +2504,41 @@ nsresult QuotaManager::Observer::Init() 
   }
 
   rv = obs->AddObserver(this, kProfileDoChangeTopic, false);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
     return rv;
   }
 
+  rv = obs->AddObserver(this, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID, false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    obs->RemoveObserver(this, kProfileDoChangeTopic);
+    obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+    return rv;
+  }
+
   return NS_OK;
 }
 
 nsresult QuotaManager::Observer::Shutdown() {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (NS_WARN_IF(!obs)) {
     return NS_ERROR_FAILURE;
   }
 
+  MOZ_ALWAYS_SUCCEEDS(
+      obs->RemoveObserver(this, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID));
   MOZ_ALWAYS_SUCCEEDS(obs->RemoveObserver(this, kProfileDoChangeTopic));
   MOZ_ALWAYS_SUCCEEDS(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
 
+  sInstance = nullptr;
+
   // In general, the instance will have died after the latter removal call, so
   // it's not safe to do anything after that point.
   // However, Shutdown is currently called from Observe which is called by the
   // Observer Service which holds a strong reference to the observer while the
   // Observe method is being called.
 
   return NS_OK;
 }
@@ -2591,16 +2567,42 @@ QuotaManager::Observer::Observe(nsISuppo
     rv = baseDir->GetPath(gBaseDirPath);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     return NS_OK;
   }
 
+  if (!strcmp(aTopic, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID)) {
+    // mBackgroundThread can be null if we somehow get here without
+    // receiving SetBackgroundEventTarget() first.  mPendingProfileChange is our
+    // re-entrancy guard (the nested event loop below may cause re-entrancy).
+    if (!mBackgroundEventTarget || mPendingProfileChange) {
+      return NS_OK;
+    }
+
+    AutoRestore<bool> pending(mPendingProfileChange);
+    mPendingProfileChange = true;
+
+    MOZ_ASSERT(gInstance);
+
+    bool done = false;
+
+    RefPtr<ShutdownRunnable> shutdownRunnable = new ShutdownRunnable(done);
+    MOZ_ALWAYS_SUCCEEDS(
+        mBackgroundEventTarget->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
+
+    MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; }));
+
+    gBaseDirPath.Truncate();
+
+    return NS_OK;
+  }
+
   if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     rv = Shutdown();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     return NS_OK;
   }
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -95,17 +95,16 @@ class QuotaManager final : public Backgr
   typedef nsClassHashtable<nsCStringHashKey, nsTArray<DirectoryLockImpl*>>
       DirectoryLockTable;
 
  public:
   class CreateRunnable;
 
  private:
   class ShutdownRunnable;
-  class ShutdownObserver;
   class Observer;
 
  public:
   NS_INLINE_DECL_REFCOUNTING(QuotaManager)
 
   static nsresult Initialize();
 
   static bool IsRunningXPCShellTests() {