Bug 1365534 - Close temp file in FileBlockCache thread - r?cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Wed, 17 May 2017 16:00:39 +1200
changeset 580043 14363204f5a48ea636d8b97c271ef81502b0b458
parent 580042 a7a9122cbcb902f68ff7763866c05007d475a2b7
child 580044 29b072418fc4e9262eb2d427d87ce02e8d5bbf8c
push id59433
push usergsquelart@mozilla.com
push dateThu, 18 May 2017 04:39:26 +0000
reviewerscpearce
bugs1365534
milestone55.0a1
Bug 1365534 - Close temp file in FileBlockCache thread - r?cpearce Closing the temporary file was done in the FileBlockCache destructor, which is called on the main thread. Instead, we are now dispatching a new final task from Close, which will close the temporary file and then shutdown the thread. The thread and FD ownerships are transferred to that final task, so that no more tasks may be unexpectly queued to that thread, and both members can immediately be reused after Close() returns. MozReview-Commit-ID: L9djYGhDFn4
dom/media/FileBlockCache.cpp
--- a/dom/media/FileBlockCache.cpp
+++ b/dom/media/FileBlockCache.cpp
@@ -98,53 +98,63 @@ FileBlockCache::FileBlockCache()
     mIsWriteScheduled(false),
     mIsOpen(false)
 {
 }
 
 FileBlockCache::~FileBlockCache()
 {
   NS_ASSERTION(!mIsOpen, "Should Close() FileBlockCache before destroying");
-  {
-    // Note, mThread will be shutdown by the time this runs, so we won't
-    // block while taking mFileMonitor.
-    MonitorAutoLock mon(mFileMonitor);
-    if (mFD) {
-      PRStatus prrc;
-      prrc = PR_Close(mFD);
-      if (prrc != PR_SUCCESS) {
-        NS_WARNING("PR_Close() failed.");
-      }
-      mFD = nullptr;
-    }
-  }
 }
 
 void FileBlockCache::Close()
 {
   LOG("Close()");
 
-  MonitorAutoLock mon(mDataMonitor);
-  if (!mIsOpen) {
-    return;
+  nsCOMPtr<nsIThread> thread;
+  {
+    MonitorAutoLock mon(mDataMonitor);
+    if (!mIsOpen) {
+      return;
+    }
+    mIsOpen = false;
+    if (!mThread) {
+      return;
+    }
+    thread.swap(mThread);
   }
-  mIsOpen = false;
-  if (!mThread) {
-    return;
+
+  PRFileDesc* fd;
+  {
+    MonitorAutoLock lock(mFileMonitor);
+    fd = mFD;
+    mFD = nullptr;
   }
-  // We must shut down the thread in another runnable. This is called
-  // while we're shutting down the media cache, and nsIThread::Shutdown()
-  // can cause events to run before it completes, which could end up
-  // opening more streams, while the media cache is shutting down and
-  // releasing memory etc! Also note we close mFD in the destructor so
-  // as to not disturb any IO that's currently running.
-  nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mThread);
-  SystemGroup::Dispatch(
-    "ShutdownThreadEvent", TaskCategory::Other, event.forget());
-  mThread = nullptr;
+
+  // Let the thread close the FD, and then trigger its own shutdown.
+  // Note that mThread is now empty, so no other task will be posted there.
+  // Also mThread and mFD are empty and therefore can be reused immediately.
+  nsresult rv = thread->Dispatch(NS_NewRunnableFunction([thread, fd] {
+    if (fd) {
+      PRStatus prrc;
+      prrc = PR_Close(fd);
+      if (prrc != PR_SUCCESS) {
+        NS_WARNING("PR_Close() failed.");
+      }
+    }
+    // We must shut down the thread in another runnable. This is called
+    // while we're shutting down the media cache, and nsIThread::Shutdown()
+    // can cause events to run before it completes, which could end up
+    // opening more streams, while the media cache is shutting down and
+    // releasing memory etc!
+    nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(thread);
+    SystemGroup::Dispatch(
+      "ShutdownThreadEvent", TaskCategory::Other, event.forget());
+  }), NS_DISPATCH_NORMAL);
+  NS_ENSURE_SUCCESS_VOID(rv);
 }
 
 template<typename Container, typename Value>
 bool
 ContainerContains(const Container& aContainer, const Value& value)
 {
   return std::find(aContainer.begin(), aContainer.end(), value)
          != aContainer.end();