Bug 1207220: Ensure MediaShutdownManager waits until all MediaDecoder have completed their shutdown. r=cpearce

XPCOM when shutting down expects all tasks to be run synchronously. As such, we must ensure that the remaining MediaDecoder are shut down before continuing on the next task.
In particular destroying gfxPlatforms must only ever happen after, as it is possible for the MediaDecoderReader to make use of gfx resources during shutdown.
This commit is contained in:
Jean-Yves Avenard 2016-01-04 14:53:02 +11:00
Родитель a9f31c44eb
Коммит 3c25c690a7
6 изменённых файлов: 59 добавлений и 16 удалений

Просмотреть файл

@ -595,14 +595,14 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
MediaShutdownManager::Instance().Register(this);
}
void
RefPtr<ShutdownPromise>
MediaDecoder::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown)
return;
if (mShuttingDown) {
return ShutdownPromise::CreateAndResolve(true, __func__);
}
mShuttingDown = true;
mResourceCallback->Disconnect();
@ -614,6 +614,7 @@ MediaDecoder::Shutdown()
// This changes the decoder state to SHUTDOWN and does other things
// necessary to unblock the state machine thread if it's blocked, so
// the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
RefPtr<ShutdownPromise> shutdown;
if (mDecoderStateMachine) {
mTimedMetadataListener.Disconnect();
mMetadataLoadedListener.Disconnect();
@ -622,9 +623,11 @@ MediaDecoder::Shutdown()
mOnSeekingStart.Disconnect();
mOnMediaNotSeekable.Disconnect();
mDecoderStateMachine->BeginShutdown()->Then(
AbstractThread::MainThread(), __func__, this,
&MediaDecoder::FinishShutdown, &MediaDecoder::FinishShutdown);
shutdown = mDecoderStateMachine->BeginShutdown()
->Then(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::FinishShutdown,
&MediaDecoder::FinishShutdown)
->CompletionPromise();
}
// Force any outstanding seek and byterange requests to complete
@ -638,6 +641,8 @@ MediaDecoder::Shutdown()
ChangeState(PLAY_STATE_SHUTDOWN);
MediaShutdownManager::Instance().Unregister(this);
return shutdown ? shutdown : ShutdownPromise::CreateAndResolve(true, __func__);
}
MediaDecoder::~MediaDecoder()
@ -671,12 +676,13 @@ MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
}
}
void
RefPtr<ShutdownPromise>
MediaDecoder::FinishShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
mDecoderStateMachine->BreakCycles();
SetStateMachine(nullptr);
return ShutdownPromise::CreateAndResolve(true, __func__);
}
MediaResourceCallback*

Просмотреть файл

@ -346,7 +346,7 @@ public:
// Cleanup internal data structures. Must be called on the main
// thread by the owning object before that object disposes of this object.
virtual void Shutdown();
virtual RefPtr<ShutdownPromise> Shutdown();
// Start downloading the media. Decode the downloaded data up to the
// point of the first frame of data.
@ -803,7 +803,7 @@ private:
SetMediaSeekable(false);
}
void FinishShutdown();
RefPtr<ShutdownPromise> FinishShutdown();
MediaEventProducer<void> mDataArrivedEvent;

Просмотреть файл

@ -18,8 +18,9 @@ extern LazyLogModule gMediaDecoderLog;
NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIObserver)
MediaShutdownManager::MediaShutdownManager()
: mIsObservingShutdown(false),
mIsDoingXPCOMShutDown(false)
: mIsObservingShutdown(false)
, mIsDoingXPCOMShutDown(false)
, mCompletedShutdown(false)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(MediaShutdownManager);
@ -114,11 +115,35 @@ MediaShutdownManager::Shutdown()
// Iterate over the decoders and shut them down, and remove them from the
// hashtable.
nsTArray<RefPtr<ShutdownPromise>> promises;
for (auto iter = mDecoders.Iter(); !iter.Done(); iter.Next()) {
iter.Get()->GetKey()->Shutdown();
promises.AppendElement(iter.Get()->GetKey()->Shutdown()->Then(
// We want to ensure that all shutdowns have completed, regardless
// of the ShutdownPromise being resolved or rejected. At this stage,
// a MediaDecoder's ShutdownPromise is only ever resolved, but as this may
// change in the future we want to avoid nasty surprises, so we wrap the
// ShutdownPromise into our own that will only ever be resolved.
AbstractThread::MainThread(), __func__,
[]() -> RefPtr<ShutdownPromise> {
return ShutdownPromise::CreateAndResolve(true, __func__);
},
[]() -> RefPtr<ShutdownPromise> {
return ShutdownPromise::CreateAndResolve(true, __func__);
})->CompletionPromise());
iter.Remove();
}
if (!promises.IsEmpty()) {
ShutdownPromise::All(AbstractThread::MainThread(), promises)
->Then(AbstractThread::MainThread(), __func__, this,
&MediaShutdownManager::FinishShutdown,
&MediaShutdownManager::FinishShutdown);
// Wait for all decoders to complete their async shutdown...
while (!mCompletedShutdown) {
NS_ProcessNextEvent(NS_GetCurrentThread(), true);
}
}
// Remove the MediaShutdownManager instance from the shutdown observer
// list.
nsContentUtils::UnregisterShutdownObserver(this);
@ -132,4 +157,11 @@ MediaShutdownManager::Shutdown()
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::Shutdown() end."));
}
void
MediaShutdownManager::FinishShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
mCompletedShutdown = true;
}
} // namespace mozilla

Просмотреть файл

@ -81,6 +81,7 @@ private:
virtual ~MediaShutdownManager();
void Shutdown();
void FinishShutdown();
// Ensures we have a shutdown listener if we need one, and removes the
// listener and destroys the singleton if we don't.
@ -97,6 +98,10 @@ private:
bool mIsObservingShutdown;
bool mIsDoingXPCOMShutDown;
// Will be set to true once all registered MediaDecoders have completed their
// shutdown.
bool mCompletedShutdown;
};
} // namespace mozilla

Просмотреть файл

@ -139,7 +139,7 @@ MediaSourceDecoder::GetBuffered()
return buffered;
}
void
RefPtr<ShutdownPromise>
MediaSourceDecoder::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
@ -151,7 +151,7 @@ MediaSourceDecoder::Shutdown()
}
mDemuxer = nullptr;
MediaDecoder::Shutdown();
return MediaDecoder::Shutdown();
}
/*static*/

Просмотреть файл

@ -50,7 +50,7 @@ public:
mDormantSupported = aSupported;
}
virtual void Shutdown() override;
virtual RefPtr<ShutdownPromise> Shutdown() override;
static already_AddRefed<MediaResource> CreateResource(nsIPrincipal* aPrincipal = nullptr);