Bug 1287747 - Fix up GetFilesHelper and GetFilesHelperParent to release on the main-thread only. r=smaug, a=ritu
authorAndrea Marchesini <amarchesini@mozilla.com>
Sat, 17 Sep 2016 09:55:30 +0200
changeset 350394 b45d33f4b3be28f0883ab602b512090908256930
parent 350393 8252fe02a82702c9b0dd3abf02bb5b45f20cb67d
child 350395 c3e2971240ea4904fdbd9423b38f4a79cf7d1923
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, ritu
bugs1287747
milestone50.0
Bug 1287747 - Fix up GetFilesHelper and GetFilesHelperParent to release on the main-thread only. r=smaug, a=ritu
dom/filesystem/GetFilesHelper.cpp
dom/filesystem/GetFilesHelper.h
--- a/dom/filesystem/GetFilesHelper.cpp
+++ b/dom/filesystem/GetFilesHelper.cpp
@@ -2,20 +2,76 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "GetFilesHelper.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
+#include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 
+namespace {
+
+// This class is used in the DTOR of GetFilesHelper to release resources in the
+// correct thread.
+class ReleaseRunnable final : public Runnable
+{
+public:
+  static void
+  MaybeReleaseOnMainThread(nsTArray<RefPtr<Promise>>& aPromises,
+                           nsTArray<RefPtr<GetFilesCallback>>& aCallbacks,
+                           Sequence<RefPtr<File>>& aFiles,
+                           already_AddRefed<nsIGlobalObject> aGlobal)
+  {
+    if (NS_IsMainThread()) {
+      return;
+    }
+
+    RefPtr<ReleaseRunnable> runnable =
+      new ReleaseRunnable(aPromises, aCallbacks, aFiles, Move(aGlobal));
+    NS_DispatchToMainThread(runnable);
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    mPromises.Clear();
+    mCallbacks.Clear();
+    mFiles.Clear();
+    mGlobal = nullptr;
+
+    return NS_OK;
+  }
+
+private:
+  ReleaseRunnable(nsTArray<RefPtr<Promise>>& aPromises,
+                  nsTArray<RefPtr<GetFilesCallback>>& aCallbacks,
+                  Sequence<RefPtr<File>>& aFiles,
+                  already_AddRefed<nsIGlobalObject> aGlobal)
+  {
+    mPromises.SwapElements(aPromises);
+    mCallbacks.SwapElements(aCallbacks);
+    mFiles.SwapElements(aFiles);
+    mGlobal = aGlobal;
+  }
+
+  nsTArray<RefPtr<Promise>> mPromises;
+  nsTArray<RefPtr<GetFilesCallback>> mCallbacks;
+  Sequence<RefPtr<File>> mFiles;
+  nsCOMPtr<nsIGlobalObject> mGlobal;
+};
+
+} // anonymous
+
 ///////////////////////////////////////////////////////////////////////////////
 // GetFilesHelper Base class
 
 already_AddRefed<GetFilesHelper>
 GetFilesHelper::Create(nsIGlobalObject* aGlobal,
                        const nsTArray<OwningFileOrDirectory>& aFilesOrDirectory,
                        bool aRecursiveFlag, ErrorResult& aRv)
 {
@@ -76,16 +132,22 @@ GetFilesHelper::GetFilesHelper(nsIGlobal
   , mGlobal(aGlobal)
   , mListingCompleted(false)
   , mErrorResult(NS_OK)
   , mMutex("GetFilesHelper::mMutex")
   , mCanceled(false)
 {
 }
 
+GetFilesHelper::~GetFilesHelper()
+{
+  ReleaseRunnable::MaybeReleaseOnMainThread(mPromises, mCallbacks, mFiles,
+                                            mGlobal.forget());
+}
+
 void
 GetFilesHelper::AddPromise(Promise* aPromise)
 {
   MOZ_ASSERT(aPromise);
 
   // Still working.
   if (!mListingCompleted) {
     mPromises.AppendElement(aPromise);
@@ -552,16 +614,21 @@ private:
 GetFilesHelperParent::GetFilesHelperParent(const nsID& aUUID,
                                            ContentParent* aContentParent,
                                            bool aRecursiveFlag)
   : GetFilesHelper(nullptr, aRecursiveFlag)
   , mContentParent(aContentParent)
   , mUUID(aUUID)
 {}
 
+GetFilesHelperParent::~GetFilesHelperParent()
+{
+  NS_ReleaseOnMainThread(mContentParent.forget());
+}
+
 /* static */ already_AddRefed<GetFilesHelperParent>
 GetFilesHelperParent::Create(const nsID& aUUID, const nsAString& aDirectoryPath,
                              bool aRecursiveFlag, ContentParent* aContentParent,
                              ErrorResult& aRv)
 {
   MOZ_ASSERT(aContentParent);
 
   RefPtr<GetFilesHelperParent> helper =
--- a/dom/filesystem/GetFilesHelper.h
+++ b/dom/filesystem/GetFilesHelper.h
@@ -94,17 +94,17 @@ public:
 
   // CC methods
   void Unlink();
   void Traverse(nsCycleCollectionTraversalCallback &cb);
 
 protected:
   GetFilesHelper(nsIGlobalObject* aGlobal, bool aRecursiveFlag);
 
-  virtual ~GetFilesHelper() {}
+  virtual ~GetFilesHelper();
 
   void
   SetDirectoryPath(const nsAString& aDirectoryPath)
   {
     mDirectoryPath = aDirectoryPath;
   }
 
   virtual bool
@@ -193,16 +193,18 @@ public:
   static already_AddRefed<GetFilesHelperParent>
   Create(const nsID& aUUID, const nsAString& aDirectoryPath,
          bool aRecursiveFlag, ContentParent* aContentParent, ErrorResult& aRv);
 
 private:
   GetFilesHelperParent(const nsID& aUUID, ContentParent* aContentParent,
                        bool aRecursiveFlag);
 
+  ~GetFilesHelperParent();
+
   RefPtr<ContentParent> mContentParent;
   nsID mUUID;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_GetFilesHelper_h