Commit c2548b8f authored by tkent@chromium.org's avatar tkent@chromium.org

Oilpan: WebAudio: Apply the weak HashMap pattern to remove an entry from...

Oilpan: WebAudio: Apply the weak HashMap pattern to remove an entry from AudioContext::m_dirtyAudioSummingJunctions.

r178238, which made AudioSummingJunction::m_context a weak member, didn't
work. If the AudioContext and an AudioSummingJunction object become unreachable
togeter, AudioSummingJunction::m_context is not cleared and their destuction
order is not deterministic. We must not touch weak members in destructors.

With this CL, we register all of AudioSummingJunction objects to AudioContext,
and applies the weak HashMap pattern to clear m_dirtyAudioSummingJunctions.

BUG=392788

Review URL: https://codereview.chromium.org/393133003

git-svn-id: svn://svn.chromium.org/blink/trunk@178521 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent ed435746
...@@ -191,6 +191,11 @@ void AudioContext::initialize() ...@@ -191,6 +191,11 @@ void AudioContext::initialize()
void AudioContext::clear() void AudioContext::clear()
{ {
#if ENABLE(OILPAN)
// We need to run disposers before destructing m_contextGraphMutex.
m_liveAudioSummingJunctions.clear();
#endif
// We have to release our reference to the destination node before the context will ever be deleted since the destination node holds a reference to the context. // We have to release our reference to the destination node before the context will ever be deleted since the destination node holds a reference to the context.
if (m_destinationNode) if (m_destinationNode)
m_destinationNode.clear(); m_destinationNode.clear();
...@@ -756,6 +761,20 @@ void AudioContext::handleDeferredAudioNodeTasks() ...@@ -756,6 +761,20 @@ void AudioContext::handleDeferredAudioNodeTasks()
m_deferredFinishDerefList.clear(); m_deferredFinishDerefList.clear();
} }
#if ENABLE(OILPAN)
void AudioContext::registerLiveAudioSummingJunction(AudioSummingJunction& junction)
{
ASSERT(isMainThread());
m_liveAudioSummingJunctions.add(&junction, adoptPtr(new AudioSummingJunctionDisposer(junction)));
}
AudioContext::AudioSummingJunctionDisposer::~AudioSummingJunctionDisposer()
{
ASSERT(isMainThread());
m_junction.context()->removeMarkedSummingJunction(&m_junction);
}
#endif
void AudioContext::markForDeletion(AudioNode* node) void AudioContext::markForDeletion(AudioNode* node)
{ {
ASSERT(isGraphOwner()); ASSERT(isGraphOwner());
...@@ -965,6 +984,9 @@ void AudioContext::trace(Visitor* visitor) ...@@ -965,6 +984,9 @@ void AudioContext::trace(Visitor* visitor)
visitor->trace(m_renderTarget); visitor->trace(m_renderTarget);
visitor->trace(m_destinationNode); visitor->trace(m_destinationNode);
visitor->trace(m_listener); visitor->trace(m_listener);
#if ENABLE(OILPAN)
visitor->trace(m_liveAudioSummingJunctions);
#endif
EventTargetWithInlineData::trace(visitor); EventTargetWithInlineData::trace(visitor);
} }
......
...@@ -140,6 +140,9 @@ public: ...@@ -140,6 +140,9 @@ public:
// Called periodically at the end of each render quantum to dereference finished source nodes. // Called periodically at the end of each render quantum to dereference finished source nodes.
void derefFinishedSourceNodes(); void derefFinishedSourceNodes();
#if ENABLE(OILPAN)
void registerLiveAudioSummingJunction(AudioSummingJunction&);
#endif
// We schedule deletion of all marked nodes at the end of each realtime render quantum. // We schedule deletion of all marked nodes at the end of each realtime render quantum.
void markForDeletion(AudioNode*); void markForDeletion(AudioNode*);
void deleteMarkedNodes(); void deleteMarkedNodes();
...@@ -276,6 +279,21 @@ private: ...@@ -276,6 +279,21 @@ private:
// before deref(). // before deref().
Vector<RefPtr<AudioNode> > m_referencedNodes; Vector<RefPtr<AudioNode> > m_referencedNodes;
#if ENABLE(OILPAN)
class AudioSummingJunctionDisposer {
public:
explicit AudioSummingJunctionDisposer(AudioSummingJunction& junction) : m_junction(junction) { }
~AudioSummingJunctionDisposer();
private:
AudioSummingJunction& m_junction;
};
// The purpose of m_liveAudioSummingJunctions is to remove a dying
// AudioSummingJunction from m_dirtySummingJunctions. However we put all of
// AudioSummingJunction objects to m_liveAudioSummingJunctions to avoid
// concurrent access to m_liveAudioSummingJunctions.
HeapHashMap<WeakMember<AudioSummingJunction>, OwnPtr<AudioSummingJunctionDisposer> > m_liveAudioSummingJunctions;
#endif
// Accumulate nodes which need to be deleted here. // Accumulate nodes which need to be deleted here.
// This is copied to m_nodesToDelete at the end of a render cycle in handlePostRenderTasks(), where we're assured of a stable graph // This is copied to m_nodesToDelete at the end of a render cycle in handlePostRenderTasks(), where we're assured of a stable graph
// state which will have no references to any of the nodes in m_nodesToDelete once the context lock is released // state which will have no references to any of the nodes in m_nodesToDelete once the context lock is released
......
...@@ -38,14 +38,18 @@ AudioSummingJunction::AudioSummingJunction(AudioContext* context) ...@@ -38,14 +38,18 @@ AudioSummingJunction::AudioSummingJunction(AudioContext* context)
: m_context(context) : m_context(context)
, m_renderingStateNeedUpdating(false) , m_renderingStateNeedUpdating(false)
{ {
ASSERT(context);
#if ENABLE(OILPAN)
m_context->registerLiveAudioSummingJunction(*this);
#endif
} }
AudioSummingJunction::~AudioSummingJunction() AudioSummingJunction::~AudioSummingJunction()
{ {
// Oilpan: m_context is null if AudioContext and this object die #if !ENABLE(OILPAN)
// together. It's non-null if this object dies before AudioContext.
if (m_renderingStateNeedUpdating && m_context.get()) if (m_renderingStateNeedUpdating && m_context.get())
m_context->removeMarkedSummingJunction(this); m_context->removeMarkedSummingJunction(this);
#endif
} }
void AudioSummingJunction::trace(Visitor* visitor) void AudioSummingJunction::trace(Visitor* visitor)
......
...@@ -63,16 +63,7 @@ public: ...@@ -63,16 +63,7 @@ public:
protected: protected:
explicit AudioSummingJunction(AudioContext*); explicit AudioSummingJunction(AudioContext*);
// Oilpan: m_context can be null only in the destructor because RefPtrWillBeMember<AudioContext> m_context;
// AudioSummingJunction objects are owned by AudioNodes, and AudioNodes have
// strong references to AudioContext.
// Theorically this should be a strong reference and AudioContext::
// m_dirtySummingJunctions should be HeapHashSet<WeakMember<
// AudioSummingJunction>>, but we can't do them because the map is modified
// in an audio rendering thread, which has no GC support. We need to remove
// an AudioSummingJunction from AudioContext in ~AudioSummingJunction, and
// this WeakMember<> makes it possible though we can't do it with Member<>.
RefPtrWillBeWeakMember<AudioContext> m_context;
// m_outputs contains the AudioNodeOutputs representing current connections which are not disabled. // m_outputs contains the AudioNodeOutputs representing current connections which are not disabled.
// The rendering code should never use this directly, but instead uses m_renderingOutputs. // The rendering code should never use this directly, but instead uses m_renderingOutputs.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment