Index: third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp |
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..470e213e130701906f6d739ea83ce2185840a87f |
--- /dev/null |
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp |
@@ -0,0 +1,262 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "modules/webaudio/AudioWorkletThread.h" |
+ |
+#include "bindings/core/v8/Microtask.h" |
+#include "bindings/core/v8/ScriptSourceCode.h" |
+#include "bindings/core/v8/V8Binding.h" |
+#include "bindings/core/v8/V8GCController.h" |
+#include "bindings/core/v8/V8Initializer.h" |
+#include "bindings/core/v8/V8PerIsolateData.h" |
+#include "bindings/core/v8/WorkerOrWorkletScriptController.h" |
+#include "core/events/MessageEvent.h" |
+#include "modules/webaudio/AudioDestinationNode.h" |
+#include "modules/webaudio/AudioWorkletGlobalScope.h" |
+#include "modules/webaudio/AudioWorkletThreadStartupData.h" |
+#include "platform/Logging.h" |
+#include "platform/Task.h" |
+#include "platform/ThreadSafeFunctional.h" |
+#include "platform/WebThreadSupportingGC.h" |
+#include "public/platform/Platform.h" |
+#include "public/platform/WebThread.h" |
+ |
+namespace blink { |
+ |
+namespace { |
+ |
+ class WorkletMicrotaskRunner : public WebThread::TaskObserver { |
+ |
+ public: |
+ explicit WorkletMicrotaskRunner(AudioWorkletThread* audioWorkletThread) |
+ : m_audioWorkletThread(audioWorkletThread) |
+ { |
+ } |
+ |
+ void willProcessTask() final {} |
+ |
+ void didProcessTask() final |
+ { |
+ Microtask::performCheckpoint(m_audioWorkletThread->isolate()); |
+ } |
+ |
+ private: |
+ // Thread owns the microtask runner; reference remains |
+ // valid for the lifetime of this object. |
+ AudioWorkletThread* m_audioWorkletThread; |
+ }; |
+ |
+ void destroyThread(WebThreadSupportingGC* thread) |
+ { |
+ ASSERT(isMainThread()); |
+ // The destructor for |thread| will block until all tasks have completed. |
+ // This guarantees that shutdown will finish before the thread is destroyed. |
+ delete thread; |
+ } |
+ |
+ class AudioWorkletSharedState { |
+ public: |
+ static AudioWorkletSharedState& instance() |
+ { |
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(AudioWorkletSharedState, audioWorkletSharedState, (new AudioWorkletSharedState())); |
+ return audioWorkletSharedState; |
+ } |
+ |
+ WebThreadSupportingGC* audioWorkletThread() |
+ { |
+ MutexLocker lock(m_mutex); |
+ if (!m_thread && isMainThread()) { |
+ ASSERT(!m_workerCount); |
+ WebThread* platformThread = Platform::current()->createThread("offline audio renderer"); |
+ m_thread = WebThreadSupportingGC::createForThread(platformThread); |
+ } |
+ return m_thread.get(); |
+ } |
+ |
+ void initializeBackingThread() |
+ { |
+ MutexLocker lock(m_mutex); |
+ ASSERT(m_thread->isCurrentThread()); |
+ |
+ // ++m_workerCount; |
+ // if (m_workerCount > 1) |
+ // return; |
+ |
+ m_thread->initialize(); |
+ |
+ // Initialize the isolate at the same time. |
+ ASSERT(!m_isolate); |
+ m_isolate = V8PerIsolateData::initialize(); |
+ V8Initializer::initializeWorker(m_isolate); |
+ |
+ // OwnPtr<V8IsolateInterruptor> interruptor = adoptPtr(new V8IsolateInterruptor(m_isolate)); |
+ // ThreadState::current()->addInterruptor(interruptor.release()); |
+ // ThreadState::current()->registerTraceDOMWrappers(m_isolate, V8GCController::traceDOMWrappers); |
+ } |
+ |
+ void shutdownBackingThread() |
+ { |
+ MutexLocker lock(m_mutex); |
+ ASSERT(m_thread->isCurrentThread()); |
+ |
+ // ASSERT(m_workerCount > 0); |
+ // --m_workerCount; |
+ |
+ if (m_workerCount == 0) { |
+ m_thread->shutdown(); |
+ Platform::current()->mainThread()->getWebTaskRunner()->postTask( |
+ BLINK_FROM_HERE, threadSafeBind(destroyThread, AllowCrossThreadAccess(m_thread.leakPtr()))); |
+ } |
+ } |
+ |
+ v8::Isolate* isolate() |
+ { |
+ MutexLocker lock(m_mutex); |
+ ASSERT(m_thread->isCurrentThread()); |
+ ASSERT(m_isolate); |
+ // It is safe to use the existing isolate even if TerminateExecution() has been |
+ // called on it, without calling CancelTerminateExecution(). |
+ return m_isolate; |
+ } |
+ |
+ void willDestroyIsolate() |
+ { |
+ MutexLocker lock(m_mutex); |
+ ASSERT(m_thread->isCurrentThread()); |
+ if (m_workerCount == 1) |
+ V8PerIsolateData::willBeDestroyed(m_isolate); |
+ } |
+ |
+ void destroyIsolate() |
+ { |
+ MutexLocker lock(m_mutex); |
+ if (!m_thread) { |
+ ASSERT(m_workerCount == 0); |
+ V8PerIsolateData::destroy(m_isolate); |
+ m_isolate = nullptr; |
+ } |
+ } |
+ |
+ void terminateV8Execution() |
+ { |
+ MutexLocker lock(m_mutex); |
+ ASSERT(isMainThread()); |
+ if (m_workerCount > 1) |
+ return; |
+ m_isolate->TerminateExecution(); |
+ } |
+ |
+ private: |
+ AudioWorkletSharedState() {} |
+ ~AudioWorkletSharedState() {} |
+ Mutex m_mutex; |
+ OwnPtr<WebThreadSupportingGC> m_thread; |
+ int m_workerCount = 0; |
+ v8::Isolate* m_isolate = nullptr; |
+ }; |
+ |
+} // namespace |
+ |
+PassRefPtr<AudioWorkletThread> AudioWorkletThread::create(AudioDestinationHandler& audioDestinationHandler) |
+{ |
+ ASSERT(isMainThread()); |
+ return adoptRef(new AudioWorkletThread(audioDestinationHandler)); |
+} |
+ |
+AudioWorkletThread::AudioWorkletThread(AudioDestinationHandler& audioDestinationHandler) |
+ : m_destinationHandler(audioDestinationHandler) |
+{ |
+} |
+ |
+AudioWorkletThread::~AudioWorkletThread() |
+{ |
+} |
+ |
+bool AudioWorkletThread::isCurrentThread() |
+{ |
+ return audioRenderThread().isCurrentThread(); |
+} |
+ |
+void AudioWorkletThread::initialize(LocalFrame* frame, PassOwnPtr<AudioWorkletThreadStartupData> startupData) |
+{ |
+ ASSERT(isMainThread()); |
+ |
+ if (m_initialized) |
+ return; |
+ |
+ m_initialized = true; |
+ audioRenderThread().postTask(BLINK_FROM_HERE, threadSafeBind(&AudioWorkletThread::initializeInternal, AllowCrossThreadAccess(this), frame, passed(std::move(startupData)))); |
hongchan
2016/05/23 21:48:54
In file included from ../../third_party/WebKit/Sou
|
+} |
+ |
+void AudioWorkletThread::initializeInternal(LocalFrame* frame, PassOwnPtr<AudioWorkletThreadStartupData> startupData) |
+{ |
+ ASSERT(audioRenderThread().isCurrentThread()); |
+ { |
+ MutexLocker lock(m_threadStateMutex); |
+ m_microtaskRunner = adoptPtr(new WorkletMicrotaskRunner(this)); |
+ AudioWorkletSharedState::instance().initializeBackingThread(); |
+ audioRenderThread().addTaskObserver(m_microtaskRunner.get()); |
+ m_isolate = AudioWorkletSharedState::instance().isolate(); |
+ m_audioWorkletGlobalScope = AudioWorkletGlobalScope::create(frame, startupData->m_url, startupData->m_userAgent, startupData->m_securityOrigin.release(), m_isolate); |
+ } |
+} |
+ |
+void AudioWorkletThread::shutdown() |
+{ |
+ ASSERT(isMainThread()); |
+ m_audioWorkletGlobalScope->scriptController()->willScheduleExecutionTermination(); |
+ AudioWorkletSharedState::instance().terminateV8Execution(); |
+ audioRenderThread().postTask(BLINK_FROM_HERE, threadSafeBind(&AudioWorkletThread::shutdownInternal, AllowCrossThreadAccess(this))); |
+} |
+ |
+void AudioWorkletThread::evaluate(const String& sourceCode, const KURL& scriptURL) |
+{ |
+ ASSERT(isMainThread()); |
+ audioRenderThread().postTask(BLINK_FROM_HERE, threadSafeBind(&AudioWorkletThread::evaluateInternal, AllowCrossThreadAccess(this), sourceCode.isolatedCopy(), scriptURL.copy())); |
+} |
+ |
+void AudioWorkletThread::evaluateInternal(const String& sourceCode, const KURL& scriptURL) |
+{ |
+ ASSERT(audioRenderThread().isCurrentThread()); |
+ m_audioWorkletGlobalScope->scriptController()->evaluate(ScriptSourceCode(sourceCode, scriptURL)); |
+} |
+ |
+WebThreadSupportingGC& AudioWorkletThread::audioRenderThread() |
+{ |
+ return *AudioWorkletSharedState::instance().audioWorkletThread(); |
+} |
+ |
+void AudioWorkletThread::shutdownInternal() |
+{ |
+ ASSERT(isCurrentThread()); |
+ { |
+ MutexLocker lock(m_threadStateMutex); |
+ if (m_shutdown) |
+ return; |
+ m_shutdown = true; |
+ } |
+ m_audioWorkletGlobalScope->dispose(); |
+ audioRenderThread().postTask(BLINK_FROM_HERE, threadSafeBind(&AudioWorkletThread::performShutdownTask, AllowCrossThreadAccess(this))); |
+} |
+ |
+void AudioWorkletThread::performShutdownTask() |
+{ |
+// The below assignment will destroy the context, which will in turn notify messaging proxy. |
+// We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. |
+// If Oilpan is enabled, we detach of the context/global scope, with the final heap cleanup below sweeping it out. |
+#if !ENABLE(OILPAN) |
+ ASSERT(m_audioWorkletGlobalScope->hasOneRef()); |
+#endif |
+ m_audioWorkletGlobalScope->notifyContextDestroyed(); |
+ m_audioWorkletGlobalScope = nullptr; |
+ AudioWorkletSharedState::instance().willDestroyIsolate(); |
+ AudioWorkletSharedState::instance().shutdownBackingThread(); |
+ AudioWorkletSharedState::instance().terminateV8Execution(); |
+ m_isolate = nullptr; |
+ m_microtaskRunner = nullptr; |
+ // Notify the proxy that the WorkerGlobalScope has been disposed of. |
+ // This can free this thread object, hence it must not be touched afterwards. |
+ m_destinationHandler.stopRendering(); |
+} |
+} // namespace blink |