зеркало из https://github.com/mozilla/pjs.git
Backout 12744c5b688d, edefcb820429 to investigate Android C1 permaorange.
This commit is contained in:
Родитель
5db8d36c67
Коммит
2aebf9cdf8
|
@ -165,6 +165,13 @@ public:
|
||||||
const PRUint32 mRate;
|
const PRUint32 mRate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PRUint32 gStateMachineCount = 0;
|
||||||
|
static nsIThread* gStateMachineThread = 0;
|
||||||
|
|
||||||
|
nsIThread* nsBuiltinDecoderStateMachine::GetStateMachineThread() {
|
||||||
|
return gStateMachineThread;
|
||||||
|
}
|
||||||
|
|
||||||
// Shuts down a thread asynchronously.
|
// Shuts down a thread asynchronously.
|
||||||
class ShutdownThreadEvent : public nsRunnable
|
class ShutdownThreadEvent : public nsRunnable
|
||||||
{
|
{
|
||||||
|
@ -180,161 +187,6 @@ private:
|
||||||
nsCOMPtr<nsIThread> mThread;
|
nsCOMPtr<nsIThread> 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<nsIRunnable> 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,
|
nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder,
|
||||||
nsBuiltinDecoderReader* aReader,
|
nsBuiltinDecoderReader* aReader,
|
||||||
bool aRealTime) :
|
bool aRealTime) :
|
||||||
|
@ -369,8 +221,14 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
|
MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||||
|
if (gStateMachineCount == 0) {
|
||||||
StateMachineTracker::Instance().EnsureGlobalStateMachine();
|
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.
|
// only enable realtime mode when "media.realtime_decoder.enabled" is true.
|
||||||
if (Preferences::GetBool("media.realtime_decoder.enabled", false) == false)
|
if (Preferences::GetBool("media.realtime_decoder.enabled", false) == false)
|
||||||
|
@ -387,8 +245,18 @@ nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
|
||||||
if (mTimer)
|
if (mTimer)
|
||||||
mTimer->Cancel();
|
mTimer->Cancel();
|
||||||
mTimer = nsnull;
|
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<nsIRunnable> event = new ShutdownThreadEvent(gStateMachineThread);
|
||||||
|
NS_RELEASE(gStateMachineThread);
|
||||||
|
gStateMachineThread = nsnull;
|
||||||
|
NS_DispatchToMainThread(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsBuiltinDecoderStateMachine::HasFutureAudio() const {
|
bool nsBuiltinDecoderStateMachine::HasFutureAudio() const {
|
||||||
|
@ -1188,7 +1056,6 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
|
||||||
{
|
{
|
||||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||||
mDecodeThread->Shutdown();
|
mDecodeThread->Shutdown();
|
||||||
StateMachineTracker::Instance().NoteDecodeThreadDestroyed();
|
|
||||||
}
|
}
|
||||||
mDecodeThread = nsnull;
|
mDecodeThread = nsnull;
|
||||||
mDecodeThreadIdle = false;
|
mDecodeThreadIdle = false;
|
||||||
|
@ -1215,48 +1082,23 @@ nsBuiltinDecoderStateMachine::StartDecodeThread()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
||||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||||
PRUint32 count = 0;
|
|
||||||
bool created = false;
|
|
||||||
{
|
|
||||||
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
|
|
||||||
count = StateMachineTracker::Instance().GetDecodeThreadCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
mStopDecodeThread = false;
|
mStopDecodeThread = false;
|
||||||
if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED)
|
if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED)
|
||||||
return NS_OK;
|
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) {
|
if (!mDecodeThread) {
|
||||||
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
|
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
|
||||||
nsnull,
|
nsnull,
|
||||||
MEDIA_THREAD_STACK_SIZE);
|
MEDIA_THREAD_STACK_SIZE);
|
||||||
if (NS_FAILED(rv)) {
|
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;
|
mState = DECODER_STATE_SHUTDOWN;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
created = true;
|
|
||||||
}
|
}
|
||||||
nsCOMPtr<nsIRunnable> event =
|
nsCOMPtr<nsIRunnable> event =
|
||||||
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
|
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
|
||||||
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||||
mDecodeThreadIdle = false;
|
mDecodeThreadIdle = false;
|
||||||
|
|
||||||
if (created) {
|
|
||||||
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
|
|
||||||
StateMachineTracker::Instance().NoteDecodeThreadCreated();
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2132,7 +1974,7 @@ nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine() {
|
||||||
|
|
||||||
nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) {
|
nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) {
|
||||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||||
NS_ABORT_IF_FALSE(GetStateMachineThread(),
|
NS_ABORT_IF_FALSE(gStateMachineThread,
|
||||||
"Must have a state machine thread to schedule");
|
"Must have a state machine thread to schedule");
|
||||||
|
|
||||||
if (mState == DECODER_STATE_SHUTDOWN) {
|
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
|
// We're not currently running this state machine on the state machine
|
||||||
// thread. Dispatch an event to run one cycle of the state machine.
|
// thread. Dispatch an event to run one cycle of the state machine.
|
||||||
mDispatchedRunEvent = true;
|
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
|
// We're not currently running this state machine on the state machine
|
||||||
// thread, but something has already dispatched an event to run it again,
|
// thread, but something has already dispatched an event to run it again,
|
||||||
|
@ -2181,7 +2023,7 @@ nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) {
|
||||||
if (!mTimer) {
|
if (!mTimer) {
|
||||||
mTimer = do_CreateInstance("@mozilla.org/timer;1", &res);
|
mTimer = do_CreateInstance("@mozilla.org/timer;1", &res);
|
||||||
if (NS_FAILED(res)) return res;
|
if (NS_FAILED(res)) return res;
|
||||||
mTimer->SetTarget(GetStateMachineThread());
|
mTimer->SetTarget(gStateMachineThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = mTimer->InitWithFuncCallback(::TimeoutExpired,
|
res = mTimer->InitWithFuncCallback(::TimeoutExpired,
|
||||||
|
@ -2190,15 +2032,3 @@ nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine(PRInt64 aUsecs) {
|
||||||
nsITimer::TYPE_ONE_SHOT);
|
nsITimer::TYPE_ONE_SHOT);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsBuiltinDecoderStateMachine::OnStateMachineThread() const
|
|
||||||
{
|
|
||||||
return IsCurrentThread(GetStateMachineThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIThread* nsBuiltinDecoderStateMachine::GetStateMachineThread()
|
|
||||||
{
|
|
||||||
return StateMachineTracker::Instance().GetGlobalStateMachineThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,9 @@ public:
|
||||||
return IsCurrentThread(mAudioThread);
|
return IsCurrentThread(mAudioThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnStateMachineThread() const;
|
bool OnStateMachineThread() const {
|
||||||
|
return IsCurrentThread(GetStateMachineThread());
|
||||||
|
}
|
||||||
|
|
||||||
nsresult GetBuffered(nsTimeRanges* aBuffered);
|
nsresult GetBuffered(nsTimeRanges* aBuffered);
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html class="reftest-wait">
|
|
||||||
<head>
|
|
||||||
<script>
|
|
||||||
var ITERATIONS = 200;
|
|
||||||
|
|
||||||
function stoptest ()
|
|
||||||
{
|
|
||||||
document.documentElement.removeAttribute("class");
|
|
||||||
}
|
|
||||||
|
|
||||||
function boom()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < ITERATIONS; ++i) {
|
|
||||||
a = document.createElementNS("http://www.w3.org/1999/xhtml", "audio");
|
|
||||||
a.addEventListener("loadedmetadata", stoptest);
|
|
||||||
a.setAttributeNS(null, "autoplay", "");
|
|
||||||
a.setAttributeNS(null, "src", "sound.ogg");
|
|
||||||
}
|
|
||||||
setTimeout(stoptest, 250);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body onload="boom();"></body>
|
|
||||||
</html>
|
|
|
@ -8,4 +8,3 @@ load 493915-1.html
|
||||||
skip-if(Android) load 495794-1.html
|
skip-if(Android) load 495794-1.html
|
||||||
load 492286-1.xhtml
|
load 492286-1.xhtml
|
||||||
load 576612-1.html
|
load 576612-1.html
|
||||||
load 691096-1.html
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче