Bug 1446931 - P1. Handle errors in Benchmark. r=gerald
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 29 Mar 2018 22:11:06 +0200
changeset 411695 13b8bb0d5cc6d241af2b2fa64eabf94c4e137973
parent 411694 f312d31f9c3cc19732ab8d5f1e581835cba4ecf9
child 411696 8e0de009a63f8e4c05e16926d3dddbb1b63167e0
push id101729
push usercsabou@mozilla.com
push dateWed, 04 Apr 2018 18:07:35 +0000
treeherdermozilla-inbound@3c240f56a113 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1446931
milestone61.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 1446931 - P1. Handle errors in Benchmark. r=gerald Benchmark had never been intended to be able to process invalid content. However over time Benchmark class has been used extensively by the fuzzing team. As such, it became necessary to handle errors of all kind. MozReview-Commit-ID: E0YulHuoiq2
dom/media/Benchmark.cpp
dom/media/Benchmark.h
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -126,22 +126,29 @@ void
 Benchmark::ReturnResult(uint32_t aDecodeFps)
 {
   MOZ_ASSERT(OnThread());
 
   mPromise.ResolveIfExists(aDecodeFps, __func__);
 }
 
 void
+Benchmark::ReturnError(const MediaResult& aError)
+{
+  MOZ_ASSERT(OnThread());
+
+  mPromise.RejectIfExists(aError, __func__);
+}
+
+void
 Benchmark::Dispose()
 {
   MOZ_ASSERT(OnThread());
 
   mKeepAliveUntilComplete = nullptr;
-  mPromise.RejectIfExists(false, __func__);
 }
 
 void
 Benchmark::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
   gfxVars::Initialize();
   gfxPrefs::GetSingleton();
@@ -179,22 +186,22 @@ BenchmarkPlayback::DemuxSamples()
       if (mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack)) {
         mTrackDemuxer =
           mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
       } else if (mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack)) {
         mTrackDemuxer =
           mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
       }
       if (!mTrackDemuxer) {
-        MainThreadShutdown();
+        Error(MediaResult(NS_ERROR_FAILURE, "Can't create track demuxer"));
         return;
       }
       DemuxNextSample();
     },
-    [this, ref](const MediaResult& aError) { MainThreadShutdown(); });
+    [this, ref](const MediaResult& aError) { Error(aError); });
 }
 
 void
 BenchmarkPlayback::DemuxNextSample()
 {
   MOZ_ASSERT(OnThread());
 
   RefPtr<Benchmark> ref(mMainThreadState);
@@ -212,41 +219,62 @@ BenchmarkPlayback::DemuxNextSample()
       }
     },
     [this, ref](const MediaResult& aError) {
       switch (aError.Code()) {
         case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
           InitDecoder(Move(*mTrackDemuxer->GetInfo()));
           break;
         default:
-          MainThreadShutdown();
+          Error(aError);
+          break;
       }
     });
 }
 
 void
 BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo)
 {
   MOZ_ASSERT(OnThread());
 
   RefPtr<PDMFactory> platform = new PDMFactory();
   mDecoder = platform->CreateDecoder({ aInfo, mDecoderTaskQueue });
   if (!mDecoder) {
-    MainThreadShutdown();
+    Error(MediaResult(NS_ERROR_FAILURE, "Failed to create decoder"));
     return;
   }
   RefPtr<Benchmark> ref(mMainThreadState);
   mDecoder->Init()->Then(
     Thread(), __func__,
-    [this, ref](TrackInfo::TrackType aTrackType) {
-      InputExhausted();
-    },
-    [this, ref](const MediaResult& aError) {
-      MainThreadShutdown();
-    });
+    [this, ref](TrackInfo::TrackType aTrackType) { InputExhausted(); },
+    [this, ref](const MediaResult& aError) { Error(aError); });
+}
+
+void
+BenchmarkPlayback::FinalizeShutdown()
+{
+  MOZ_ASSERT(OnThread());
+
+  MOZ_ASSERT(!mDecoder, "mDecoder must have been shutdown already");
+  mDecoderTaskQueue->BeginShutdown();
+  mDecoderTaskQueue->AwaitShutdownAndIdle();
+  mDecoderTaskQueue = nullptr;
+
+  if (mTrackDemuxer) {
+    mTrackDemuxer->Reset();
+    mTrackDemuxer->BreakCycles();
+    mTrackDemuxer = nullptr;
+  }
+  mDemuxer = nullptr;
+
+  RefPtr<Benchmark> ref(mMainThreadState);
+  Thread()->AsTaskQueue()->BeginShutdown()->Then(
+    ref->Thread(), __func__,
+    [ref]() { ref->Dispose(); },
+    []() { MOZ_CRASH("not reached"); });
 }
 
 void
 BenchmarkPlayback::MainThreadShutdown()
 {
   MOZ_ASSERT(OnThread());
 
   if (mFinished) {
@@ -258,35 +286,24 @@ BenchmarkPlayback::MainThreadShutdown()
   if (mDecoder) {
     RefPtr<Benchmark> ref(mMainThreadState);
     mDecoder->Flush()->Then(
       Thread(), __func__,
       [ref, this]() {
         mDecoder->Shutdown()->Then(
           Thread(), __func__,
           [ref, this]() {
-            mDecoderTaskQueue->BeginShutdown();
-            mDecoderTaskQueue->AwaitShutdownAndIdle();
-            mDecoderTaskQueue = nullptr;
-
-            if (mTrackDemuxer) {
-              mTrackDemuxer->Reset();
-              mTrackDemuxer->BreakCycles();
-              mTrackDemuxer = nullptr;
-            }
-
-            Thread()->AsTaskQueue()->BeginShutdown()->Then(
-              ref->Thread(), __func__,
-              [ref]() { ref->Dispose(); },
-              []() { MOZ_CRASH("not reached"); });
+            FinalizeShutdown();
           },
           []() { MOZ_CRASH("not reached"); });
         mDecoder = nullptr;
       },
       []() { MOZ_CRASH("not reached"); });
+  } else {
+    FinalizeShutdown();
   }
 }
 
 void
 BenchmarkPlayback::Output(const MediaDataDecoder::DecodedData& aResults)
 {
   MOZ_ASSERT(OnThread());
   RefPtr<Benchmark> ref(mMainThreadState);
@@ -305,39 +322,51 @@ BenchmarkPlayback::Output(const MediaDat
     ref->Dispatch(
       NS_NewRunnableFunction("BenchmarkPlayback::Output", [ref, decodeFps]() {
         ref->ReturnResult(decodeFps);
       }));
   }
 }
 
 void
+BenchmarkPlayback::Error(const MediaResult& aError)
+{
+  MOZ_ASSERT(OnThread());
+
+  RefPtr<Benchmark> ref(mMainThreadState);
+  MainThreadShutdown();
+  ref->Dispatch(NS_NewRunnableFunction(
+    "BenchmarkPlayback::Error",
+    [ref, aError]() { ref->ReturnError(aError); }));
+}
+
+void
 BenchmarkPlayback::InputExhausted()
 {
   MOZ_ASSERT(OnThread());
   if (mFinished || mSampleIndex >= mSamples.Length()) {
     return;
   }
   RefPtr<Benchmark> ref(mMainThreadState);
   mDecoder->Decode(mSamples[mSampleIndex])
     ->Then(Thread(), __func__,
            [ref, this](const MediaDataDecoder::DecodedData& aResults) {
              Output(aResults);
              InputExhausted();
            },
-           [ref, this](const MediaResult& aError) { MainThreadShutdown(); });
+           [ref, this](const MediaResult& aError) { Error(aError); });
   mSampleIndex++;
   if (mSampleIndex == mSamples.Length()) {
     if (ref->mParameters.mStopAtFrame) {
       mSampleIndex = 0;
     } else {
       mDecoder->Drain()->Then(
         Thread(), __func__,
         [ref, this](const MediaDataDecoder::DecodedData& aResults) {
           mDrained = true;
           Output(aResults);
         },
-        [ref, this](const MediaResult& aError) { MainThreadShutdown(); });
+        [ref, this](const MediaResult& aError) { Error(aError); });
     }
   }
 }
 
 } // namespace mozilla
--- a/dom/media/Benchmark.h
+++ b/dom/media/Benchmark.h
@@ -25,18 +25,22 @@ class BenchmarkPlayback : public QueueOb
   friend class Benchmark;
   BenchmarkPlayback(Benchmark* aMainThreadState, MediaDataDemuxer* aDemuxer);
   void DemuxSamples();
   void DemuxNextSample();
   void MainThreadShutdown();
   void InitDecoder(TrackInfo&& aInfo);
 
   void Output(const MediaDataDecoder::DecodedData& aResults);
+  void Error(const MediaResult& aError);
   void InputExhausted();
 
+  // Shutdown trackdemuxer and demuxer if any and shutdown the task queues.
+  void FinalizeShutdown();
+
   Atomic<Benchmark*> mMainThreadState;
 
   RefPtr<TaskQueue> mDecoderTaskQueue;
   RefPtr<MediaDataDecoder> mDecoder;
 
   // Object only accessed on Thread()
   RefPtr<MediaDataDemuxer> mDemuxer;
   RefPtr<MediaTrackDemuxer> mTrackDemuxer;
@@ -76,28 +80,29 @@ public:
     }
 
     const int32_t mFramesToMeasure;
     const uint32_t mStartupFrame;
     const Maybe<int32_t> mStopAtFrame;
     const TimeDuration mTimeout;
   };
 
-  typedef MozPromise<uint32_t, bool, /* IsExclusive = */ true> BenchmarkPromise;
+  typedef MozPromise<uint32_t, MediaResult, /* IsExclusive = */ true> BenchmarkPromise;
 
   explicit Benchmark(MediaDataDemuxer* aDemuxer,
                      const Parameters& aParameters = Parameters());
   RefPtr<BenchmarkPromise> Run();
 
   static void Init();
 
 private:
   friend class BenchmarkPlayback;
   virtual ~Benchmark();
   void ReturnResult(uint32_t aDecodeFps);
+  void ReturnError(const MediaResult& aError);
   void Dispose();
   const Parameters mParameters;
   RefPtr<Benchmark> mKeepAliveUntilComplete;
   BenchmarkPlayback mPlaybackState;
   MozPromiseHolder<BenchmarkPromise> mPromise;
 };
 
 class VP9Benchmark