Bug 1349862 - MutableBlobStorage must use a TaskQueue in order to preserve the order of runnables for I/O ops. r=asuth, a=lizzard
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 28 Mar 2017 11:05:58 +0200
changeset 379420 6c25e0308c34aa94624450f21e27d5e97d1b7a63
parent 379419 d3788f9d140b06c6c99658bbb9a1b2ced46c79e4
child 379421 4f97cc13beb2334f14e6cf4f73eaab5e45f07491
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, lizzard
bugs1349862
milestone53.0
Bug 1349862 - MutableBlobStorage must use a TaskQueue in order to preserve the order of runnables for I/O ops. r=asuth, a=lizzard
dom/file/MutableBlobStorage.cpp
dom/file/MutableBlobStorage.h
--- a/dom/file/MutableBlobStorage.cpp
+++ b/dom/file/MutableBlobStorage.cpp
@@ -2,16 +2,17 @@
 /* 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 "mozilla/dom/MutableBlobStorage.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/File.h"
+#include "mozilla/TaskQueue.h"
 #include "nsAnonymousTemporaryFile.h"
 #include "nsNetCID.h"
 #include "nsProxyRelease.h"
 #include "WorkerPrivate.h"
 
 #define BLOB_MEMORY_TEMPORARY_FILE 1048576
 
 namespace mozilla {
@@ -358,17 +359,22 @@ MutableBlobStorage::MutableBlobStorage(M
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 MutableBlobStorage::~MutableBlobStorage()
 {
   free(mData);
 
   if (mFD) {
-    DispatchToIOThread(new CloseFileRunnable(mFD));
+    RefPtr<Runnable> runnable = new CloseFileRunnable(mFD);
+    DispatchToIOThread(runnable.forget());
+  }
+
+  if (mTaskQueue) {
+    mTaskQueue->BeginShutdown();
   }
 }
 
 uint64_t
 MutableBlobStorage::GetBlobWhenReady(nsISupports* aParent,
                                      const nsACString& aContentType,
                                      MutableBlobStorageCallback* aCallback)
 {
@@ -379,32 +385,28 @@ MutableBlobStorage::GetBlobWhenReady(nsI
   MOZ_ASSERT(mStorageState != eClosed);
   StorageState previousState = mStorageState;
   mStorageState = eClosed;
 
   if (previousState == eInTemporaryFile) {
     MOZ_ASSERT(mFD);
 
     if (NS_FAILED(mErrorResult)) {
-      NS_DispatchToMainThread(
-        new BlobCreationDoneRunnable(this, aCallback, nullptr, mErrorResult));
+      RefPtr<Runnable> runnable =
+        new BlobCreationDoneRunnable(this, aCallback, nullptr, mErrorResult);
+      NS_DispatchToMainThread(runnable.forget());
       return 0;
     }
 
     // We want to wait until all the WriteRunnable are completed. The way we do
     // this is to go to the I/O thread and then we come back: the runnables are
     // executed in order and this LastRunnable will be... the last one.
-    nsresult rv = DispatchToIOThread(new LastRunnable(this, aParent,
-                                                      aContentType, aCallback));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      NS_DispatchToMainThread(
-        new BlobCreationDoneRunnable(this, aCallback, nullptr, rv));
-      return 0;
-    }
-
+    RefPtr<Runnable> runnable =
+      new LastRunnable(this, aParent, aContentType, aCallback);
+    DispatchToIOThread(runnable.forget());
     return mDataLen;
   }
 
   RefPtr<BlobImpl> blobImpl;
 
   if (mData) {
     blobImpl = new BlobImplMemory(mData, mDataLen,
                                   NS_ConvertUTF8toUTF16(aContentType));
@@ -454,20 +456,17 @@ MutableBlobStorage::Append(const void* a
     MOZ_ASSERT(mFD);
 
     RefPtr<WriteRunnable> runnable =
       WriteRunnable::CopyBuffer(this, mFD, aData, aLength);
     if (NS_WARN_IF(!runnable)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    nsresult rv = DispatchToIOThread(runnable);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+    DispatchToIOThread(runnable.forget());
 
     mDataLen += aLength;
     return NS_OK;
   }
 
   // By default, we store in memory.
 
   uint64_t offset = mDataLen;
@@ -527,51 +526,46 @@ MutableBlobStorage::ShouldBeTemporarySto
 
   return bufferSize.value() >= Preferences::GetUint("dom.blob.memoryToTemporaryFile",
                                                     BLOB_MEMORY_TEMPORARY_FILE);
 }
 
 nsresult
 MutableBlobStorage::MaybeCreateTemporaryFile()
 {
-  nsresult rv = DispatchToIOThread(new CreateTemporaryFileRunnable(this));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
+  RefPtr<Runnable> runnable = new CreateTemporaryFileRunnable(this);
+  DispatchToIOThread(runnable.forget());
 
   mStorageState = eWaitingForTemporaryFile;
   return NS_OK;
 }
 
 void
 MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mStorageState == eWaitingForTemporaryFile ||
              mStorageState == eClosed);
 
   if (mStorageState == eClosed) {
-    DispatchToIOThread(new CloseFileRunnable(aFD));
+    RefPtr<Runnable> runnable = new CloseFileRunnable(aFD);
+    DispatchToIOThread(runnable.forget());
     return;
   }
 
   mStorageState = eInTemporaryFile;
   mFD = aFD;
 
   RefPtr<WriteRunnable> runnable =
     WriteRunnable::AdoptBuffer(this, mFD, mData, mDataLen);
   MOZ_ASSERT(runnable);
 
   mData = nullptr;
 
-  nsresult rv = DispatchToIOThread(runnable);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    mErrorResult = rv;
-    return;
-  }
+  DispatchToIOThread(runnable.forget());
 }
 
 void
 MutableBlobStorage::CreateBlobAndRespond(already_AddRefed<nsISupports> aParent,
                                          const nsACString& aContentType,
                                          already_AddRefed<MutableBlobStorageCallback> aCallback)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -592,25 +586,25 @@ MutableBlobStorage::CreateBlobAndRespond
 
 void
 MutableBlobStorage::ErrorPropagated(nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mErrorResult = aRv;
 }
 
-/* static */ nsresult
-MutableBlobStorage::DispatchToIOThread(Runnable* aRunnable)
+void
+MutableBlobStorage::DispatchToIOThread(already_AddRefed<nsIRunnable> aRunnable)
 {
-  nsCOMPtr<nsIEventTarget> target
-    = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
-  MOZ_ASSERT(target);
+  if (!mTaskQueue) {
+    nsCOMPtr<nsIEventTarget> target
+      = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+    MOZ_ASSERT(target);
 
-  nsresult rv = target->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+    mTaskQueue = new TaskQueue(target.forget());
   }
 
-  return NS_OK;
+  nsCOMPtr<nsIRunnable> runnable(aRunnable);
+  mTaskQueue->Dispatch(runnable.forget());
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/file/MutableBlobStorage.h
+++ b/dom/file/MutableBlobStorage.h
@@ -6,16 +6,19 @@
 
 #ifndef mozilla_dom_MutableBlobStorage_h
 #define mozilla_dom_MutableBlobStorage_h
 
 #include "mozilla/RefPtr.h"
 #include "prio.h"
 
 namespace mozilla {
+
+class TaskQueue;
+
 namespace dom {
 
 class Blob;
 class BlobImpl;
 class MutableBlobStorage;
 
 class MutableBlobStorageCallback
 {
@@ -64,17 +67,17 @@ private:
   ~MutableBlobStorage();
 
   bool ExpandBufferSize(uint64_t aSize);
 
   bool ShouldBeTemporaryStorage(uint64_t aSize) const;
 
   nsresult MaybeCreateTemporaryFile();
 
-  static nsresult DispatchToIOThread(Runnable* aRunnable);
+  void DispatchToIOThread(already_AddRefed<nsIRunnable> aRunnable);
 
   // All these variables are touched on the main thread only.
 
   void* mData;
   uint64_t mDataLen;
   uint64_t mDataBufferLen;
 
   enum StorageState {
@@ -85,14 +88,16 @@ private:
     eClosed
   };
 
   StorageState mStorageState;
 
   PRFileDesc* mFD;
 
   nsresult mErrorResult;
+
+  RefPtr<TaskQueue> mTaskQueue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MutableBlobStorage_h