Bug 785909 - Don't init FileMediaResource::mSize on the main thread. r=roc
authorChris Pearce <cpearce@mozilla.com>
Wed, 29 Aug 2012 15:55:57 +1200
changeset 110034 e6517dae3b952faed11a8c5e4f7e9f23d98a0278
parent 110033 4a4696fcfd03c2a81c4f442fdab6a5ab9da37dc0
child 110035 747584155b62aaf0c2a9919104c730df29fe63d1
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs785909
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 785909 - Don't init FileMediaResource::mSize on the main thread. r=roc
content/media/MediaResource.cpp
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -913,17 +913,18 @@ ChannelMediaResource::PossiblyResume()
   }
 }
 
 class FileMediaResource : public MediaResource
 {
 public:
   FileMediaResource(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
     MediaResource(aDecoder, aChannel, aURI), mSize(-1),
-    mLock("FileMediaResource.mLock")
+    mLock("FileMediaResource.mLock"),
+    mSizeInitialized(false)
   {
   }
   ~FileMediaResource()
   {
   }
 
   // Main thread
   virtual nsresult Open(nsIStreamListener** aStreamListener);
@@ -950,17 +951,21 @@ public:
   virtual void    Pin() {}
   virtual void    Unpin() {}
   virtual double  GetDownloadRate(bool* aIsReliable)
   {
     // The data's all already here
     *aIsReliable = true;
     return 100*1024*1024; // arbitray, use 100MB/s
   }
-  virtual int64_t GetLength() { return mSize; }
+  virtual int64_t GetLength() {
+    MutexAutoLock lock(mLock);
+    EnsureLengthInitialized();
+    return mSize;
+  }
   virtual int64_t GetNextCachedData(int64_t aOffset)
   {
     return (aOffset < mSize) ? aOffset : -1;
   }
   virtual int64_t GetCachedDataEnd(int64_t aOffset) { return NS_MAX(aOffset, mSize); }
   virtual bool    IsDataCachedToEndOfResource(int64_t aOffset) { return true; }
   virtual bool    IsSuspendedByCache(MediaResource** aActiveResource)
   {
@@ -969,16 +974,19 @@ public:
     }
     return false;
   }
   virtual bool    IsSuspended() { return false; }
 
   nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
 
 private:
+  // Ensures mSize is initialized, if it can be.
+  void EnsureLengthInitialized();
+
   // The file size, or -1 if not known. Immutable after Open().
   int64_t mSize;
 
   // This lock handles synchronisation between calls to Close() and
   // the Read, Seek, etc calls. Close must not be called while a
   // Read or Seek is in progress since it resets various internal
   // values to null.
   // This lock protects mSeekable and mInput.
@@ -986,16 +994,21 @@ private:
 
   // Seekable stream interface to file. This can be used from any
   // thread.
   nsCOMPtr<nsISeekableStream> mSeekable;
 
   // Input stream for the media data. This can be used from any
   // thread.
   nsCOMPtr<nsIInputStream>  mInput;
+
+  // Whether we've attempted to initialize mSize. Note that mSize can be -1
+  // when mSizeInitialized is true if we tried and failed to get the size
+  // of the file.
+  bool mSizeInitialized;
 };
 
 class LoadedEvent : public nsRunnable
 {
 public:
   LoadedEvent(nsMediaDecoder* aDecoder) :
     mDecoder(aDecoder)
   {
@@ -1010,18 +1023,37 @@ public:
     mDecoder->NotifyDownloadEnded(NS_OK);
     return NS_OK;
   }
 
 private:
   nsRefPtr<nsMediaDecoder> mDecoder;
 };
 
+void FileMediaResource::EnsureLengthInitialized()
+{
+  mLock.AssertCurrentThreadOwns();
+  if (mSizeInitialized) {
+    return;
+  }
+  mSizeInitialized = true;
+  // Get the file size and inform the decoder.
+  uint64_t size;
+  nsresult res = mInput->Available(&size);
+  if (NS_SUCCEEDED(res) && size <= PR_INT64_MAX) {
+    mSize = (int64_t)size;
+    nsCOMPtr<nsIRunnable> event = new LoadedEvent(mDecoder);
+    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+  }
+}
+
 nsresult FileMediaResource::GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
 {
+  MutexAutoLock lock(mLock);
+  EnsureLengthInitialized();
   if (mSize == -1) {
     return NS_ERROR_FAILURE;
   }
   aRanges.AppendElement(MediaByteRange(0, mSize));
   return NS_OK;
 }
 
 nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener)
@@ -1066,26 +1098,16 @@ nsresult FileMediaResource::Open(nsIStre
   if (!mSeekable) {
     // XXX The file may just be a .url or similar
     // shortcut that points to a Web site. We need to fix this by
     // doing an async open and waiting until we locate the real resource,
     // then using that (if it's still a file!).
     return NS_ERROR_FAILURE;
   }
 
-  // Get the file size and inform the decoder.
-  uint64_t size;
-  rv = mInput->Available(&size);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(size <= PR_INT64_MAX, NS_ERROR_FILE_TOO_BIG);
- 
-  mSize = (int64_t)size;
-
-  nsCOMPtr<nsIRunnable> event = new LoadedEvent(mDecoder);
-  NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 nsresult FileMediaResource::Close()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   MutexAutoLock lock(mLock);
@@ -1135,16 +1157,17 @@ MediaResource* FileMediaResource::CloneD
     return nullptr;
 
   return new FileMediaResource(aDecoder, channel, mURI);
 }
 
 nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
 {
   MutexAutoLock lock(mLock);
+  EnsureLengthInitialized();
   if (!mInput || !mSeekable)
     return NS_ERROR_FAILURE;
   int64_t offset = 0;
   nsresult res = mSeekable->Tell(&offset);
   NS_ENSURE_SUCCESS(res,res);
   res = mSeekable->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
   NS_ENSURE_SUCCESS(res,res);
   uint32_t bytesRead = 0;
@@ -1164,38 +1187,41 @@ nsresult FileMediaResource::ReadFromCach
 
   // Else we succeed if the reset-seek succeeds.
   return seekres;
 }
 
 nsresult FileMediaResource::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
 {
   MutexAutoLock lock(mLock);
+  EnsureLengthInitialized();
   if (!mInput)
     return NS_ERROR_FAILURE;
   return mInput->Read(aBuffer, aCount, aBytes);
 }
 
 nsresult FileMediaResource::Seek(int32_t aWhence, int64_t aOffset)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   MutexAutoLock lock(mLock);
   if (!mSeekable)
     return NS_ERROR_FAILURE;
+  EnsureLengthInitialized();
   return mSeekable->Seek(aWhence, aOffset);
 }
 
 int64_t FileMediaResource::Tell()
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   MutexAutoLock lock(mLock);
   if (!mSeekable)
     return 0;
+  EnsureLengthInitialized();
 
   int64_t offset = 0;
   mSeekable->Tell(&offset);
   return offset;
 }
 
 MediaResource*
 MediaResource::Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel)