Bug 1426578. P2 - always access MediaCache::mStreams while the cache monitor is held. draft
authorJW Wang <jwwang@mozilla.com>
Fri, 15 Dec 2017 11:23:27 +0800
changeset 713857 1a2469069657433d4752c6f88a32d5df74675d03
parent 713856 13667c7100ae1404c207fbed43f1e573bb8ac96d
child 713858 c77249307248f65f7c9902a8068a70d8548368fd
push id93781
push userjwwang@mozilla.com
push dateThu, 21 Dec 2017 03:28:43 +0000
bugs1426578
milestone59.0a1
Bug 1426578. P2 - always access MediaCache::mStreams while the cache monitor is held. Note we offload MediaCache::CloseStreamsForPrivateBrowsing() to another thread so we don't need to take the cache monitor on the main thread. MozReview-Commit-ID: 9hYszHZ0OJJ
dom/media/MediaCache.cpp
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -248,26 +248,27 @@ public:
   void Verify(AutoLock&) {}
 #endif
 
   ReentrantMonitor& Monitor() { return mMonitor; }
 
   /**
    * An iterator that makes it easy to iterate through all streams that
    * have a given resource ID and are not closed.
-   * Can be used on the main thread or while holding the media cache lock.
+   * Must be used while holding the media cache lock.
    */
   class ResourceStreamIterator
   {
   public:
     ResourceStreamIterator(MediaCache* aMediaCache, int64_t aResourceID)
       : mMediaCache(aMediaCache)
       , mResourceID(aResourceID)
       , mNext(0)
     {
+      aMediaCache->mMonitor.AssertCurrentThreadIn();
     }
     MediaCacheStream* Next(AutoLock& aLock)
     {
       while (mNext < mMediaCache->mStreams.Length()) {
         MediaCacheStream* stream = mMediaCache->mStreams[mNext];
         ++mNext;
         if (stream->GetResourceID() == mResourceID && !stream->IsClosed(aLock))
           return stream;
@@ -438,18 +439,17 @@ protected:
   // This member is main-thread only. It's used to allocate unique
   // resource IDs to streams.
   int64_t mNextResourceID = 0;
 
   // The monitor protects all the data members here. Also, off-main-thread
   // readers that need to block will Wait() on this monitor. When new
   // data becomes available in the cache, we NotifyAll() on this monitor.
   ReentrantMonitor mMonitor;
-  // This is only written while on the main thread and the monitor is held.
-  // Thus, it can be safely read from the main thread or while holding the monitor.
+  // This must always be accessed when the monitor is held.
   nsTArray<MediaCacheStream*> mStreams;
   // The Blocks describing the cache entries.
   nsTArray<Block> mIndex;
   // Keep track for highest number of blocks used, for telemetry purposes.
   int32_t mIndexWatermark = 0;
   // Keep track for highest number of blocks owners, for telemetry purposes.
   uint32_t mBlockOwnersWatermark = 0;
   // Writer which performs IO, asynchronously writing cache blocks.
@@ -719,21 +719,26 @@ MediaCache::Flush()
     });
   sThread->Dispatch(r.forget());
 }
 
 void
 MediaCache::CloseStreamsForPrivateBrowsing()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  for (MediaCacheStream* s : mStreams) {
-    if (s->mIsPrivateBrowsing) {
-      s->mClient->Close();
-    }
-  }
+  sThread->Dispatch(
+    NS_NewRunnableFunction("MediaCache::CloseStreamsForPrivateBrowsing",
+                           [self = RefPtr<MediaCache>(this)]() {
+                             AutoLock lock(self->mMonitor);
+                             for (MediaCacheStream* s : self->mStreams) {
+                               if (s->mIsPrivateBrowsing) {
+                                 s->CloseInternal(lock);
+                               }
+                             }
+                           }));
 }
 
 /* static */ RefPtr<MediaCache>
 MediaCache::GetMediaCache(int64_t aContentLength)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   if (!sThreadInit) {