Bug 860958 - Make it safe to stop source nodes when shutting down the AudioContext in case the nodes die right away; r=roc
☠☠ backed out by 0ad4e00d7945 ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 30 Apr 2013 16:01:39 -0400
changeset 141393 cace8e8e855692a7d2648de7e9a99cd323e813bc
parent 141392 3225e8f5aa5f38ac23ec4b65ea9fa1de174160f5
child 141394 0ad4e00d794536b440bd8cd3bfdf448755a558bf
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs860958
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 860958 - Make it safe to stop source nodes when shutting down the AudioContext in case the nodes die right away; r=roc
content/media/webaudio/AudioContext.cpp
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -292,43 +292,57 @@ AudioContext::DestinationStream() const
 }
 
 double
 AudioContext::CurrentTime() const
 {
   return MediaTimeToSeconds(Destination()->Stream()->GetCurrentTime());
 }
 
+template <class T>
 static PLDHashOperator
-StopAudioBufferSourceNode(nsPtrHashKey<AudioBufferSourceNode>* aEntry, void* aData)
+GetHashtableEntry(nsPtrHashKey<T>* aEntry, void* aData)
 {
-  ErrorResult rv;
-  aEntry->GetKey()->Stop(0.0, rv);
+  nsTArray<T*>* array = static_cast<nsTArray<T*>*>(aData);
+  array->AppendElement(aEntry->GetKey());
   return PL_DHASH_NEXT;
 }
 
-static PLDHashOperator
-StopScriptProcessorNode(nsPtrHashKey<ScriptProcessorNode>* aEntry, void* aData)
+template <class T>
+static void
+GetHashtableElements(nsTHashtable<nsPtrHashKey<T> >& aHashtable, nsTArray<T*>& aArray)
 {
-  aEntry->GetKey()->Stop();
-  return PL_DHASH_NEXT;
+  aHashtable.EnumerateEntries(&GetHashtableEntry<T>, &aArray);
 }
 
 void
 AudioContext::Shutdown()
 {
   Suspend();
   mDecoder.Shutdown();
 
   // Stop all audio buffer source nodes, to make sure that they release
   // their self-references.
-  mAudioBufferSourceNodes.EnumerateEntries(StopAudioBufferSourceNode, nullptr);
+  // We first gather an array of the nodes and then call Stop on each one,
+  // since Stop may delete the object and therefore trigger a re-entrant
+  // hashtable call to remove the pointer from the hashtable, which is
+  // not safe.
+  nsTArray<AudioBufferSourceNode*> sourceNodes;
+  GetHashtableElements(mAudioBufferSourceNodes, sourceNodes);
+  for (uint32_t i = 0; i < sourceNodes.Length(); ++i) {
+    ErrorResult rv;
+    sourceNodes[i]->Stop(0.0, rv);
+  }
   // Stop all script processor nodes, to make sure that they release
   // their self-references.
-  mScriptProcessorNodes.EnumerateEntries(StopScriptProcessorNode, nullptr);
+  nsTArray<ScriptProcessorNode*> spNodes;
+  GetHashtableElements(mScriptProcessorNodes, spNodes);
+  for (uint32_t i = 0; i < spNodes.Length(); ++i) {
+    spNodes[i]->Stop();
+  }
 }
 
 void
 AudioContext::Suspend()
 {
   MediaStream* ds = DestinationStream();
   if (ds) {
     ds->ChangeExplicitBlockerCount(1);