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
--- 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) {