Backed out changeset 18c302f80bce (bug 1108707) for nsTArray_base leaks.

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2014-12-09 15:49:38 -05:00
parent b392b7de2a
commit 073573c2a9
22 changed files with 84 additions and 180 deletions

View File

@ -283,28 +283,18 @@ MediaDecoderReader::BreakCycles()
mTaskQueue = nullptr;
}
nsRefPtr<ShutdownPromise>
void
MediaDecoderReader::Shutdown()
{
MOZ_ASSERT(OnDecodeThread());
mShutdown = true;
ReleaseMediaResources();
nsRefPtr<ShutdownPromise> p;
// Spin down the task queue if necessary. We wait until BreakCycles to null
// out mTaskQueue, since otherwise any remaining tasks could crash when they
// invoke GetTaskQueue()->IsCurrentThreadIn().
if (mTaskQueue && !mTaskQueueIsBorrowed) {
// If we own our task queue, shutdown ends when the task queue is done.
p = mTaskQueue->BeginShutdown();
} else {
// If we don't own our task queue, we resolve immediately (though
// asynchronously).
p = new ShutdownPromise(__func__);
p->Resolve(true, __func__);
// We may be running in the task queue ourselves, so we don't block this
// thread on task queue draining, since that would deadlock.
mTaskQueue->BeginShutdown();
}
return p;
mTaskQueue = nullptr;
}
AudioDecodeRendezvous::AudioDecodeRendezvous()

View File

@ -65,7 +65,7 @@ public:
// This is different from ReleaseMediaResources() as it is irreversable,
// whereas ReleaseMediaResources() is. Must be called on the decode
// thread.
virtual nsRefPtr<ShutdownPromise> Shutdown();
virtual void Shutdown();
virtual void SetCallback(RequestSampleCallback* aDecodedSampleCallback);
MediaTaskQueue* EnsureTaskQueue();

View File

@ -2470,53 +2470,6 @@ private:
nsRefPtr<MediaDecoderStateMachine> mStateMachine;
};
void
MediaDecoderStateMachine::ShutdownReader()
{
MOZ_ASSERT(OnDecodeThread());
mReader->Shutdown()->Then(GetStateMachineThread(), __func__, this,
&MediaDecoderStateMachine::FinishShutdown,
&MediaDecoderStateMachine::FinishShutdown);
}
void
MediaDecoderStateMachine::FinishShutdown(bool aSuccess)
{
MOZ_ASSERT(OnStateMachineThread());
MOZ_ASSERT(aSuccess);
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
// The reader's listeners hold references to the state machine,
// creating a cycle which keeps the state machine and its shared
// thread pools alive. So break it here.
AudioQueue().ClearListeners();
VideoQueue().ClearListeners();
// Now that those threads are stopped, there's no possibility of
// mPendingWakeDecoder being needed again. Revoke it.
mPendingWakeDecoder = nullptr;
MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN,
"How did we escape from the shutdown state?");
// We must daisy-chain these events to destroy the decoder. We must
// destroy the decoder on the main thread, but we can't destroy the
// decoder while this thread holds the decoder monitor. We can't
// dispatch an event to the main thread to destroy the decoder from
// here, as the event may run before the dispatch returns, and we
// hold the decoder monitor here. We also want to guarantee that the
// state machine is destroyed on the main thread, and so the
// event runner running this function (which holds a reference to the
// state machine) needs to finish and be released in order to allow
// that. So we dispatch an event to run after this event runner has
// finished and released its monitor/references. That event then will
// dispatch an event to the main thread to release the decoder and
// state machine.
GetStateMachineThread()->Dispatch(
new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL);
DECODER_LOG("Dispose Event Dispatched");
}
nsresult MediaDecoderStateMachine::RunStateMachine()
{
AssertCurrentThreadInMonitor();
@ -2533,14 +2486,47 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
StopAudioThread();
FlushDecoding();
// Put a task in the decode queue to shutdown the reader.
// Put a task in the decode queue to shutdown the reader and wait for
// the queue to spin down.
RefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ShutdownReader);
DebugOnly<nsresult> rv = DecodeTaskQueue()->Dispatch(task);
MOZ_ASSERT(NS_SUCCEEDED(rv));
{
RefPtr<nsIRunnable> task;
task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::Shutdown);
nsRefPtr<MediaTaskQueue> queue = DecodeTaskQueue();
DebugOnly<nsresult> rv = queue->Dispatch(task);
MOZ_ASSERT(NS_SUCCEEDED(rv));
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
queue->AwaitShutdownAndIdle();
}
DECODER_LOG("Shutdown started");
// The reader's listeners hold references to the state machine,
// creating a cycle which keeps the state machine and its shared
// thread pools alive. So break it here.
AudioQueue().ClearListeners();
VideoQueue().ClearListeners();
// Now that those threads are stopped, there's no possibility of
// mPendingWakeDecoder being needed again. Revoke it.
mPendingWakeDecoder = nullptr;
MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN,
"How did we escape from the shutdown state?");
// We must daisy-chain these events to destroy the decoder. We must
// destroy the decoder on the main thread, but we can't destroy the
// decoder while this thread holds the decoder monitor. We can't
// dispatch an event to the main thread to destroy the decoder from
// here, as the event may run before the dispatch returns, and we
// hold the decoder monitor here. We also want to guarantee that the
// state machine is destroyed on the main thread, and so the
// event runner running this function (which holds a reference to the
// state machine) needs to finish and be released in order to allow
// that. So we dispatch an event to run after this event runner has
// finished and released its monitor/references. That event then will
// dispatch an event to the main thread to release the decoder and
// state machine.
GetStateMachineThread()->Dispatch(
new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL);
DECODER_LOG("SHUTDOWN OK");
return NS_OK;
}

View File

@ -162,8 +162,6 @@ public:
// Set/Unset dormant state.
void SetDormant(bool aDormant);
void Shutdown();
void ShutdownReader();
void FinishShutdown(bool aSuccess);
// Called from the main thread to get the duration. The decoder monitor
// must be obtained before calling this. It is in units of microseconds.

View File

@ -134,17 +134,12 @@ MediaTaskQueue::AwaitShutdownAndIdle()
AwaitIdleLocked();
}
nsRefPtr<ShutdownPromise>
void
MediaTaskQueue::BeginShutdown()
{
MonitorAutoLock mon(mQueueMonitor);
mIsShutdown = true;
nsRefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
if (!mIsRunning) {
mShutdownPromise.Resolve(true, __func__);
}
mon.NotifyAll();
return p;
}
nsresult
@ -213,7 +208,6 @@ MediaTaskQueue::Runner::Run()
mQueue->mRunningThread = NS_GetCurrentThread();
if (mQueue->mTasks.size() == 0) {
mQueue->mIsRunning = false;
mQueue->mShutdownPromise.ResolveIfExists(true, __func__);
mon.NotifyAll();
return NS_OK;
}
@ -241,7 +235,6 @@ MediaTaskQueue::Runner::Run()
if (mQueue->mTasks.size() == 0) {
// No more events to run. Exit the task runner.
mQueue->mIsRunning = false;
mQueue->mShutdownPromise.ResolveIfExists(true, __func__);
mon.NotifyAll();
mQueue->mRunningThread = nullptr;
return NS_OK;

View File

@ -12,7 +12,6 @@
#include "mozilla/Monitor.h"
#include "SharedThreadPool.h"
#include "nsThreadUtils.h"
#include "MediaPromise.h"
class nsIRunnable;
@ -20,8 +19,6 @@ namespace mozilla {
class SharedThreadPool;
typedef MediaPromise<bool, bool> ShutdownPromise;
// Abstracts executing runnables in order in a thread pool. The runnables
// dispatched to the MediaTaskQueue will be executed in the order in which
// they're received, and are guaranteed to not be executed concurrently.
@ -53,9 +50,7 @@ public:
// remain alive at least until all the events are drained, because the Runners
// hold a strong reference to the task queue, and one of them is always held
// by the threadpool event queue when the task queue is non-empty.
//
// The returned promise is resolved when the queue goes empty.
nsRefPtr<ShutdownPromise> BeginShutdown();
void BeginShutdown();
// Blocks until all task finish executing.
void AwaitIdle();
@ -110,7 +105,6 @@ private:
// True if we've started our shutdown process.
bool mIsShutdown;
MediaPromiseHolder<ShutdownPromise> mShutdownPromise;
class MOZ_STACK_CLASS AutoSetFlushing
{

View File

@ -99,8 +99,7 @@ nsresult AndroidMediaReader::ReadMetadata(MediaInfo* aInfo,
return NS_OK;
}
nsRefPtr<ShutdownPromise>
AndroidMediaReader::Shutdown()
void AndroidMediaReader::Shutdown()
{
ResetDecode();
if (mPlugin) {
@ -108,7 +107,7 @@ AndroidMediaReader::Shutdown()
mPlugin = nullptr;
}
return MediaDecoderReader::Shutdown();
MediaDecoderReader::Shutdown();
}
// Resets all state related to decoding, emptying all buffers etc.

View File

@ -71,7 +71,7 @@ public:
MetadataTags** aTags);
virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
virtual void Shutdown() MOZ_OVERRIDE;
class ImageBufferCallback : public MPAPI::BufferCallback {
typedef mozilla::layers::Image Image;

View File

@ -139,7 +139,7 @@ MP4Reader::~MP4Reader()
MOZ_COUNT_DTOR(MP4Reader);
}
nsRefPtr<ShutdownPromise>
void
MP4Reader::Shutdown()
{
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
@ -172,7 +172,7 @@ MP4Reader::Shutdown()
mPlatform = nullptr;
}
return MediaDecoderReader::Shutdown();
MediaDecoderReader::Shutdown();
}
void

View File

@ -71,7 +71,7 @@ public:
virtual nsresult ResetDecode() MOZ_OVERRIDE;
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
virtual void Shutdown() MOZ_OVERRIDE;
private:

View File

@ -11,7 +11,6 @@
#include "nsCOMPtr.h"
#include "nsError.h"
#include "MediaDecoder.h"
#include "MediaSourceReader.h"
class nsIStreamListener;
@ -19,6 +18,7 @@ namespace mozilla {
class MediaResource;
class MediaDecoderStateMachine;
class MediaSourceReader;
class SourceBufferDecoder;
class TrackBuffer;
@ -71,8 +71,6 @@ public:
virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
#endif
MediaSourceReader* GetReader() { return mReader; }
private:
// The owning MediaSource holds a strong reference to this decoder, and
// calls Attach/DetachMediaSource on this decoder to set and clear

View File

@ -236,35 +236,17 @@ MediaSourceReader::OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason)
GetCallback()->OnNotDecoded(aType, WAITING_FOR_DATA);
}
nsRefPtr<ShutdownPromise>
void
MediaSourceReader::Shutdown()
{
MOZ_ASSERT(mMediaSourceShutdownPromise.IsEmpty());
nsRefPtr<ShutdownPromise> p = mMediaSourceShutdownPromise.Ensure(__func__);
ContinueShutdown(true);
return p;
}
void
MediaSourceReader::ContinueShutdown(bool aSuccess)
{
MOZ_ASSERT(aSuccess);
if (mTrackBuffers.Length()) {
mTrackBuffers[0]->Shutdown()->Then(GetTaskQueue(), __func__, this,
&MediaSourceReader::ContinueShutdown,
&MediaSourceReader::ContinueShutdown);
mShutdownTrackBuffers.AppendElement(mTrackBuffers[0]);
mTrackBuffers.RemoveElementAt(0);
return;
MediaDecoderReader::Shutdown();
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
mTrackBuffers[i]->Shutdown();
}
mAudioTrack = nullptr;
mAudioReader = nullptr;
mVideoTrack = nullptr;
mVideoReader = nullptr;
MediaDecoderReader::Shutdown()->ChainTo(mMediaSourceShutdownPromise.Steal(), __func__);
}
void
@ -277,12 +259,11 @@ MediaSourceReader::BreakCycles()
MOZ_ASSERT(!mAudioReader);
MOZ_ASSERT(!mVideoTrack);
MOZ_ASSERT(!mVideoReader);
MOZ_ASSERT(!mTrackBuffers.Length());
for (uint32_t i = 0; i < mShutdownTrackBuffers.Length(); ++i) {
mShutdownTrackBuffers[i]->BreakCycles();
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
mTrackBuffers[i]->BreakCycles();
}
mShutdownTrackBuffers.Clear();
mTrackBuffers.Clear();
}
already_AddRefed<MediaDecoderReader>

View File

@ -97,7 +97,7 @@ public:
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
void Shutdown();
virtual void BreakCycles();
@ -135,7 +135,6 @@ private:
nsRefPtr<MediaDecoderReader> mVideoReader;
nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
nsRefPtr<TrackBuffer> mAudioTrack;
nsRefPtr<TrackBuffer> mVideoTrack;
@ -177,9 +176,6 @@ private:
bool mVideoIsSeeking;
bool mHasEssentialTrackBuffers;
void ContinueShutdown(bool aSuccess);
MediaPromiseHolder<ShutdownPromise> mMediaSourceShutdownPromise;
#ifdef MOZ_FMP4
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
#endif

View File

@ -96,39 +96,23 @@ private:
nsAutoTArray<nsRefPtr<SourceBufferDecoder>,2> mDecoders;
};
nsRefPtr<ShutdownPromise>
void
TrackBuffer::Shutdown()
{
MOZ_ASSERT(mShutdownPromise.IsEmpty());
nsRefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
RefPtr<MediaTaskQueue> queue = mTaskQueue;
// Finish any decoder initialization, which may add to mInitializedDecoders.
// Shutdown waits for any pending events, which may require the monitor,
// so we must not hold the monitor during this call.
mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
mTaskQueue->BeginShutdown();
mTaskQueue->AwaitShutdownAndIdle();
mTaskQueue = nullptr;
queue->BeginShutdown()
->Then(mParentDecoder->GetReader()->GetTaskQueue(), __func__, this,
&TrackBuffer::ContinueShutdown, &TrackBuffer::ContinueShutdown);
return p;
}
void
TrackBuffer::ContinueShutdown(bool aSuccess)
{
MOZ_ASSERT(aSuccess);
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
if (mDecoders.Length()) {
mDecoders[0]->GetReader()->Shutdown()
->Then(mParentDecoder->GetReader()->GetTaskQueue(), __func__, this,
&TrackBuffer::ContinueShutdown, &TrackBuffer::ContinueShutdown);
mShutdownDecoders.AppendElement(mDecoders[0]);
mDecoders.RemoveElementAt(0);
return;
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
mDecoders[i]->GetReader()->Shutdown();
}
mInitializedDecoders.Clear();
mParentDecoder = nullptr;
mShutdownPromise.Resolve(true, __func__);
}
bool
@ -449,13 +433,12 @@ TrackBuffer::BreakCycles()
{
MOZ_ASSERT(NS_IsMainThread());
for (uint32_t i = 0; i < mShutdownDecoders.Length(); ++i) {
mShutdownDecoders[i]->BreakCycles();
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
mDecoders[i]->BreakCycles();
}
mShutdownDecoders.Clear();
mDecoders.Clear();
// These are cleared in Shutdown()
MOZ_ASSERT(!mDecoders.Length());
MOZ_ASSERT(mInitializedDecoders.IsEmpty());
MOZ_ASSERT(!mParentDecoder);
}

View File

@ -8,7 +8,6 @@
#define MOZILLA_TRACKBUFFER_H_
#include "SourceBufferDecoder.h"
#include "MediaPromise.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/mozalloc.h"
@ -34,7 +33,7 @@ public:
TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
nsRefPtr<ShutdownPromise> Shutdown();
void Shutdown();
// Append data to the current decoder. Also responsible for calling
// NotifyDataArrived on the decoder to keep buffered range computation up
@ -132,11 +131,6 @@ private:
// mParentDecoder's monitor.
nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
// During shutdown, we move decoders from mDecoders to mShutdownDecoders after
// invoking Shutdown. This is all so that we can avoid destroying the decoders
// off-main-thread. :-(
nsTArray<nsRefPtr<SourceBufferDecoder>> mShutdownDecoders;
// Contains only the initialized decoders managed by this TrackBuffer.
// Access protected by mParentDecoder's monitor.
nsTArray<nsRefPtr<SourceBufferDecoder>> mInitializedDecoders;
@ -159,9 +153,6 @@ private:
// Set when the first decoder used by this TrackBuffer is initialized.
// Protected by mParentDecoder's monitor.
MediaInfo mInfo;
void ContinueShutdown(bool aSuccess);
MediaPromiseHolder<ShutdownPromise> mShutdownPromise;
};
} // namespace mozilla

View File

@ -8,7 +8,6 @@ MOCHITEST_MANIFESTS += ['test/mochitest.ini']
EXPORTS += [
'AsyncEventRunner.h',
'MediaSourceDecoder.h',
'MediaSourceReader.h',
]
EXPORTS.mozilla.dom += [

View File

@ -344,11 +344,11 @@ MediaCodecReader::ReleaseMediaResources()
ReleaseCriticalResources();
}
nsRefPtr<ShutdownPromise>
void
MediaCodecReader::Shutdown()
{
ReleaseResources();
return MediaDecoderReader::Shutdown();
MediaDecoderReader::Shutdown();
}
void

View File

@ -68,7 +68,7 @@ public:
// Destroys the decoding state. The reader cannot be made usable again.
// This is different from ReleaseMediaResources() as Shutdown() is
// irreversible, whereas ReleaseMediaResources() is reversible.
virtual nsRefPtr<ShutdownPromise> Shutdown();
virtual void Shutdown();
// Used to retrieve some special information that can only be retrieved after
// all contents have been continuously parsed. (ex. total duration of some

View File

@ -175,20 +175,17 @@ void MediaOmxReader::ReleaseDecoder()
mOmxDecoder.clear();
}
nsRefPtr<ShutdownPromise>
MediaOmxReader::Shutdown()
void MediaOmxReader::Shutdown()
{
nsCOMPtr<nsIRunnable> cancelEvent =
NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData);
NS_DispatchToMainThread(cancelEvent);
nsRefPtr<ShutdownPromise> p = MediaDecoderReader::Shutdown();
MediaDecoderReader::Shutdown();
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &MediaOmxReader::ReleaseDecoder);
NS_DispatchToMainThread(event);
return p;
}
bool MediaOmxReader::IsWaitingMediaResources()

View File

@ -104,7 +104,7 @@ public:
virtual void SetIdle() MOZ_OVERRIDE;
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
virtual void Shutdown() MOZ_OVERRIDE;
bool IsShutdown() {
MutexAutoLock lock(mMutex);

View File

@ -218,8 +218,7 @@ WebMReader::~WebMReader()
MOZ_COUNT_DTOR(WebMReader);
}
nsRefPtr<ShutdownPromise>
WebMReader::Shutdown()
void WebMReader::Shutdown()
{
#if defined(MOZ_PDM_VPX)
if (mVideoTaskQueue) {
@ -233,7 +232,7 @@ WebMReader::Shutdown()
mVideoDecoder = nullptr;
}
return MediaDecoderReader::Shutdown();
MediaDecoderReader::Shutdown();
}
nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor)

View File

@ -133,7 +133,7 @@ protected:
~WebMReader();
public:
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
virtual void Shutdown() MOZ_OVERRIDE;
virtual nsresult Init(MediaDecoderReader* aCloneDonor);
virtual nsresult ResetDecode();
virtual bool DecodeAudioData();