Changeset 92658 in webkit
- Timestamp:
- Aug 8, 2011 5:49:04 PM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r92657 r92658 1 2011-08-08 Chris Rogers <crogers@google.com> 2 3 Fix thread-safety of AudioNode deletion 4 https://bugs.webkit.org/show_bug.cgi?id=65888 5 6 Reviewed by Kenneth Russell 7 8 No new tests - JavaScript API is not affected. 9 10 * webaudio/AudioContext.cpp: 11 (WebCore::AudioContext::AudioContext): 12 (WebCore::AudioContext::constructCommon): 13 (WebCore::AudioContext::~AudioContext): 14 (WebCore::AudioContext::uninitialize): 15 (WebCore::AudioContext::handlePostRenderTasks): 16 (WebCore::AudioContext::scheduleNodeDeletion): 17 (WebCore::AudioContext::deleteMarkedNodesDispatch): 18 (WebCore::AudioContext::deleteMarkedNodes): 19 * webaudio/AudioContext.h: 20 1 21 2011-08-08 Chris Marrin <cmarrin@apple.com> 2 22 -
trunk/Source/WebCore/webaudio/AudioContext.cpp
r92068 r92658 121 121 , m_document(document) 122 122 , m_destinationNode(0) 123 , m_isDeletionScheduled(false) 123 124 , m_connectionCount(0) 124 125 , m_audioThread(0) … … 161 162 void AudioContext::constructCommon() 162 163 { 163 // Note: because adoptRef() won't be called until we leave this constructor, but code in this constructor needs to reference this context,164 // relax the check.165 relaxAdoptionRequirement();166 167 164 FFTFrame::initialize(); 168 165 … … 176 173 #if DEBUG_AUDIONODE_REFERENCES 177 174 printf("%p: AudioContext::~AudioContext()\n", this); 178 #endif 175 #endif 179 176 // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around. 180 177 ASSERT(!m_nodesToDelete.size()); … … 228 225 // Get rid of the sources which may still be playing. 229 226 derefUnfinishedSourceNodes(); 230 227 228 deleteMarkedNodes(); 229 231 230 // Because the AudioBuffers are garbage collected, we can't delete them here. 232 231 // Instead, at least release the potentially large amount of allocated memory for the audio data. … … 567 566 derefFinishedSourceNodes(); 568 567 569 // Finally actually delete. 570 deleteMarkedNodes(); 568 // Don't delete in the real-time thread. Let the main thread do it. 569 // Ref-counted objects held by certain AudioNodes may not be thread-safe. 570 scheduleNodeDeletion(); 571 571 572 572 // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs. … … 597 597 } 598 598 599 void AudioContext::scheduleNodeDeletion() 600 { 601 bool isGood = m_isInitialized && isGraphOwner(); 602 ASSERT(isGood); 603 if (!isGood) 604 return; 605 606 // Make sure to call deleteMarkedNodes() on main thread. 607 if (m_nodesToDelete.size() && !m_isDeletionScheduled) { 608 m_isDeletionScheduled = true; 609 610 // Don't let ourself get deleted before the callback. 611 // See matching deref() in deleteMarkedNodesDispatch(). 612 ref(); 613 callOnMainThread(deleteMarkedNodesDispatch, this); 614 } 615 } 616 617 void AudioContext::deleteMarkedNodesDispatch(void* userData) 618 { 619 AudioContext* context = reinterpret_cast<AudioContext*>(userData); 620 ASSERT(context); 621 if (!context) 622 return; 623 624 context->deleteMarkedNodes(); 625 context->deref(); 626 } 627 599 628 void AudioContext::deleteMarkedNodes() 600 629 { 601 ASSERT(isGraphOwner() || isAudioThreadFinished()); 602 630 ASSERT(isMainThread()); 631 632 AutoLocker locker(this); 633 603 634 // Note: deleting an AudioNode can cause m_nodesToDelete to grow. 604 size_t nodesDeleted = 0;605 635 while (size_t n = m_nodesToDelete.size()) { 606 636 AudioNode* node = m_nodesToDelete[n - 1]; … … 619 649 // Finally, delete it. 620 650 delete node; 621 622 // Don't delete too many nodes per render quantum since we don't want to do too much work in the realtime audio thread. 623 if (++nodesDeleted > MaxNodesToDeletePerQuantum) 624 break; 625 } 651 } 652 653 m_isDeletionScheduled = false; 626 654 } 627 655 -
trunk/Source/WebCore/webaudio/AudioContext.h
r92068 r92658 39 39 #include <wtf/RefCounted.h> 40 40 #include <wtf/RefPtr.h> 41 #include <wtf/ThreadSafeRefCounted.h> 41 42 #include <wtf/Threading.h> 42 43 #include <wtf/Vector.h> … … 68 69 // For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism. 69 70 70 class AudioContext : public ActiveDOMObject, public RefCounted<AudioContext>, public EventTarget {71 class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted<AudioContext>, public EventTarget { 71 72 public: 72 73 // Create an AudioContext for rendering to the audio hardware. … … 137 138 void derefFinishedSourceNodes(); 138 139 139 // We reap all marked nodes at the end of each realtime render quantum in deleteMarkedNodes().140 // We schedule deletion of all marked nodes at the end of each realtime render quantum. 140 141 void markForDeletion(AudioNode*); 141 142 void deleteMarkedNodes(); 142 143 143 144 // Keeps track of the number of connections made. 144 145 void incrementConnectionCount() … … 210 211 DEFINE_ATTRIBUTE_EVENT_LISTENER(complete); 211 212 212 // Reconcile ref/deref which are defined both in AudioNodeand EventTarget.213 using RefCounted<AudioContext>::ref;214 using RefCounted<AudioContext>::deref;213 // Reconcile ref/deref which are defined both in ThreadSafeRefCounted and EventTarget. 214 using ThreadSafeRefCounted<AudioContext>::ref; 215 using ThreadSafeRefCounted<AudioContext>::deref; 215 216 216 217 void startRendering(); … … 226 227 void lazyInitialize(); 227 228 void uninitialize(); 229 230 void scheduleNodeDeletion(); 231 static void deleteMarkedNodesDispatch(void* userData); 228 232 229 233 bool m_isInitialized; … … 258 262 Vector<AudioNode*> m_referencedNodes; 259 263 260 // Accumulate nodes which need to be deleted at the end of a render cycle (in realtime thread) here. 264 // Accumulate nodes which need to be deleted here. 265 // They will be scheduled for deletion (on the main thread) at the end of a render cycle (in realtime thread). 261 266 Vector<AudioNode*> m_nodesToDelete; 267 bool m_isDeletionScheduled; 262 268 263 269 // Only accessed when the graph lock is held.
Note: See TracChangeset
for help on using the changeset viewer.