Changeset 92658 in webkit


Ignore:
Timestamp:
Aug 8, 2011 5:49:04 PM (13 years ago)
Author:
crogers@google.com
Message:

Fix thread-safety of AudioNode deletion
https://bugs.webkit.org/show_bug.cgi?id=65888

Reviewed by Kenneth Russell

No new tests - JavaScript API is not affected.

  • webaudio/AudioContext.cpp:

(WebCore::AudioContext::AudioContext):
(WebCore::AudioContext::constructCommon):
(WebCore::AudioContext::~AudioContext):
(WebCore::AudioContext::uninitialize):
(WebCore::AudioContext::handlePostRenderTasks):
(WebCore::AudioContext::scheduleNodeDeletion):
(WebCore::AudioContext::deleteMarkedNodesDispatch):
(WebCore::AudioContext::deleteMarkedNodes):

  • webaudio/AudioContext.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r92657 r92658  
     12011-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
    1212011-08-08  Chris Marrin  <cmarrin@apple.com>
    222
  • trunk/Source/WebCore/webaudio/AudioContext.cpp

    r92068 r92658  
    121121    , m_document(document)
    122122    , m_destinationNode(0)
     123    , m_isDeletionScheduled(false)
    123124    , m_connectionCount(0)
    124125    , m_audioThread(0)
     
    161162void AudioContext::constructCommon()
    162163{
    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    
    167164    FFTFrame::initialize();
    168165   
     
    176173#if DEBUG_AUDIONODE_REFERENCES
    177174    printf("%p: AudioContext::~AudioContext()\n", this);
    178 #endif   
     175#endif
    179176    // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
    180177    ASSERT(!m_nodesToDelete.size());
     
    228225        // Get rid of the sources which may still be playing.
    229226        derefUnfinishedSourceNodes();
    230        
     227
     228        deleteMarkedNodes();
     229
    231230        // Because the AudioBuffers are garbage collected, we can't delete them here.
    232231        // Instead, at least release the potentially large amount of allocated memory for the audio data.
     
    567566        derefFinishedSourceNodes();
    568567
    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();
    571571
    572572        // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
     
    597597}
    598598
     599void 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
     617void 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
    599628void AudioContext::deleteMarkedNodes()
    600629{
    601     ASSERT(isGraphOwner() || isAudioThreadFinished());
    602 
     630    ASSERT(isMainThread());
     631
     632    AutoLocker locker(this);
     633   
    603634    // Note: deleting an AudioNode can cause m_nodesToDelete to grow.
    604     size_t nodesDeleted = 0;
    605635    while (size_t n = m_nodesToDelete.size()) {
    606636        AudioNode* node = m_nodesToDelete[n - 1];
     
    619649        // Finally, delete it.
    620650        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;
    626654}
    627655
  • trunk/Source/WebCore/webaudio/AudioContext.h

    r92068 r92658  
    3939#include <wtf/RefCounted.h>
    4040#include <wtf/RefPtr.h>
     41#include <wtf/ThreadSafeRefCounted.h>
    4142#include <wtf/Threading.h>
    4243#include <wtf/Vector.h>
     
    6869// For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism.
    6970
    70 class AudioContext : public ActiveDOMObject, public RefCounted<AudioContext>, public EventTarget {
     71class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted<AudioContext>, public EventTarget {
    7172public:
    7273    // Create an AudioContext for rendering to the audio hardware.
     
    137138    void derefFinishedSourceNodes();
    138139
    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.
    140141    void markForDeletion(AudioNode*);
    141142    void deleteMarkedNodes();
    142 
     143   
    143144    // Keeps track of the number of connections made.
    144145    void incrementConnectionCount()
     
    210211    DEFINE_ATTRIBUTE_EVENT_LISTENER(complete);
    211212
    212     // Reconcile ref/deref which are defined both in AudioNode and 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;
    215216
    216217    void startRendering();
     
    226227    void lazyInitialize();
    227228    void uninitialize();
     229
     230    void scheduleNodeDeletion();
     231    static void deleteMarkedNodesDispatch(void* userData);
    228232   
    229233    bool m_isInitialized;
     
    258262    Vector<AudioNode*> m_referencedNodes;
    259263
    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).
    261266    Vector<AudioNode*> m_nodesToDelete;
     267    bool m_isDeletionScheduled;
    262268
    263269    // Only accessed when the graph lock is held.
Note: See TracChangeset for help on using the changeset viewer.