Bug 1400166. P2 - Flush() should dispatch a task to clear arrays. draft
authorJW Wang <jwwang@mozilla.com>
Mon, 18 Sep 2017 11:07:52 +0800
changeset 666189 9b140bb729b974f0146c25704c09173ce63a0de2
parent 666188 ba49d265551a889519ebea1b37e05cd8b328e575
child 666823 6e81842faab0def555dfbc130aa92bfdedef9d1a
push id80301
push userjwwang@mozilla.com
push dateMon, 18 Sep 2017 06:00:41 +0000
bugs1400166
milestone57.0a1
Bug 1400166. P2 - Flush() should dispatch a task to clear arrays. If mBlockChanges is cleared when PerformBlockIOs() is dropping the data lock, blockIndex will become an invalid index after it acquire the data lock again. MozReview-Commit-ID: 5Cu2TgEO3F5
dom/media/FileBlockCache.cpp
--- a/dom/media/FileBlockCache.cpp
+++ b/dom/media/FileBlockCache.cpp
@@ -116,20 +116,27 @@ FileBlockCache::Init()
 }
 
 void
 FileBlockCache::Flush()
 {
   LOG("Flush()");
   MutexAutoLock mon(mDataMutex);
   MOZ_ASSERT(mThread);
-  // Just discard pending changes, assume MediaCache won't read from
-  // blocks it hasn't written to.
-  mChangeIndexList.clear();
-  mBlockChanges.Clear();
+
+  // Dispatch a task so we won't clear the arrays while PerformBlockIOs() is
+  // dropping the data lock and cause InvalidArrayIndex.
+  RefPtr<FileBlockCache> self = this;
+  mThread->Dispatch(NS_NewRunnableFunction("FileBlockCache::Flush", [self]() {
+    MutexAutoLock mon(self->mDataMutex);
+    // Just discard pending changes, assume MediaCache won't read from
+    // blocks it hasn't written to.
+    self->mChangeIndexList.clear();
+    self->mBlockChanges.Clear();
+  }));
 }
 
 int32_t
 FileBlockCache::GetMaxBlocks() const
 {
   // We look up the cache size every time. This means dynamic changes
   // to the pref are applied.
   const uint32_t cacheSizeKb =
@@ -350,17 +357,17 @@ nsresult FileBlockCache::MoveBlockInFile
     return NS_ERROR_FAILURE;
   }
   return WriteBlockToFile(aDestBlockIndex, buf);
 }
 
 void
 FileBlockCache::PerformBlockIOs()
 {
-  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
   MutexAutoLock mon(mDataMutex);
   NS_ASSERTION(mIsWriteScheduled, "Should report write running or scheduled.");
 
   LOG("Run() mFD=%p mThread=%p", mFD, mThread.get());
 
   while (!mChangeIndexList.empty()) {
     if (!mThread) {
       // We've been closed, abort, discarding unwritten changes.