diff --git a/content/media/nsBuiltinDecoderStateMachine.cpp b/content/media/nsBuiltinDecoderStateMachine.cpp index 456407093023..3e0cec3710a4 100644 --- a/content/media/nsBuiltinDecoderStateMachine.cpp +++ b/content/media/nsBuiltinDecoderStateMachine.cpp @@ -165,6 +165,13 @@ public: const PRUint32 mRate; }; +static PRUint32 gStateMachineCount = 0; +static nsIThread* gStateMachineThread = 0; + +nsIThread* nsBuiltinDecoderStateMachine::GetStateMachineThread() { + return gStateMachineThread; +} + // Shuts down a thread asynchronously. class ShutdownThreadEvent : public nsRunnable { @@ -180,161 +187,6 @@ private: nsCOMPtr mThread; }; -// Owns the global state machine thread and counts of -// state machine and decoder threads. There should -// only be one instance of this class. -class StateMachineTracker -{ -private: - StateMachineTracker() : - mMonitor("media.statemachinetracker"), - mStateMachineCount(0), - mDecodeThreadCount(0), - mStateMachineThread(nsnull) - { - MOZ_COUNT_CTOR(StateMachineTracker); - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - } - - ~StateMachineTracker() - { - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - MOZ_COUNT_DTOR(StateMachineTracker); - } - -public: - // Access singleton instance. This is initially called on the main - // thread in the nsBuiltinDecoderStateMachine constructor resulting - // in the global object being created lazily. Non-main thread - // access always occurs after this and uses the monitor to - // safely access the decode thread counts. - static StateMachineTracker& Instance(); - - // Instantiate the global state machine thread if required. - // Call on main thread only. - void EnsureGlobalStateMachine(); - - // Destroy global state machine thread if required. - // Call on main thread only. - void CleanupGlobalStateMachine(); - - // Return the global state machine thread. Call from any thread. - nsIThread* GetGlobalStateMachineThread() - { - ReentrantMonitorAutoEnter mon(mMonitor); - NS_ASSERTION(mStateMachineThread, "Should have non-null state machine thread!"); - return mStateMachineThread; - } - - // Maximum number of active decode threads allowed. When more - // than this number are active the thread creation will fail. - static const PRUint32 MAX_DECODE_THREADS = 50; - - // Returns the number of active decode threads. - // Call on any thread. Holds the internal monitor so don't - // call with any other monitor held to avoid deadlock. - PRUint32 GetDecodeThreadCount(); - - // Keep track of the fact that a decode thread was created. - // Call on any thread. Holds the internal monitor so don't - // call with any other monitor held to avoid deadlock. - void NoteDecodeThreadCreated(); - - // Keep track of the fact that a decode thread was destroyed. - // Call on any thread. Holds the internal monitor so don't - // call with any other monitor held to avoid deadlock. - void NoteDecodeThreadDestroyed(); - -private: - // Holds global instance of StateMachineTracker. - // Writable on main thread only. - static StateMachineTracker* mInstance; - - // Reentrant monitor that must be obtained to access - // the decode thread count member and methods. - ReentrantMonitor mMonitor; - - // Number of instances of nsBuiltinDecoderStateMachine - // that are currently instantiated. Access on the - // main thread only. - PRUint32 mStateMachineCount; - - // Number of instances of decoder threads that are - // currently instantiated. Access only with the - // mMonitor lock held. Can be used from any thread. - PRUint32 mDecodeThreadCount; - - // Global state machine thread. Write on the main thread - // only, read from the decoder threads. Synchronized via - // the mMonitor. - nsIThread* mStateMachineThread; -}; - -StateMachineTracker* StateMachineTracker::mInstance = nsnull; - -StateMachineTracker& StateMachineTracker::Instance() -{ - if (!mInstance) { - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - mInstance = new StateMachineTracker(); - } - return *mInstance; -} - -void StateMachineTracker::EnsureGlobalStateMachine() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - ReentrantMonitorAutoEnter mon(mMonitor); - if (mStateMachineCount == 0) { - NS_ASSERTION(!mStateMachineThread, "Should have null state machine thread!"); - nsresult res = NS_NewThread(&mStateMachineThread, - nsnull); - NS_ABORT_IF_FALSE(NS_SUCCEEDED(res), "Can't create media state machine thread"); - } - mStateMachineCount++; -} - -void StateMachineTracker::CleanupGlobalStateMachine() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ABORT_IF_FALSE(mStateMachineCount > 0, - "State machine ref count must be > 0"); - mStateMachineCount--; - if (mStateMachineCount == 0) { - LOG(PR_LOG_DEBUG, ("Destroying media state machine thread")); - { - ReentrantMonitorAutoEnter mon(mMonitor); - nsCOMPtr event = new ShutdownThreadEvent(mStateMachineThread); - NS_RELEASE(mStateMachineThread); - mStateMachineThread = nsnull; - NS_DispatchToMainThread(event); - - NS_ASSERTION(mDecodeThreadCount == 0, "Decode thread count must be zero."); - mInstance = nsnull; - } - delete this; - } -} - -void StateMachineTracker::NoteDecodeThreadCreated() -{ - ReentrantMonitorAutoEnter mon(mMonitor); - ++mDecodeThreadCount; -} - -void StateMachineTracker::NoteDecodeThreadDestroyed() -{ - ReentrantMonitorAutoEnter mon(mMonitor); - --mDecodeThreadCount; -} - -PRUint32 StateMachineTracker::GetDecodeThreadCount() -{ - ReentrantMonitorAutoEnter mon(mMonitor); - return mDecodeThreadCount; -} - nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader, bool aRealTime) : @@ -369,8 +221,14 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe { MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine); NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - StateMachineTracker::Instance().EnsureGlobalStateMachine(); + if (gStateMachineCount == 0) { + NS_ASSERTION(!gStateMachineThread, "Should have null state machine thread!"); + nsresult res = NS_NewThread(&gStateMachineThread, + nsnull, + MEDIA_THREAD_STACK_SIZE); + NS_ABORT_IF_FALSE(NS_SUCCEEDED(res), "Can't create media state machine thread"); + } + gStateMachineCount++; // only enable realtime mode when "media.realtime_decoder.enabled" is true. if (Preferences::GetBool("media.realtime_decoder.enabled", false) == false) @@ -387,8 +245,18 @@ nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine() if (mTimer) mTimer->Cancel(); mTimer = nsnull; - - StateMachineTracker::Instance().CleanupGlobalStateMachine(); + + NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); + NS_ABORT_IF_FALSE(gStateMachineCount > 0, + "State machine ref count must be > 0"); + gStateMachineCount--; + if (gStateMachineCount == 0) { + LOG(PR_LOG_DEBUG, ("Destroying media state machine thread")); + nsCOMPtr event = new ShutdownThreadEvent(gStateMachineThread); + NS_RELEASE(gStateMachineThread); + gStateMachineThread = nsnull; + NS_DispatchToMainThread(event); + } } bool nsBuiltinDecoderStateMachine::HasFutureAudio() const { @@ -1188,7 +1056,6 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread() { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); mDecodeThread->Shutdown(); - StateMachineTracker::Instance().NoteDecodeThreadDestroyed(); } mDecodeThread = nsnull; mDecodeThreadIdle = false; @@ -1215,48 +1082,23 @@ nsBuiltinDecoderStateMachine::StartDecodeThread() { NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread."); mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); - PRUint32 count = 0; - bool created = false; - { - ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor()); - count = StateMachineTracker::Instance().GetDecodeThreadCount(); - } - mStopDecodeThread = false; if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED) return NS_OK; - if (!mDecodeThread && count > StateMachineTracker::MAX_DECODE_THREADS) { - // Have to run one iteration of the state machine loop to ensure the - // shutdown state is processed. - ScheduleStateMachine(); - mState = DECODER_STATE_SHUTDOWN; - return NS_ERROR_FAILURE; - } - if (!mDecodeThread) { nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread), nsnull, MEDIA_THREAD_STACK_SIZE); if (NS_FAILED(rv)) { - // Have to run one iteration of the state machine loop to ensure the - // shutdown state is processed. - ScheduleStateMachine(); mState = DECODER_STATE_SHUTDOWN; return rv; } - created = true; } nsCOMPtr event = NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun); mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL); mDecodeThreadIdle = false; - - if (created) { - ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor()); - StateMachineTracker::Instance().NoteDecodeThreadCreated(); - } - return NS_OK; } @@ -2132,7 +1974,7 @@ nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine() { nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) { mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); - NS_ABORT_IF_FALSE(GetStateMachineThread(), + NS_ABORT_IF_FALSE(gStateMachineThread, "Must have a state machine thread to schedule"); if (mState == DECODER_STATE_SHUTDOWN) { @@ -2167,7 +2009,7 @@ nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) { // We're not currently running this state machine on the state machine // thread. Dispatch an event to run one cycle of the state machine. mDispatchedRunEvent = true; - return GetStateMachineThread()->Dispatch(this, NS_DISPATCH_NORMAL); + return gStateMachineThread->Dispatch(this, NS_DISPATCH_NORMAL); } // We're not currently running this state machine on the state machine // thread, but something has already dispatched an event to run it again, @@ -2181,7 +2023,7 @@ nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) { if (!mTimer) { mTimer = do_CreateInstance("@mozilla.org/timer;1", &res); if (NS_FAILED(res)) return res; - mTimer->SetTarget(GetStateMachineThread()); + mTimer->SetTarget(gStateMachineThread); } res = mTimer->InitWithFuncCallback(::TimeoutExpired, @@ -2190,15 +2032,3 @@ nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) { nsITimer::TYPE_ONE_SHOT); return res; } - -bool nsBuiltinDecoderStateMachine::OnStateMachineThread() const -{ - return IsCurrentThread(GetStateMachineThread()); -} - -nsIThread* nsBuiltinDecoderStateMachine::GetStateMachineThread() -{ - return StateMachineTracker::Instance().GetGlobalStateMachineThread(); -} - - diff --git a/content/media/nsBuiltinDecoderStateMachine.h b/content/media/nsBuiltinDecoderStateMachine.h index 4a01a99562ee..f0baada6a207 100644 --- a/content/media/nsBuiltinDecoderStateMachine.h +++ b/content/media/nsBuiltinDecoderStateMachine.h @@ -205,7 +205,9 @@ public: return IsCurrentThread(mAudioThread); } - bool OnStateMachineThread() const; + bool OnStateMachineThread() const { + return IsCurrentThread(GetStateMachineThread()); + } nsresult GetBuffered(nsTimeRanges* aBuffered); diff --git a/content/media/test/crashtests/691096-1.html b/content/media/test/crashtests/691096-1.html deleted file mode 100644 index fd6dbbb5c723..000000000000 --- a/content/media/test/crashtests/691096-1.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - diff --git a/content/media/test/crashtests/crashtests.list b/content/media/test/crashtests/crashtests.list index 42ff46579fef..dfcfdc34046e 100644 --- a/content/media/test/crashtests/crashtests.list +++ b/content/media/test/crashtests/crashtests.list @@ -8,4 +8,3 @@ load 493915-1.html skip-if(Android) load 495794-1.html load 492286-1.xhtml load 576612-1.html -load 691096-1.html