Changeset 268897 in webkit
- Timestamp:
- Oct 22, 2020, 3:25:44 PM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 19 edited
- 1 copied
-
ChangeLog (modified) (1 diff)
-
Modules/webaudio/AudioWorkletMessagingProxy.cpp (modified) (1 diff)
-
Modules/webaudio/AudioWorkletThread.cpp (modified) (3 diffs)
-
Modules/webaudio/AudioWorkletThread.h (modified) (3 diffs)
-
Sources.txt (modified) (1 diff)
-
WebCore.xcodeproj/project.pbxproj (modified) (2 diffs)
-
page/MemoryRelease.cpp (modified) (1 diff)
-
page/cocoa/ResourceUsageThreadCocoa.mm (modified) (1 diff)
-
page/linux/ResourceUsageThreadLinux.cpp (modified) (1 diff)
-
workers/DedicatedWorkerThread.cpp (modified) (1 diff)
-
workers/WorkerGlobalScope.h (modified) (1 diff)
-
workers/WorkerOrWorkletGlobalScope.h (modified) (1 diff)
-
workers/WorkerOrWorkletThread.cpp (copied) (copied from trunk/Source/WebCore/workers/WorkerThread.cpp ) (14 diffs)
-
workers/WorkerOrWorkletThread.h (modified) (3 diffs)
-
workers/WorkerThread.cpp (modified) (5 diffs)
-
workers/WorkerThread.h (modified) (6 diffs)
-
workers/service/context/ServiceWorkerThread.cpp (modified) (5 diffs)
-
worklets/Worklet.cpp (modified) (2 diffs)
-
worklets/Worklet.h (modified) (2 diffs)
-
worklets/WorkletParameters.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r268895 r268897 1 2020-10-22 Chris Dumez <cdumez@apple.com> 2 3 Share more code between WorkerThread and AudioWorkletThread 4 https://bugs.webkit.org/show_bug.cgi?id=218051 5 6 Reviewed by Geoffrey Garen. 7 8 Share more code between WorkerThread and AudioWorkletThread by moving more logic 9 to the WorkerOrWorklet base class. 10 11 No new tests, no web-facing behavior change. 12 13 * Modules/webaudio/AudioWorkletMessagingProxy.cpp: 14 (WebCore::generateWorkletParameters): 15 * Modules/webaudio/AudioWorkletThread.cpp: 16 (WebCore::AudioWorkletThread::AudioWorkletThread): 17 (WebCore::AudioWorkletThread::createGlobalScope): 18 (WebCore::AudioWorkletThread::workerLoaderProxy): 19 (WebCore::AudioWorkletThread::createThread): 20 (WebCore::AudioWorkletThread::globalScope const): 21 * Modules/webaudio/AudioWorkletThread.h: 22 * Sources.txt: 23 * WebCore.xcodeproj/project.pbxproj: 24 * page/MemoryRelease.cpp: 25 (WebCore::releaseMemory): 26 * page/cocoa/ResourceUsageThreadCocoa.mm: 27 (WebCore::ResourceUsageThread::platformCollectCPUData): 28 * page/linux/ResourceUsageThreadLinux.cpp: 29 (WebCore::ResourceUsageThread::platformCollectCPUData): 30 * workers/DedicatedWorkerThread.cpp: 31 (WebCore::DedicatedWorkerThread::runEventLoop): 32 * workers/WorkerGlobalScope.h: 33 * workers/WorkerOrWorkletGlobalScope.h: 34 (WebCore::WorkerOrWorkletGlobalScope::suspend): 35 (WebCore::WorkerOrWorkletGlobalScope::resume): 36 * workers/WorkerOrWorkletThread.cpp: Copied from Source/WebCore/workers/WorkerThread.cpp. 37 (WebCore::WorkerOrWorkletThread::workerOrWorkletThreadsLock): 38 (WebCore::WorkerOrWorkletThread::WorkerOrWorkletThread): 39 (WebCore::WorkerOrWorkletThread::~WorkerOrWorkletThread): 40 (WebCore::WorkerOrWorkletThread::startRunningDebuggerTasks): 41 (WebCore::WorkerOrWorkletThread::stopRunningDebuggerTasks): 42 (WebCore::WorkerOrWorkletThread::runEventLoop): 43 (WebCore::WorkerOrWorkletThread::workerOrWorkletThread): 44 (WebCore::WorkerOrWorkletThread::start): 45 (WebCore::WorkerOrWorkletThread::stop): 46 (WebCore::WorkerOrWorkletThread::suspend): 47 (WebCore::WorkerOrWorkletThread::resume): 48 (WebCore::WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads): 49 * workers/WorkerOrWorkletThread.h: 50 (WebCore::WorkerOrWorkletThread::thread const): 51 (WebCore::WorkerOrWorkletThread::globalScope const): 52 (WebCore::WorkerOrWorkletThread::runLoop): 53 (WebCore::WorkerOrWorkletThread::start): 54 (WebCore::WorkerOrWorkletThread::stop): 55 (WebCore::WorkerOrWorkletThread::identifier const): 56 (WebCore::WorkerOrWorkletThread::evaluateScriptIfNecessary): 57 (WebCore::WorkerOrWorkletThread::shouldWaitForWebInspectorOnStartup const): 58 * workers/WorkerThread.cpp: 59 (WebCore::WorkerThread::workerThreadCount): 60 (WebCore::WorkerThread::WorkerThread): 61 (WebCore::WorkerThread::~WorkerThread): 62 (WebCore::WorkerThread::createThread): 63 (WebCore::WorkerThread::createGlobalScope): 64 (WebCore::WorkerThread::shouldWaitForWebInspectorOnStartup const): 65 (WebCore::WorkerThread::evaluateScriptIfNecessary): 66 (WebCore::WorkerThread::globalScope): 67 * workers/WorkerThread.h: 68 * workers/service/context/ServiceWorkerThread.cpp: 69 (WebCore::ServiceWorkerThread::queueTaskToFireFetchEvent): 70 (WebCore::ServiceWorkerThread::queueTaskToPostMessage): 71 (WebCore::ServiceWorkerThread::queueTaskToFireInstallEvent): 72 (WebCore::ServiceWorkerThread::queueTaskToFireActivateEvent): 73 (WebCore::ServiceWorkerThread::finishedEvaluatingScript): 74 * worklets/Worklet.cpp: 75 (WebCore::Worklet::Worklet): 76 * worklets/Worklet.h: 77 (WebCore::Worklet::identifier const): 78 * worklets/WorkletParameters.h: 79 (WebCore::WorkletParameters::isolatedCopy const): 80 1 81 2020-10-22 Adrian Perez de Castro <aperez@igalia.com> 2 82 -
trunk/Source/WebCore/Modules/webaudio/AudioWorkletMessagingProxy.cpp
r268103 r268897 52 52 document->url(), 53 53 jsRuntimeFlags, 54 worklet.audioContext() ? worklet.audioContext()->sampleRate() : 0.0f 54 worklet.audioContext() ? worklet.audioContext()->sampleRate() : 0.0f, 55 worklet.identifier() 55 56 }; 56 57 } -
trunk/Source/WebCore/Modules/webaudio/AudioWorkletThread.cpp
r268822 r268897 34 34 #include "AudioWorkletGlobalScope.h" 35 35 #include "AudioWorkletMessagingProxy.h" 36 #include "WorkerOrWorkletScriptController.h" 37 38 #if PLATFORM(IOS_FAMILY) 39 #include "FloatingPointEnvironment.h" 40 #endif 41 42 #if USE(GLIB) 43 #include <wtf/glib/GRefPtr.h> 44 #endif 36 #include <wtf/Threading.h> 45 37 46 38 namespace WebCore { 47 39 48 40 AudioWorkletThread::AudioWorkletThread(AudioWorkletMessagingProxy& messagingProxy, const WorkletParameters& parameters) 49 : m_messagingProxy(messagingProxy) 41 : WorkerOrWorkletThread(parameters.identifier.isolatedCopy()) 42 , m_messagingProxy(messagingProxy) 50 43 , m_parameters(parameters.isolatedCopy()) 51 44 { … … 54 47 AudioWorkletThread::~AudioWorkletThread() = default; 55 48 56 void AudioWorkletThread::start()49 Ref<WorkerOrWorkletGlobalScope> AudioWorkletThread::createGlobalScope() 57 50 { 58 auto lock = holdLock(m_threadCreationAndWorkletGlobalScopeLock); 59 60 Ref<Thread> thread = Thread::create("WebCore: AudioWorklet", [this] { 61 workletThread(); 62 }, ThreadType::Audio); 63 // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads). 64 WTF::storeStoreFence(); 65 m_thread = WTFMove(thread); 66 } 67 68 void AudioWorkletThread::stop() 69 { 70 // Mutex protection is necessary to ensure that m_workerGlobalScope isn't changed by 71 // WorkerThread::workerThread() while we're accessing it. Note also that stop() can 72 // be called before m_workerGlobalScope is fully created. 73 auto locker = tryHoldLock(m_threadCreationAndWorkletGlobalScopeLock); 74 if (!locker) { 75 // The thread is still starting, spin the runloop and try again to avoid deadlocks if the worker thread 76 // needs to interact with the main thread during startup. 77 callOnMainThread([this]() mutable { 78 stop(); 79 }); 80 return; 81 } 82 83 // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever. 84 if (m_workletGlobalScope) { 85 m_workletGlobalScope->script()->scheduleExecutionTermination(); 86 87 m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) { 88 auto& workletGlobalScope = downcast<AudioWorkletGlobalScope>(context); 89 90 workletGlobalScope.prepareForDestruction(); 91 92 // Stick a shutdown command at the end of the queue, so that we deal 93 // with all the cleanup tasks the databases post first. 94 workletGlobalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) { 95 auto& workletGlobalScope = downcast<AudioWorkletGlobalScope>(context); 96 // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed. 97 workletGlobalScope.clearScript(); 98 } }); 99 100 } }); 101 return; 102 } 103 m_runLoop.terminate(); 104 } 105 106 void AudioWorkletThread::workletThread() 107 { 108 auto protectedThis = makeRef(*this); 109 110 // Propagate the mainThread's fenv to workers. 111 #if PLATFORM(IOS_FAMILY) 112 FloatingPointEnvironment::singleton().propagateMainThreadEnvironment(); 113 #endif 114 115 #if USE(GLIB) 116 GRefPtr<GMainContext> mainContext = adoptGRef(g_main_context_new()); 117 g_main_context_push_thread_default(mainContext.get()); 118 #endif 119 120 WorkerOrWorkletScriptController* scriptController; 121 { 122 auto lock = holdLock(m_threadCreationAndWorkletGlobalScopeLock); 123 m_workletGlobalScope = AudioWorkletGlobalScope::create(*this, m_parameters); 124 125 scriptController = m_workletGlobalScope->script(); 126 127 if (m_runLoop.terminated()) { 128 // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, 129 // forbidExecution() couldn't be called from stop(). 130 scriptController->scheduleExecutionTermination(); 131 scriptController->forbidExecution(); 132 } 133 } 134 135 runEventLoop(); 136 137 #if USE(GLIB) 138 g_main_context_pop_thread_default(mainContext.get()); 139 #endif 140 141 RefPtr<Thread> protector = m_thread; 142 143 ASSERT(m_workletGlobalScope->hasOneRef()); 144 145 RefPtr<AudioWorkletGlobalScope> workletGlobalScopeToDelete; 146 { 147 // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope 148 // while WorkerThread::stop is accessing it. 149 auto lock = holdLock(m_threadCreationAndWorkletGlobalScopeLock); 150 151 // Delay the destruction of the WorkerGlobalScope context until after we've unlocked the 152 // m_threadCreationAndWorkerGlobalScopeMutex. This is needed because destructing the 153 // context will trigger the main thread to race against us to delete the WorkerThread 154 // object, and the WorkerThread object owns the mutex we need to unlock after this. 155 workletGlobalScopeToDelete = WTFMove(m_workletGlobalScope); 156 } 157 158 // The below assignment will destroy the context, which will in turn notify messaging proxy. 159 // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. 160 workletGlobalScopeToDelete = nullptr; 161 162 // Send the last WorkerThread Ref to be Deref'ed on the main thread. 163 callOnMainThread([protectedThis = WTFMove(protectedThis)] { }); 164 165 // The thread object may be already destroyed from notification now, don't try to access "this". 166 protector->detach(); 167 } 168 169 void AudioWorkletThread::runEventLoop() 170 { 171 // Does not return until terminated. 172 m_runLoop.run(m_workletGlobalScope.get()); 51 return AudioWorkletGlobalScope::create(*this, m_parameters); 173 52 } 174 53 … … 178 57 } 179 58 59 Ref<Thread> AudioWorkletThread::createThread() 60 { 61 return Thread::create("WebCore: AudioWorklet", [this] { 62 workerOrWorkletThread(); 63 }, ThreadType::Audio); 64 } 65 66 AudioWorkletGlobalScope* AudioWorkletThread::globalScope() const 67 { 68 return downcast<AudioWorkletGlobalScope>(WorkerOrWorkletThread::globalScope()); 69 } 70 180 71 } // namespace WebCore 181 72 -
trunk/Source/WebCore/Modules/webaudio/AudioWorkletThread.h
r268161 r268897 31 31 #if ENABLE(WEB_AUDIO) 32 32 #include "WorkerOrWorkletThread.h" 33 #include "WorkerRunLoop.h"34 33 #include "WorkletParameters.h" 35 #include <wtf/Forward.h>36 #include <wtf/Lock.h>37 #include <wtf/Threading.h>38 34 39 35 namespace WebCore { … … 50 46 ~AudioWorkletThread(); 51 47 52 AudioWorkletGlobalScope* globalScope() const { return m_workletGlobalScope.get(); } 53 54 void start(); 55 void stop(); 48 AudioWorkletGlobalScope* globalScope() const; 56 49 57 50 // WorkerOrWorkletThread. 58 WorkerRunLoop& runLoop() final { return m_runLoop; }59 51 WorkerLoaderProxy& workerLoaderProxy() final; 60 Thread* thread() const final { return m_thread.get(); } 52 61 53 AudioWorkletMessagingProxy& messagingProxy() { return m_messagingProxy; } 62 54 … … 64 56 AudioWorkletThread(AudioWorkletMessagingProxy&, const WorkletParameters&); 65 57 66 void runEventLoop(); 67 void workletThread(); 58 // WorkerOrWorkletThread. 59 Ref<WTF::Thread> createThread() final; 60 Ref<WorkerOrWorkletGlobalScope> createGlobalScope() final; 68 61 69 62 AudioWorkletMessagingProxy& m_messagingProxy; 70 RefPtr<Thread> m_thread;71 WorkerRunLoop m_runLoop;72 63 WorkletParameters m_parameters; 73 RefPtr<AudioWorkletGlobalScope> m_workletGlobalScope;74 Lock m_threadCreationAndWorkletGlobalScopeLock;75 64 }; 76 65 -
trunk/Source/WebCore/Sources.txt
r268886 r268897 2564 2564 workers/WorkerOrWorkletGlobalScope.cpp 2565 2565 workers/WorkerOrWorkletScriptController.cpp 2566 workers/WorkerOrWorkletThread.cpp 2566 2567 workers/WorkerRunLoop.cpp 2567 2568 workers/WorkerScriptLoader.cpp -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r268886 r268897 10755 10755 837FB3421F9EA06700D0FC31 /* ExtendableMessageEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExtendableMessageEvent.cpp; sourceTree = "<group>"; }; 10756 10756 837FB3431F9EA06800D0FC31 /* ExtendableMessageEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ExtendableMessageEvent.idl; sourceTree = "<group>"; }; 10757 837FCB4D2540E3C700934D4F /* WorkerOrWorkletThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerOrWorkletThread.cpp; sourceTree = "<group>"; }; 10757 10758 8386A96E19F61E4F00E1EC4A /* StyleBuilderGenerated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleBuilderGenerated.cpp; path = DerivedSources/WebCore/StyleBuilderGenerated.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; 10758 10759 838867341D13BA59003697D0 /* RenderObjectEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderObjectEnums.h; sourceTree = "<group>"; }; … … 18880 18881 835AA388253F55BB00746554 /* WorkerOrWorkletScriptController.cpp */, 18881 18882 839A095B2524F37600EEF328 /* WorkerOrWorkletScriptController.h */, 18883 837FCB4D2540E3C700934D4F /* WorkerOrWorkletThread.cpp */, 18882 18884 83E828B2252794CD0027E0F7 /* WorkerOrWorkletThread.h */, 18883 18885 416E29A5102FA962007FC14E /* WorkerReportingProxy.h */, -
trunk/Source/WebCore/page/MemoryRelease.cpp
r261494 r268897 148 148 if (synchronous == Synchronous::Yes) { 149 149 // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself. 150 Worker Thread::releaseFastMallocFreeMemoryInAllThreads();150 WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads(); 151 151 #if ENABLE(SCROLLING_THREAD) 152 152 ScrollingThread::dispatch(WTF::releaseFastMallocFreeMemory); -
trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm
r266388 r268897 172 172 HashMap<mach_port_t, String> knownWorkerThreads; 173 173 { 174 LockHolder lock(WorkerThread::workerThreadsMutex());175 for (auto* thread : Worker Thread::workerThreads(lock)) {174 auto locker = holdLock(WorkerOrWorkletThread::workerOrWorkletThreadsLock()); 175 for (auto* thread : WorkerOrWorkletThread::workerOrWorkletThreads()) { 176 176 // Ignore worker threads that have not been fully started yet. 177 177 if (!thread->thread()) -
trunk/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp
r266388 r268897 247 247 HashMap<pid_t, String> knownWorkerThreads; 248 248 { 249 LockHolder lock(WorkerThread::workerThreadsMutex());250 for (auto* thread : Worker Thread::workerThreads(lock)) {249 auto locker = holdLock(WorkerOrWorkletThread::workerOrWorkletThreadsLock()); 250 for (auto* thread : WorkerOrWorkletThread::workerOrWorkletThreads()) { 251 251 // Ignore worker threads that have not been fully started yet. 252 252 if (!thread->thread()) -
trunk/Source/WebCore/workers/DedicatedWorkerThread.cpp
r256012 r268897 55 55 { 56 56 // Notify the parent object of our current active state before calling the superclass to run the event loop. 57 m_workerObjectProxy.reportPendingActivity( workerGlobalScope()->hasPendingActivity());57 m_workerObjectProxy.reportPendingActivity(globalScope()->hasPendingActivity()); 58 58 WorkerThread::runEventLoop(); 59 59 } -
trunk/Source/WebCore/workers/WorkerGlobalScope.h
r268822 r268897 72 72 #if ENABLE(INDEXED_DATABASE) 73 73 IDBClient::IDBConnectionProxy* idbConnectionProxy() final; 74 void suspend() ;75 void resume() ;74 void suspend() final; 75 void resume() final; 76 76 #endif 77 77 -
trunk/Source/WebCore/workers/WorkerOrWorkletGlobalScope.h
r268868 r268897 62 62 using RefCounted::deref; 63 63 64 virtual void suspend() { } 65 virtual void resume() { } 66 64 67 protected: 65 68 WorkerOrWorkletGlobalScope(Ref<JSC::VM>&&, WorkerOrWorkletThread*); -
trunk/Source/WebCore/workers/WorkerOrWorkletThread.cpp
r268896 r268897 1 1 /* 2 * Copyright (C) 2008-20 17 Apple Inc. All Rights Reserved.2 * Copyright (C) 2008-2020 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 22 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 *25 24 */ 26 25 27 26 #include "config.h" 28 #include "WorkerThread.h" 29 30 #include "IDBConnectionProxy.h" 31 #include "ScriptSourceCode.h" 32 #include "SecurityOrigin.h" 33 #include "SocketProvider.h" 34 #include "ThreadGlobalData.h" 35 #include "WorkerGlobalScope.h" 36 #include "WorkerInspectorController.h" 37 #include <utility> 38 #include <wtf/Lock.h> 39 #include <wtf/NeverDestroyed.h> 40 #include <wtf/Noncopyable.h> 41 #include <wtf/text/WTFString.h> 27 #include "WorkerOrWorkletThread.h" 28 29 #include "WorkerOrWorkletScriptController.h" 42 30 43 31 #if PLATFORM(IOS_FAMILY) 44 32 #include "FloatingPointEnvironment.h" 45 #include "WebCoreThread.h"46 33 #endif 47 34 … … 52 39 namespace WebCore { 53 40 54 HashSet<WorkerThread*>& WorkerThread::workerThreads(const LockHolder&) 55 { 56 static NeverDestroyed<HashSet<WorkerThread*>> workerThreads; 57 return workerThreads; 58 } 59 60 Lock& WorkerThread::workerThreadsMutex() 41 Lock& WorkerOrWorkletThread::workerOrWorkletThreadsLock() 61 42 { 62 43 static Lock mutex; … … 64 45 } 65 46 66 unsigned WorkerThread::workerThreadCount() 67 { 68 LockHolder lock(workerThreadsMutex()); 69 return workerThreads(lock).size(); 70 } 71 72 WorkerParameters WorkerParameters::isolatedCopy() const 73 { 74 return { 75 scriptURL.isolatedCopy(), 76 name.isolatedCopy(), 77 identifier.isolatedCopy(), 78 userAgent.isolatedCopy(), 79 isOnline, 80 contentSecurityPolicyResponseHeaders, 81 shouldBypassMainWorldContentSecurityPolicy, 82 timeOrigin, 83 referrerPolicy, 84 requestAnimationFrameEnabled, 85 acceleratedCompositingEnabled, 86 webGLEnabled, 87 }; 88 } 89 90 struct WorkerThreadStartupData { 91 WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED; 92 public: 93 WorkerThreadStartupData(const WorkerParameters& params, const String& sourceCode, WorkerThreadStartMode, const SecurityOrigin& topOrigin); 94 95 WorkerParameters params; 96 Ref<SecurityOrigin> origin; 97 String sourceCode; 98 WorkerThreadStartMode startMode; 99 Ref<SecurityOrigin> topOrigin; 100 }; 101 102 WorkerThreadStartupData::WorkerThreadStartupData(const WorkerParameters& other, const String& sourceCode, WorkerThreadStartMode startMode, const SecurityOrigin& topOrigin) 103 : params(other.isolatedCopy()) 104 , origin(SecurityOrigin::create(other.scriptURL)->isolatedCopy()) 105 , sourceCode(sourceCode.isolatedCopy()) 106 , startMode(startMode) 107 , topOrigin(topOrigin.isolatedCopy()) 108 { 109 } 110 111 WorkerThread::WorkerThread(const WorkerParameters& params, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerDebuggerProxy& workerDebuggerProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags) 112 : m_identifier(params.identifier.isolatedCopy()) 113 , m_workerLoaderProxy(workerLoaderProxy) 114 , m_workerDebuggerProxy(workerDebuggerProxy) 115 , m_workerReportingProxy(workerReportingProxy) 116 , m_runtimeFlags(runtimeFlags) 117 , m_startupData(makeUnique<WorkerThreadStartupData>(params, sourceCode, startMode, topOrigin)) 118 #if ENABLE(INDEXED_DATABASE) 119 , m_idbConnectionProxy(connectionProxy) 120 #endif 121 , m_socketProvider(socketProvider) 122 { 123 #if !ENABLE(INDEXED_DATABASE) 124 UNUSED_PARAM(connectionProxy); 125 #endif 126 127 LockHolder lock(workerThreadsMutex()); 128 workerThreads(lock).add(this); 129 } 130 131 WorkerThread::~WorkerThread() 132 { 133 LockHolder lock(workerThreadsMutex()); 134 ASSERT(workerThreads(lock).contains(this)); 135 workerThreads(lock).remove(this); 136 } 137 138 void WorkerThread::start(WTF::Function<void(const String&)>&& evaluateCallback) 139 { 140 // Mutex protection is necessary to ensure that m_thread is initialized when the thread starts. 141 LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex); 142 143 if (m_thread) 144 return; 145 146 m_evaluateCallback = WTFMove(evaluateCallback); 147 148 Ref<Thread> thread = Thread::create(isServiceWorkerThread() ? "WebCore: Service Worker" : "WebCore: Worker", [this] { 149 workerThread(); 150 }, ThreadType::JavaScript); 151 // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads). 152 WTF::storeStoreFence(); 153 m_thread = WTFMove(thread); 154 } 155 156 void WorkerThread::workerThread() 47 HashSet<WorkerOrWorkletThread*>& WorkerOrWorkletThread::workerOrWorkletThreads() 48 { 49 ASSERT(workerOrWorkletThreadsLock().isHeld()); 50 static NeverDestroyed<HashSet<WorkerOrWorkletThread*>> workerOrWorkletThreads; 51 return workerOrWorkletThreads; 52 } 53 54 WorkerOrWorkletThread::WorkerOrWorkletThread(const String& identifier) 55 : m_identifier(identifier) 56 { 57 auto locker = holdLock(workerOrWorkletThreadsLock()); 58 workerOrWorkletThreads().add(this); 59 } 60 61 WorkerOrWorkletThread::~WorkerOrWorkletThread() 62 { 63 auto locker = holdLock(workerOrWorkletThreadsLock()); 64 ASSERT(workerOrWorkletThreads().contains(this)); 65 workerOrWorkletThreads().remove(this); 66 } 67 68 void WorkerOrWorkletThread::startRunningDebuggerTasks() 69 { 70 ASSERT(!m_pausedForDebugger); 71 m_pausedForDebugger = true; 72 73 MessageQueueWaitResult result; 74 do { 75 result = m_runLoop.runInDebuggerMode(*m_globalScope); 76 } while (result != MessageQueueTerminated && m_pausedForDebugger); 77 } 78 79 void WorkerOrWorkletThread::stopRunningDebuggerTasks() 80 { 81 m_pausedForDebugger = false; 82 } 83 84 void WorkerOrWorkletThread::runEventLoop() 85 { 86 // Does not return until terminated. 87 m_runLoop.run(m_globalScope.get()); 88 } 89 90 void WorkerOrWorkletThread::workerOrWorkletThread() 157 91 { 158 92 auto protectedThis = makeRef(*this); … … 170 104 WorkerOrWorkletScriptController* scriptController; 171 105 { 172 // Mutex protection is necessary to ensure that we don't change m_ workerGlobalScope106 // Mutex protection is necessary to ensure that we don't change m_globalScope 173 107 // while WorkerThread::stop() is accessing it. Note that WorkerThread::stop() can 174 108 // be called before we've finished creating the WorkerGlobalScope. 175 LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);176 m_ workerGlobalScope = createWorkerGlobalScope(m_startupData->params, WTFMove(m_startupData->origin), WTFMove(m_startupData->topOrigin));177 178 scriptController = m_ workerGlobalScope->script();109 auto locker = holdLock(m_threadCreationAndGlobalScopeLock); 110 m_globalScope = createGlobalScope(); 111 112 scriptController = m_globalScope->script(); 179 113 180 114 if (m_runLoop.terminated()) { … … 186 120 } 187 121 188 if ( m_startupData->startMode == WorkerThreadStartMode::WaitForInspector) {122 if (shouldWaitForWebInspectorOnStartup()) { 189 123 startRunningDebuggerTasks(); 190 124 … … 195 129 196 130 String exceptionMessage; 197 scriptController->evaluate(ScriptSourceCode(m_startupData->sourceCode, URL(m_startupData->params.scriptURL)), &exceptionMessage); 198 199 finishedEvaluatingScript(); 131 evaluateScriptIfNecessary(exceptionMessage); 200 132 201 133 callOnMainThread([evaluateCallback = WTFMove(m_evaluateCallback), message = exceptionMessage.isolatedCopy()] { … … 204 136 }); 205 137 206 // Free the startup data to cause its member variable deref's happen on the worker's thread (since207 // all ref/derefs of these objects are happening on the thread at this point). Note that208 // WorkerThread::~WorkerThread happens on a different thread where it was created.209 m_startupData = nullptr;210 211 138 runEventLoop(); 212 139 … … 217 144 RefPtr<Thread> protector = m_thread; 218 145 219 ASSERT(m_ workerGlobalScope->hasOneRef());220 221 RefPtr<Worker GlobalScope> workerGlobalScopeToDelete;146 ASSERT(m_globalScope->hasOneRef()); 147 148 RefPtr<WorkerOrWorkletGlobalScope> workerGlobalScopeToDelete; 222 149 { 223 // Mutex protection is necessary to ensure that we don't change m_ workerGlobalScope150 // Mutex protection is necessary to ensure that we don't change m_globalScope 224 151 // while WorkerThread::stop is accessing it. 225 LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);152 auto locker = holdLock(m_threadCreationAndGlobalScopeLock); 226 153 227 154 // Delay the destruction of the WorkerGlobalScope context until after we've unlocked the … … 229 156 // context will trigger the main thread to race against us to delete the WorkerThread 230 157 // object, and the WorkerThread object owns the mutex we need to unlock after this. 231 workerGlobalScopeToDelete = WTFMove(m_workerGlobalScope);158 workerGlobalScopeToDelete = std::exchange(m_globalScope, nullptr); 232 159 233 160 if (m_stoppedCallback) … … 249 176 } 250 177 251 void WorkerThread::startRunningDebuggerTasks() 252 { 253 ASSERT(!m_pausedForDebugger); 254 m_pausedForDebugger = true; 255 256 MessageQueueWaitResult result; 257 do { 258 result = m_runLoop.runInDebuggerMode(*m_workerGlobalScope); 259 } while (result != MessageQueueTerminated && m_pausedForDebugger); 260 } 261 262 void WorkerThread::stopRunningDebuggerTasks() 263 { 264 m_pausedForDebugger = false; 265 } 266 267 void WorkerThread::runEventLoop() 268 { 269 // Does not return until terminated. 270 m_runLoop.run(m_workerGlobalScope.get()); 271 } 272 273 void WorkerThread::suspend() 274 { 275 m_isSuspended = true; 276 runLoop().postTask([&](ScriptExecutionContext&) { 277 if (m_workerGlobalScope) 278 m_workerGlobalScope->suspend(); 279 280 m_suspensionSemaphore.wait(); 281 282 if (m_workerGlobalScope) 283 m_workerGlobalScope->resume(); 284 }); 285 } 286 287 void WorkerThread::resume() 288 { 289 ASSERT(m_isSuspended); 290 m_isSuspended = false; 291 m_suspensionSemaphore.signal(); 292 } 293 294 void WorkerThread::stop(WTF::Function<void()>&& stoppedCallback) 178 void WorkerOrWorkletThread::start(WTF::Function<void(const String&)>&& evaluateCallback) 179 { 180 // Mutex protection is necessary to ensure that m_thread is initialized when the thread starts. 181 auto locker = holdLock(m_threadCreationAndGlobalScopeLock); 182 183 if (m_thread) 184 return; 185 186 m_evaluateCallback = WTFMove(evaluateCallback); 187 188 auto thread = createThread(); 189 190 // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads). 191 WTF::storeStoreFence(); 192 193 m_thread = WTFMove(thread); 194 } 195 196 void WorkerOrWorkletThread::stop(Function<void()>&& stoppedCallback) 295 197 { 296 198 // Mutex protection is necessary to ensure that m_workerGlobalScope isn't changed by 297 199 // WorkerThread::workerThread() while we're accessing it. Note also that stop() can 298 200 // be called before m_workerGlobalScope is fully created. 299 auto locker = Locker<Lock>::tryLock(m_threadCreationAndWorkerGlobalScopeMutex);201 auto locker = tryHoldLock(m_threadCreationAndGlobalScopeLock); 300 202 if (!locker) { 301 203 // The thread is still starting, spin the runloop and try again to avoid deadlocks if the worker thread … … 315 217 316 218 // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever. 317 if ( m_workerGlobalScope) {318 m_workerGlobalScope->script()->scheduleExecutionTermination();219 if (globalScope()) { 220 globalScope()->script()->scheduleExecutionTermination(); 319 221 320 222 m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) { 321 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);322 323 workerGlobalScope.prepareForDestruction();223 auto& globalScope = downcast<WorkerOrWorkletGlobalScope>(context); 224 225 globalScope.prepareForDestruction(); 324 226 325 227 // Stick a shutdown command at the end of the queue, so that we deal 326 228 // with all the cleanup tasks the databases post first. 327 workerGlobalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {328 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);229 globalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) { 230 auto& globalScope = downcast<WorkerOrWorkletGlobalScope>(context); 329 231 // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed. 330 workerGlobalScope.clearScript();232 globalScope.clearScript(); 331 233 } }); 332 234 … … 337 239 } 338 240 339 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads() 340 { 341 LockHolder lock(workerThreadsMutex()); 342 for (auto* workerThread : workerThreads(lock)) { 343 workerThread->runLoop().postTask([] (ScriptExecutionContext&) { 241 void WorkerOrWorkletThread::suspend() 242 { 243 m_isSuspended = true; 244 m_runLoop.postTask([&](ScriptExecutionContext&) { 245 if (globalScope()) 246 globalScope()->suspend(); 247 248 m_suspensionSemaphore.wait(); 249 250 if (globalScope()) 251 globalScope()->resume(); 252 }); 253 } 254 255 void WorkerOrWorkletThread::resume() 256 { 257 ASSERT(m_isSuspended); 258 m_isSuspended = false; 259 m_suspensionSemaphore.signal(); 260 } 261 262 void WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads() 263 { 264 auto locker = holdLock(workerOrWorkletThreadsLock()); 265 for (auto* workerOrWorkletThread : workerOrWorkletThreads()) { 266 workerOrWorkletThread->runLoop().postTask([] (ScriptExecutionContext&) { 344 267 WTF::releaseFastMallocFreeMemory(); 345 268 }); … … 347 270 } 348 271 349 IDBClient::IDBConnectionProxy* WorkerThread::idbConnectionProxy()350 {351 #if ENABLE(INDEXED_DATABASE)352 return m_idbConnectionProxy.get();353 #else354 return nullptr;355 #endif356 }357 358 SocketProvider* WorkerThread::socketProvider()359 {360 return m_socketProvider.get();361 }362 363 272 } // namespace WebCore -
trunk/Source/WebCore/workers/WorkerOrWorkletThread.h
r268161 r268897 1 1 /* 2 * Copyright (C) 20 20 Apple Inc. All rights reserved.2 * Copyright (C) 2008-2020 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 26 26 #pragma once 27 27 28 #include "WorkerRunLoop.h" 29 #include <wtf/Forward.h> 30 #include <wtf/Function.h> 31 #include <wtf/Lock.h> 28 32 #include <wtf/ThreadSafeRefCounted.h> 33 #include <wtf/threads/BinarySemaphore.h> 29 34 30 35 namespace WTF { … … 39 44 class WorkerOrWorkletThread : public ThreadSafeRefCounted<WorkerOrWorkletThread> { 40 45 public: 41 virtual ~WorkerOrWorkletThread() = default;46 virtual ~WorkerOrWorkletThread(); 42 47 43 virtual WTF::Thread* thread() const = 0; 44 virtual WorkerRunLoop& runLoop() = 0; 48 WTF::Thread* thread() const { return m_thread.get(); } 45 49 virtual WorkerLoaderProxy& workerLoaderProxy() = 0; 50 51 WorkerOrWorkletGlobalScope* globalScope() const { return m_globalScope.get(); } 52 WorkerRunLoop& runLoop() { return m_runLoop; } 53 54 void start(Function<void(const String&)>&& evaluateCallback = { }); 55 void stop(Function<void()>&& terminatedCallback = { }); 56 57 void startRunningDebuggerTasks(); 58 void stopRunningDebuggerTasks(); 59 60 void suspend(); 61 void resume(); 62 63 const String& identifier() const { return m_identifier; } 64 65 static HashSet<WorkerOrWorkletThread*>& workerOrWorkletThreads(); 66 static Lock& workerOrWorkletThreadsLock(); 67 static void releaseFastMallocFreeMemoryInAllThreads(); 68 69 protected: 70 explicit WorkerOrWorkletThread(const String& identifier); 71 void workerOrWorkletThread(); 72 73 // Executes the event loop for the worker thread. Derived classes can override to perform actions before/after entering the event loop. 74 virtual void runEventLoop(); 75 76 private: 77 virtual Ref<WTF::Thread> createThread() = 0; 78 virtual Ref<WorkerOrWorkletGlobalScope> createGlobalScope() = 0; 79 virtual void evaluateScriptIfNecessary(String&) { } 80 virtual bool shouldWaitForWebInspectorOnStartup() const { return false; } 81 82 String m_identifier; 83 Lock m_threadCreationAndGlobalScopeLock; 84 RefPtr<WorkerOrWorkletGlobalScope> m_globalScope; 85 RefPtr<WTF::Thread> m_thread; 86 WorkerRunLoop m_runLoop; 87 Function<void(const String&)> m_evaluateCallback; 88 Function<void()> m_stoppedCallback; 89 BinarySemaphore m_suspensionSemaphore; 90 bool m_isSuspended { false }; 91 bool m_pausedForDebugger { false }; 46 92 }; 47 93 -
trunk/Source/WebCore/workers/WorkerThread.cpp
r268822 r268897 32 32 #include "SecurityOrigin.h" 33 33 #include "SocketProvider.h" 34 #include "ThreadGlobalData.h"35 34 #include "WorkerGlobalScope.h" 36 #include "WorkerInspectorController.h" 37 #include <utility> 38 #include <wtf/Lock.h> 39 #include <wtf/NeverDestroyed.h> 40 #include <wtf/Noncopyable.h> 41 #include <wtf/text/WTFString.h> 42 43 #if PLATFORM(IOS_FAMILY) 44 #include "FloatingPointEnvironment.h" 45 #include "WebCoreThread.h" 46 #endif 47 48 #if USE(GLIB) 49 #include <wtf/glib/GRefPtr.h> 50 #endif 35 #include <wtf/Threading.h> 51 36 52 37 namespace WebCore { 53 38 54 HashSet<WorkerThread*>& WorkerThread::workerThreads(const LockHolder&) 55 { 56 static NeverDestroyed<HashSet<WorkerThread*>> workerThreads; 57 return workerThreads; 58 } 59 60 Lock& WorkerThread::workerThreadsMutex() 61 { 62 static Lock mutex; 63 return mutex; 64 } 39 static std::atomic<unsigned> workerThreadCounter { 0 }; 65 40 66 41 unsigned WorkerThread::workerThreadCount() 67 42 { 68 LockHolder lock(workerThreadsMutex()); 69 return workerThreads(lock).size(); 43 return workerThreadCounter; 70 44 } 71 45 … … 110 84 111 85 WorkerThread::WorkerThread(const WorkerParameters& params, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerDebuggerProxy& workerDebuggerProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const SecurityOrigin& topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags) 112 : m_identifier(params.identifier.isolatedCopy())86 : WorkerOrWorkletThread(params.identifier.isolatedCopy()) 113 87 , m_workerLoaderProxy(workerLoaderProxy) 114 88 , m_workerDebuggerProxy(workerDebuggerProxy) … … 124 98 UNUSED_PARAM(connectionProxy); 125 99 #endif 126 127 LockHolder lock(workerThreadsMutex()); 128 workerThreads(lock).add(this); 100 ++workerThreadCounter; 129 101 } 130 102 131 103 WorkerThread::~WorkerThread() 132 104 { 133 LockHolder lock(workerThreadsMutex()); 134 ASSERT(workerThreads(lock).contains(this)); 135 workerThreads(lock).remove(this); 105 ASSERT(workerThreadCounter); 106 --workerThreadCounter; 136 107 } 137 108 138 void WorkerThread::start(WTF::Function<void(const String&)>&& evaluateCallback)109 Ref<Thread> WorkerThread::createThread() 139 110 { 140 // Mutex protection is necessary to ensure that m_thread is initialized when the thread starts. 141 LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex); 142 143 if (m_thread) 144 return; 145 146 m_evaluateCallback = WTFMove(evaluateCallback); 147 148 Ref<Thread> thread = Thread::create(isServiceWorkerThread() ? "WebCore: Service Worker" : "WebCore: Worker", [this] { 149 workerThread(); 111 return Thread::create(isServiceWorkerThread() ? "WebCore: Service Worker" : "WebCore: Worker", [this] { 112 workerOrWorkletThread(); 150 113 }, ThreadType::JavaScript); 151 // Force the Thread object to be initialized fully before storing it to m_thread (and becoming visible to other threads).152 WTF::storeStoreFence();153 m_thread = WTFMove(thread);154 114 } 155 115 156 void WorkerThread::workerThread()116 Ref<WorkerOrWorkletGlobalScope> WorkerThread::createGlobalScope() 157 117 { 158 auto protectedThis = makeRef(*this); 118 return createWorkerGlobalScope(m_startupData->params, WTFMove(m_startupData->origin), WTFMove(m_startupData->topOrigin)); 119 } 159 120 160 // Propagate the mainThread's fenv to workers. 161 #if PLATFORM(IOS_FAMILY) 162 FloatingPointEnvironment::singleton().propagateMainThreadEnvironment();163 #endif 121 bool WorkerThread::shouldWaitForWebInspectorOnStartup() const 122 { 123 return m_startupData->startMode == WorkerThreadStartMode::WaitForInspector; 124 } 164 125 165 #if USE(GLIB) 166 GRefPtr<GMainContext> mainContext = adoptGRef(g_main_context_new()); 167 g_main_context_push_thread_default(mainContext.get()); 168 #endif 169 170 WorkerOrWorkletScriptController* scriptController; 171 { 172 // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope 173 // while WorkerThread::stop() is accessing it. Note that WorkerThread::stop() can 174 // be called before we've finished creating the WorkerGlobalScope. 175 LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex); 176 m_workerGlobalScope = createWorkerGlobalScope(m_startupData->params, WTFMove(m_startupData->origin), WTFMove(m_startupData->topOrigin)); 177 178 scriptController = m_workerGlobalScope->script(); 179 180 if (m_runLoop.terminated()) { 181 // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, 182 // forbidExecution() couldn't be called from stop(). 183 scriptController->scheduleExecutionTermination(); 184 scriptController->forbidExecution(); 185 } 186 } 187 188 if (m_startupData->startMode == WorkerThreadStartMode::WaitForInspector) { 189 startRunningDebuggerTasks(); 190 191 // If the worker was somehow terminated while processing debugger commands. 192 if (m_runLoop.terminated()) 193 scriptController->forbidExecution(); 194 } 195 196 String exceptionMessage; 197 scriptController->evaluate(ScriptSourceCode(m_startupData->sourceCode, URL(m_startupData->params.scriptURL)), &exceptionMessage); 126 void WorkerThread::evaluateScriptIfNecessary(String& exceptionMessage) 127 { 128 globalScope()->script()->evaluate(ScriptSourceCode(m_startupData->sourceCode, URL(m_startupData->params.scriptURL)), &exceptionMessage); 198 129 199 130 finishedEvaluatingScript(); 200 201 callOnMainThread([evaluateCallback = WTFMove(m_evaluateCallback), message = exceptionMessage.isolatedCopy()] {202 if (evaluateCallback)203 evaluateCallback(message);204 });205 131 206 132 // Free the startup data to cause its member variable deref's happen on the worker's thread (since … … 208 134 // WorkerThread::~WorkerThread happens on a different thread where it was created. 209 135 m_startupData = nullptr; 210 211 runEventLoop();212 213 #if USE(GLIB)214 g_main_context_pop_thread_default(mainContext.get());215 #endif216 217 RefPtr<Thread> protector = m_thread;218 219 ASSERT(m_workerGlobalScope->hasOneRef());220 221 RefPtr<WorkerGlobalScope> workerGlobalScopeToDelete;222 {223 // Mutex protection is necessary to ensure that we don't change m_workerGlobalScope224 // while WorkerThread::stop is accessing it.225 LockHolder lock(m_threadCreationAndWorkerGlobalScopeMutex);226 227 // Delay the destruction of the WorkerGlobalScope context until after we've unlocked the228 // m_threadCreationAndWorkerGlobalScopeMutex. This is needed because destructing the229 // context will trigger the main thread to race against us to delete the WorkerThread230 // object, and the WorkerThread object owns the mutex we need to unlock after this.231 workerGlobalScopeToDelete = WTFMove(m_workerGlobalScope);232 233 if (m_stoppedCallback)234 callOnMainThread(WTFMove(m_stoppedCallback));235 }236 237 // The below assignment will destroy the context, which will in turn notify messaging proxy.238 // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.239 workerGlobalScopeToDelete = nullptr;240 241 // Clean up WebCore::ThreadGlobalData before WTF::Thread goes away!242 threadGlobalData().destroy();243 244 // Send the last WorkerThread Ref to be Deref'ed on the main thread.245 callOnMainThread([protectedThis = WTFMove(protectedThis)] { });246 247 // The thread object may be already destroyed from notification now, don't try to access "this".248 protector->detach();249 }250 251 void WorkerThread::startRunningDebuggerTasks()252 {253 ASSERT(!m_pausedForDebugger);254 m_pausedForDebugger = true;255 256 MessageQueueWaitResult result;257 do {258 result = m_runLoop.runInDebuggerMode(*m_workerGlobalScope);259 } while (result != MessageQueueTerminated && m_pausedForDebugger);260 }261 262 void WorkerThread::stopRunningDebuggerTasks()263 {264 m_pausedForDebugger = false;265 }266 267 void WorkerThread::runEventLoop()268 {269 // Does not return until terminated.270 m_runLoop.run(m_workerGlobalScope.get());271 }272 273 void WorkerThread::suspend()274 {275 m_isSuspended = true;276 runLoop().postTask([&](ScriptExecutionContext&) {277 if (m_workerGlobalScope)278 m_workerGlobalScope->suspend();279 280 m_suspensionSemaphore.wait();281 282 if (m_workerGlobalScope)283 m_workerGlobalScope->resume();284 });285 }286 287 void WorkerThread::resume()288 {289 ASSERT(m_isSuspended);290 m_isSuspended = false;291 m_suspensionSemaphore.signal();292 }293 294 void WorkerThread::stop(WTF::Function<void()>&& stoppedCallback)295 {296 // Mutex protection is necessary to ensure that m_workerGlobalScope isn't changed by297 // WorkerThread::workerThread() while we're accessing it. Note also that stop() can298 // be called before m_workerGlobalScope is fully created.299 auto locker = Locker<Lock>::tryLock(m_threadCreationAndWorkerGlobalScopeMutex);300 if (!locker) {301 // The thread is still starting, spin the runloop and try again to avoid deadlocks if the worker thread302 // needs to interact with the main thread during startup.303 callOnMainThread([this, stoppedCallback = WTFMove(stoppedCallback)]() mutable {304 stop(WTFMove(stoppedCallback));305 });306 return;307 }308 309 // If the thread is suspended, resume it now so that we can dispatch the cleanup tasks below.310 if (m_isSuspended)311 resume();312 313 ASSERT(!m_stoppedCallback);314 m_stoppedCallback = WTFMove(stoppedCallback);315 316 // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.317 if (m_workerGlobalScope) {318 m_workerGlobalScope->script()->scheduleExecutionTermination();319 320 m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) {321 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);322 323 workerGlobalScope.prepareForDestruction();324 325 // Stick a shutdown command at the end of the queue, so that we deal326 // with all the cleanup tasks the databases post first.327 workerGlobalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {328 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);329 // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.330 workerGlobalScope.clearScript();331 } });332 333 } });334 return;335 }336 m_runLoop.terminate();337 }338 339 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads()340 {341 LockHolder lock(workerThreadsMutex());342 for (auto* workerThread : workerThreads(lock)) {343 workerThread->runLoop().postTask([] (ScriptExecutionContext&) {344 WTF::releaseFastMallocFreeMemory();345 });346 }347 136 } 348 137 … … 361 150 } 362 151 152 WorkerGlobalScope* WorkerThread::globalScope() 153 { 154 return downcast<WorkerGlobalScope>(WorkerOrWorkletThread::globalScope()); 155 } 156 363 157 } // namespace WebCore -
trunk/Source/WebCore/workers/WorkerThread.h
r268161 r268897 28 28 #include "ContentSecurityPolicyResponseHeaders.h" 29 29 #include "WorkerOrWorkletThread.h" 30 #include "WorkerRunLoop.h"31 30 #include <JavaScriptCore/RuntimeFlags.h> 32 31 #include <memory> 33 #include <wtf/Forward.h>34 #include <wtf/Function.h>35 #include <wtf/RefCounted.h>36 32 #include <wtf/URL.h> 37 #include <wtf/threads/BinarySemaphore.h>38 33 39 34 namespace WebCore { 40 35 41 class ContentSecurityPolicyResponseHeaders;42 36 class NotificationClient; 43 37 class SecurityOrigin; … … 81 75 virtual ~WorkerThread(); 82 76 83 static HashSet<WorkerThread*>& workerThreads(const LockHolder&);84 static Lock& workerThreadsMutex();85 86 void stop(WTF::Function<void()>&& terminatedCallback);87 88 void suspend();89 void resume();90 91 Thread* thread() const final { return m_thread.get(); }92 WorkerRunLoop& runLoop() final { return m_runLoop; }93 77 WorkerLoaderProxy& workerLoaderProxy() final { return m_workerLoaderProxy; } 94 78 WorkerDebuggerProxy& workerDebuggerProxy() const { return m_workerDebuggerProxy; } … … 97 81 // Number of active worker threads. 98 82 WEBCORE_EXPORT static unsigned workerThreadCount(); 99 static void releaseFastMallocFreeMemoryInAllThreads();100 83 101 84 #if ENABLE(NOTIFICATIONS) … … 103 86 void setNotificationClient(NotificationClient* client) { m_notificationClient = client; } 104 87 #endif 105 106 void startRunningDebuggerTasks();107 void stopRunningDebuggerTasks();108 88 109 89 JSC::RuntimeFlags runtimeFlags() const { return m_runtimeFlags; } 110 111 String identifier() const { return m_identifier; }112 90 113 91 protected: … … 117 95 virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const WorkerParameters&, Ref<SecurityOrigin>&&, Ref<SecurityOrigin>&& topOrigin) = 0; 118 96 119 // Executes the event loop for the worker thread. Derived classes can override to perform actions before/after entering the event loop. 120 virtual void runEventLoop(); 121 122 WorkerGlobalScope* workerGlobalScope() { return m_workerGlobalScope.get(); } 97 WorkerGlobalScope* globalScope(); 123 98 124 99 IDBClient::IDBConnectionProxy* idbConnectionProxy(); 125 100 SocketProvider* socketProvider(); 126 101 127 void start(Function<void(const String&)>&& evaluateCallback);128 129 102 private: 130 void workerThread();131 103 virtual bool isServiceWorkerThread() const { return false; } 132 104 133 105 virtual void finishedEvaluatingScript() { } 134 106 135 RefPtr<Thread> m_thread; 136 String m_identifier; 137 WorkerRunLoop m_runLoop; 107 // WorkerOrWorkletThread. 108 Ref<WTF::Thread> createThread() final; 109 Ref<WorkerOrWorkletGlobalScope> createGlobalScope() final; 110 void evaluateScriptIfNecessary(String& exceptionMessage) final; 111 bool shouldWaitForWebInspectorOnStartup() const final; 112 138 113 WorkerLoaderProxy& m_workerLoaderProxy; 139 114 WorkerDebuggerProxy& m_workerDebuggerProxy; 140 115 WorkerReportingProxy& m_workerReportingProxy; 141 116 JSC::RuntimeFlags m_runtimeFlags; 142 bool m_pausedForDebugger { false };143 144 RefPtr<WorkerGlobalScope> m_workerGlobalScope;145 Lock m_threadCreationAndWorkerGlobalScopeMutex;146 117 147 118 std::unique_ptr<WorkerThreadStartupData> m_startupData; 148 149 WTF::Function<void(const String&)> m_evaluateCallback;150 119 151 120 #if ENABLE(NOTIFICATIONS) … … 157 126 #endif 158 127 RefPtr<SocketProvider> m_socketProvider; 159 160 WTF::Function<void()> m_stoppedCallback;161 BinarySemaphore m_suspensionSemaphore;162 bool m_isSuspended { false };163 128 }; 164 129 -
trunk/Source/WebCore/workers/service/context/ServiceWorkerThread.cpp
r266275 r268897 100 100 void ServiceWorkerThread::queueTaskToFireFetchEvent(Ref<ServiceWorkerFetch::Client>&& client, Optional<ServiceWorkerClientIdentifier>&& clientId, ResourceRequest&& request, String&& referrer, FetchOptions&& options) 101 101 { 102 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(* workerGlobalScope()));102 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope())); 103 103 serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [serviceWorkerGlobalScope, client = WTFMove(client), clientId, request = WTFMove(request), referrer = WTFMove(referrer), options = WTFMove(options)]() mutable { 104 104 ServiceWorkerFetch::dispatchFetchEvent(WTFMove(client), serviceWorkerGlobalScope, clientId, WTFMove(request), WTFMove(referrer), WTFMove(options)); … … 117 117 void ServiceWorkerThread::queueTaskToPostMessage(MessageWithMessagePorts&& message, ServiceWorkerOrClientData&& sourceData) 118 118 { 119 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(* workerGlobalScope()));119 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope())); 120 120 serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [weakThis = makeWeakPtr(this), serviceWorkerGlobalScope, message = WTFMove(message), sourceData = WTFMove(sourceData)]() mutable { 121 121 URL sourceURL; … … 146 146 void ServiceWorkerThread::queueTaskToFireInstallEvent() 147 147 { 148 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(* workerGlobalScope()));148 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope())); 149 149 serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [weakThis = makeWeakPtr(this), serviceWorkerGlobalScope]() mutable { 150 150 RELEASE_LOG(ServiceWorker, "ServiceWorkerThread::queueTaskToFireInstallEvent firing event for worker %llu", serviceWorkerGlobalScope->thread().identifier().toUInt64()); … … 172 172 void ServiceWorkerThread::queueTaskToFireActivateEvent() 173 173 { 174 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(* workerGlobalScope()));174 auto serviceWorkerGlobalScope = makeRef(downcast<ServiceWorkerGlobalScope>(*globalScope())); 175 175 serviceWorkerGlobalScope->eventLoop().queueTask(TaskSource::DOMManipulation, [weakThis = makeWeakPtr(this), serviceWorkerGlobalScope]() mutable { 176 176 RELEASE_LOG(ServiceWorker, "ServiceWorkerThread::queueTaskToFireActivateEvent firing event for worker %llu", serviceWorkerGlobalScope->thread().identifier().toUInt64()); … … 192 192 { 193 193 ASSERT(!isMainThread()); 194 m_doesHandleFetch = workerGlobalScope()->hasEventListeners(eventNames().fetchEvent);194 m_doesHandleFetch = globalScope()->hasEventListeners(eventNames().fetchEvent); 195 195 } 196 196 -
trunk/Source/WebCore/worklets/Worklet.cpp
r267859 r268897 34 34 #include "WorkletGlobalScopeProxy.h" 35 35 #include "WorkletPendingTasks.h" 36 #include <JavaScriptCore/IdentifiersFactory.h> 36 37 #include <wtf/CrossThreadCopier.h> 37 38 #include <wtf/IsoMallocInlines.h> … … 43 44 Worklet::Worklet(Document& document) 44 45 : ActiveDOMObject(&document) 46 , m_identifier("worklet:" + Inspector::IdentifiersFactory::createIdentifier()) 45 47 { 46 48 } -
trunk/Source/WebCore/worklets/Worklet.h
r267859 r268897 53 53 54 54 const Vector<Ref<WorkletGlobalScopeProxy>>& proxies() const { return m_proxies; } 55 const String& identifier() const { return m_identifier; } 55 56 56 57 protected: … … 63 64 const char* activeDOMObjectName() const final; 64 65 66 String m_identifier; 65 67 Vector<Ref<WorkletGlobalScopeProxy>> m_proxies; 66 68 HashSet<RefPtr<WorkletPendingTasks>> m_pendingTasksSet; -
trunk/Source/WebCore/worklets/WorkletParameters.h
r268076 r268897 35 35 JSC::RuntimeFlags jsRuntimeFlags; 36 36 float sampleRate; 37 String identifier; 37 38 38 39 WorkletParameters isolatedCopy() const … … 41 42 windowURL.isolatedCopy(), 42 43 jsRuntimeFlags, 43 sampleRate 44 sampleRate, 45 identifier.isolatedCopy() 44 46 }; 45 47 }
Note:
See TracChangeset
for help on using the changeset viewer.