Backout 12744c5b688d, edefcb820429 to investigate Android C1 permaorange.
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 03 Nov 2011 09:24:02 +0100
changeset 80305 c8b43b9b0398071a7fd7c19b762c51c71c925caa
parent 80304 ab06f7315bd77f45ea924acd86b66fb9e55d9687
child 80306 3025c93444a637de1409aec1f132a12e9318dda1
push id506
push userclegnitto@mozilla.com
push dateWed, 09 Nov 2011 02:03:18 +0000
treeherdermozilla-aurora@63587fc7bb93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone10.0a1
backs out12744c5b688ddc3087a5f056a1e09c82d70ddb02
Backout 12744c5b688d, edefcb820429 to investigate Android C1 permaorange.
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/nsBuiltinDecoderStateMachine.h
content/media/test/crashtests/691096-1.html
content/media/test/crashtests/crashtests.list
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -160,186 +160,38 @@ public:
     mDecoder->MetadataLoaded(mChannels, mRate);
     return NS_OK;
   }
 
   const PRUint32 mChannels;
   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 
 {
 public:
   ShutdownThreadEvent(nsIThread* aThread) : mThread(aThread) {}
   ~ShutdownThreadEvent() {}
   NS_IMETHOD Run() {
     mThread->Shutdown();
     mThread = nsnull;
     return NS_OK;
   }
 private:
   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,
                                                            nsBuiltinDecoderReader* aReader,
                                                            bool aRealTime) :
   mDecoder(aDecoder),
   mState(DECODER_STATE_DECODING_METADATA),
   mCbCrSize(0),
   mPlayDuration(0),
   mStartTime(-1),
@@ -364,36 +216,52 @@ nsBuiltinDecoderStateMachine::nsBuiltinD
   mRunAgain(false),
   mDispatchedRunEvent(false),
   mDecodeThreadWaiting(false),
   mRealTime(aRealTime),
   mEventManager(aDecoder)
 {
   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)
     mRealTime = false;
 
   mBufferingWait = mRealTime ? 0 : BUFFERING_WAIT;
   mLowDataThresholdUsecs = mRealTime ? 0 : LOW_DATA_THRESHOLD_USECS;
 }
 
 nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   MOZ_COUNT_DTOR(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<nsIRunnable> event = new ShutdownThreadEvent(gStateMachineThread);
+    NS_RELEASE(gStateMachineThread);
+    gStateMachineThread = nsnull;
+    NS_DispatchToMainThread(event);
+  }
 }
 
 bool nsBuiltinDecoderStateMachine::HasFutureAudio() const {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   NS_ASSERTION(HasAudio(), "Should only call HasFutureAudio() when we have audio");
   // We've got audio ready to play if:
   // 1. We've not completed playback of audio, and
   // 2. we either have more than the threshold of decoded audio available, or
@@ -1183,17 +1051,16 @@ void nsBuiltinDecoderStateMachine::StopD
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   mStopDecodeThread = true;
   mDecoder->GetReentrantMonitor().NotifyAll();
   if (mDecodeThread) {
     LOG(PR_LOG_DEBUG, ("%p Shutdown decode thread", mDecoder.get()));
     {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       mDecodeThread->Shutdown();
-      StateMachineTracker::Instance().NoteDecodeThreadDestroyed();
     }
     mDecodeThread = nsnull;
     mDecodeThreadIdle = false;
   }
 }
 
 void nsBuiltinDecoderStateMachine::StopAudioThread()
 {
@@ -1210,58 +1077,33 @@ void nsBuiltinDecoderStateMachine::StopA
   }
 }
 
 nsresult
 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<nsIRunnable> 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;
 }
 
 nsresult
 nsBuiltinDecoderStateMachine::StartAudioThread()
 {
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
@@ -2127,17 +1969,17 @@ void nsBuiltinDecoderStateMachine::Timeo
 }
 
 nsresult nsBuiltinDecoderStateMachine::ScheduleStateMachine() {
   return ScheduleStateMachine(0);
 }
 
 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) {
     return NS_ERROR_FAILURE;
   }
   aUsecs = PR_MAX(aUsecs, 0);
 
   TimeStamp timeout = TimeStamp::Now() + UsecsToDuration(aUsecs);
@@ -2162,43 +2004,31 @@ nsresult nsBuiltinDecoderStateMachine::S
       // We're currently running this state machine on the state machine
       // thread. Signal it to run again once it finishes its current cycle.
       mRunAgain = true;
       return NS_OK;
     } else if (!mDispatchedRunEvent) {
       // 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,
     // so just exit; it's going to run real soon.
     return NS_OK;
   }
 
   mTimeout = timeout;
 
   nsresult res;
   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,
                                      this,
                                      ms,
                                      nsITimer::TYPE_ONE_SHOT);
   return res;
 }
-
-bool nsBuiltinDecoderStateMachine::OnStateMachineThread() const
-{
-    return IsCurrentThread(GetStateMachineThread());
-}
- 
-nsIThread* nsBuiltinDecoderStateMachine::GetStateMachineThread()
-{
-  return StateMachineTracker::Instance().GetGlobalStateMachineThread();
-}
-
-
--- a/content/media/nsBuiltinDecoderStateMachine.h
+++ b/content/media/nsBuiltinDecoderStateMachine.h
@@ -200,17 +200,19 @@ public:
   }
 
   // Functions used by assertions to ensure we're calling things
   // on the appropriate threads.
   bool OnAudioThread() const {
     return IsCurrentThread(mAudioThread);
   }
 
-  bool OnStateMachineThread() const;
+  bool OnStateMachineThread() const {
+    return IsCurrentThread(GetStateMachineThread());
+  }
  
   nsresult GetBuffered(nsTimeRanges* aBuffered);
 
   PRInt64 VideoQueueMemoryInUse() {
     if (mReader) {
       return mReader->VideoQueueMemoryInUse();
     }
     return 0;
deleted file mode 100644
--- a/content/media/test/crashtests/691096-1.html
+++ /dev/null
@@ -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>
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -3,9 +3,8 @@ load 466607-1.html
 load 466945-1.html
 load 468763-1.html
 load 474744-1.html
 HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file?
 load 493915-1.html
 skip-if(Android) load 495794-1.html
 load 492286-1.xhtml
 load 576612-1.html
-load 691096-1.html