Changeset 246685 in webkit
- Timestamp:
- Jun 21, 2019 11:01:13 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r246683 r246685 1 2019-06-21 Youenn Fablet <youenn@apple.com> 2 3 Safari crashes after ~2028 OfflineAudioContext objects are created (they never get garbage collected, consuming a thread each) 4 https://bugs.webkit.org/show_bug.cgi?id=198964 5 <rdar://problem/51891520> 6 7 Reviewed by Jer Noble. 8 9 * webaudio/offlineaudiocontext-gc-expected.txt: Added. 10 * webaudio/offlineaudiocontext-gc.html: Added. 11 1 12 2019-06-21 Truitt Savell <tsavell@apple.com> 2 13 -
trunk/Source/WebCore/ChangeLog
r246683 r246685 1 2019-06-21 Youenn Fablet <youenn@apple.com> 2 3 Safari crashes after ~2028 OfflineAudioContext objects are created (they never get garbage collected, consuming a thread each) 4 https://bugs.webkit.org/show_bug.cgi?id=198964 5 <rdar://problem/51891520> 6 7 Reviewed by Jer Noble. 8 9 Move from setPendingActivity/unsetPendingActivity to an 10 m_pendingActivity member which is easier to manage. 11 12 Keep setting a pending activity for AudioContext at construction time 13 but do not do that for Offline contexts. 14 Instead, set the pending activity when startRendering is called. 15 Unset the pending activity when the rendering activity is finished. 16 17 Make m_audioDecoder a unique pointer so that it can lazily be initialized. 18 This removes the burden of creating an audio decoder thread for each context. 19 20 Test: webaudio/offlineaudiocontext-gc.html 21 22 * Modules/webaudio/AudioContext.cpp: 23 (WebCore::AudioContext::AudioContext): 24 (WebCore::AudioContext::constructCommon): 25 (WebCore::AudioContext::clear): 26 (WebCore::AudioContext::decodeAudioData): 27 (WebCore::AudioContext::startRendering): 28 (WebCore::AudioContext::finishedRendering): 29 (WebCore::AudioContext::dispatchEvent): 30 (WebCore::AudioContext::clearPendingActivity): 31 (WebCore::AudioContext::makePendingActivity): 32 To keep it consistent with setPendingActivity/unsetPendingActivity, we 33 explicitly ref/unref the AudioContext. We should try to remove this ref/unref. 34 * Modules/webaudio/AudioContext.h: 35 * Modules/webaudio/OfflineAudioDestinationNode.cpp: 36 (WebCore::OfflineAudioDestinationNode::startRendering): 37 1 38 2019-06-21 Truitt Savell <tsavell@apple.com> 2 39 -
trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp
r246437 r246685 100 100 #include <wtf/Ref.h> 101 101 #include <wtf/RefCounted.h> 102 #include <wtf/Scope.h> 102 103 #include <wtf/text/WTFString.h> 103 104 … … 142 143 , m_eventQueue(std::make_unique<GenericEventQueue>(*this)) 143 144 { 145 // According to spec AudioContext must die only after page navigate. 146 // Lets mark it as ActiveDOMObject with pending activity and unmark it in clear method. 147 makePendingActivity(); 148 144 149 constructCommon(); 145 150 … … 173 178 void AudioContext::constructCommon() 174 179 { 175 // According to spec AudioContext must die only after page navigate.176 // Lets mark it as ActiveDOMObject with pending activity and unmark it in clear method.177 setPendingActivity(*this);178 179 180 FFTFrame::initialize(); 180 181 … … 243 244 void AudioContext::clear() 244 245 { 246 Ref<AudioContext> protectedThis(*this); 247 245 248 // 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. 246 249 if (m_destinationNode) … … 254 257 } while (m_nodesToDelete.size()); 255 258 256 // It was set in constructCommon. 257 unsetPendingActivity(*this); 259 clearPendingActivity(); 258 260 } 259 261 … … 430 432 void AudioContext::decodeAudioData(Ref<ArrayBuffer>&& audioData, RefPtr<AudioBufferCallback>&& successCallback, RefPtr<AudioBufferCallback>&& errorCallback) 431 433 { 432 m_audioDecoder.decodeAsync(WTFMove(audioData), sampleRate(), WTFMove(successCallback), WTFMove(errorCallback)); 434 if (!m_audioDecoder) 435 m_audioDecoder = std::make_unique<AsyncAudioDecoder>(); 436 m_audioDecoder->decodeAsync(WTFMove(audioData), sampleRate(), WTFMove(successCallback), WTFMove(errorCallback)); 433 437 } 434 438 … … 1142 1146 return; 1143 1147 1148 makePendingActivity(); 1149 1144 1150 destination()->startRendering(); 1145 1151 setState(State::Running); … … 1177 1183 } 1178 1184 1179 void AudioContext::fireCompletionEvent() 1180 { 1185 void AudioContext::finishedRendering(bool didRendering) 1186 { 1187 ASSERT(isOfflineContext()); 1181 1188 ASSERT(isMainThread()); 1182 1189 if (!isMainThread()) 1183 1190 return; 1184 1191 1185 ALWAYS_LOG(LOGIDENTIFIER); 1186 1192 auto clearPendingActivityIfExitEarly = WTF::makeScopeExit([this] { 1193 clearPendingActivity(); 1194 }); 1195 1196 1197 ALWAYS_LOG(LOGIDENTIFIER); 1198 1199 if (!didRendering) 1200 return; 1201 1187 1202 AudioBuffer* renderedBuffer = m_renderTarget.get(); 1188 1203 setState(State::Closed); … … 1193 1208 1194 1209 // Avoid firing the event if the document has already gone away. 1195 if (!m_isStopScheduled) { 1196 // Call the offline rendering completion event listener. 1197 m_eventQueue->enqueueEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); 1198 } 1210 if (m_isStopScheduled) 1211 return; 1212 1213 clearPendingActivityIfExitEarly.release(); 1214 m_eventQueue->enqueueEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); 1215 } 1216 1217 void AudioContext::dispatchEvent(Event& event) 1218 { 1219 EventTarget::dispatchEvent(event); 1220 if (event.eventInterface() == OfflineAudioCompletionEventInterfaceType) 1221 clearPendingActivity(); 1199 1222 } 1200 1223 … … 1348 1371 } 1349 1372 1373 void AudioContext::clearPendingActivity() 1374 { 1375 if (!m_pendingActivity) 1376 return; 1377 m_pendingActivity = nullptr; 1378 // FIXME: Remove this specific deref() and ref() call in makePendingActivity(). 1379 deref(); 1380 } 1381 1382 void AudioContext::makePendingActivity() 1383 { 1384 if (m_pendingActivity) 1385 return; 1386 m_pendingActivity = ActiveDOMObject::makePendingActivity(*this); 1387 ref(); 1388 } 1389 1350 1390 #if !RELEASE_LOG_DISABLED 1351 1391 WTFLogChannel& AudioContext::logChannel() const -
trunk/Source/WebCore/Modules/webaudio/AudioContext.h
r246490 r246685 260 260 261 261 void startRendering(); 262 void fi reCompletionEvent();263 262 void finishedRendering(bool didRendering); 263 264 264 static unsigned s_hardwareContextCount; 265 265 … … 298 298 299 299 static bool isSampleRateRangeGood(float sampleRate); 300 300 void clearPendingActivity(); 301 void makePendingActivity(); 302 301 303 private: 302 304 void constructCommon(); … … 321 323 // EventTarget 322 324 ScriptExecutionContext* scriptExecutionContext() const final; 325 void dispatchEvent(Event&) final; 323 326 324 327 // MediaProducer … … 430 433 Thread* volatile m_graphOwnerThread { nullptr }; // if the lock is held then this is the thread which owns it, otherwise == nullptr. 431 434 432 AsyncAudioDecoderm_audioDecoder;435 std::unique_ptr<AsyncAudioDecoder> m_audioDecoder; 433 436 434 437 // This is considering 32 is large enough for multiple channels audio. … … 442 445 443 446 State m_state { State::Suspended }; 447 RefPtr<PendingActivity<AudioContext>> m_pendingActivity; 444 448 }; 445 449 -
trunk/Source/WebCore/Modules/webaudio/OfflineAudioDestinationNode.cpp
r244145 r246685 95 95 bool didRender = offlineRender(); 96 96 callOnMainThread([this, didRender] { 97 if (didRender) 98 context().fireCompletionEvent(); 97 context().finishedRendering(didRender); 99 98 deref(); 100 99 });
Note: See TracChangeset
for help on using the changeset viewer.