2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "WorkerThread.h"
31 #include "DedicatedWorkerGlobalScope.h"
32 #include "InspectorInstrumentation.h"
33 #include "ScriptSourceCode.h"
34 #include "SecurityOrigin.h"
35 #include "ThreadGlobalData.h"
38 #include <wtf/NeverDestroyed.h>
39 #include <wtf/Noncopyable.h>
40 #include <wtf/text/WTFString.h>
43 #include "FloatingPointEnvironment.h"
44 #include "WebCoreThread.h"
49 static std::mutex& threadSetMutex()
51 static std::once_flag onceFlag;
52 static LazyNeverDestroyed<std::mutex> mutex;
54 std::call_once(onceFlag, []{
61 static HashSet<WorkerThread*>& workerThreads()
63 static NeverDestroyed<HashSet<WorkerThread*>> workerThreads;
68 unsigned WorkerThread::workerThreadCount()
70 std::lock_guard<std::mutex> lock(threadSetMutex());
72 return workerThreads().size();
75 struct WorkerThreadStartupData {
76 WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED;
78 WorkerThreadStartupData(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin);
83 WorkerThreadStartMode m_startMode;
84 String m_contentSecurityPolicy;
85 ContentSecurityPolicy::HeaderType m_contentSecurityPolicyType;
86 RefPtr<SecurityOrigin> m_topOrigin;
89 WorkerThreadStartupData::WorkerThreadStartupData(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode startMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin)
90 : m_scriptURL(scriptURL.isolatedCopy())
91 , m_userAgent(userAgent.isolatedCopy())
92 , m_sourceCode(sourceCode.isolatedCopy())
93 , m_startMode(startMode)
94 , m_contentSecurityPolicy(contentSecurityPolicy.isolatedCopy())
95 , m_contentSecurityPolicyType(contentSecurityPolicyType)
96 , m_topOrigin(topOrigin ? &topOrigin->isolatedCopy().get() : nullptr)
100 WorkerThread::WorkerThread(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin)
102 , m_workerLoaderProxy(workerLoaderProxy)
103 , m_workerReportingProxy(workerReportingProxy)
104 , m_startupData(std::make_unique<WorkerThreadStartupData>(scriptURL, userAgent, sourceCode, startMode, contentSecurityPolicy, contentSecurityPolicyType, topOrigin))
105 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
106 , m_notificationClient(0)
109 std::lock_guard<std::mutex> lock(threadSetMutex());
111 workerThreads().add(this);
114 WorkerThread::~WorkerThread()
116 std::lock_guard<std::mutex> lock(threadSetMutex());
118 ASSERT(workerThreads().contains(this));
119 workerThreads().remove(this);
122 bool WorkerThread::start()
124 // Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts.
125 DeprecatedMutexLocker lock(m_threadCreationMutex);
130 m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker");
135 void WorkerThread::workerThreadStart(void* thread)
137 static_cast<WorkerThread*>(thread)->workerThread();
140 void WorkerThread::workerThread()
142 // Propagate the mainThread's fenv to workers.
144 FloatingPointEnvironment::singleton().propagateMainThreadEnvironment();
148 DeprecatedMutexLocker lock(m_threadCreationMutex);
149 m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicy, m_startupData->m_contentSecurityPolicyType, m_startupData->m_topOrigin.release());
151 if (m_runLoop.terminated()) {
152 // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
153 // forbidExecution() couldn't be called from stop().
154 m_workerGlobalScope->script()->forbidExecution();
158 WorkerScriptController* script = m_workerGlobalScope->script();
159 InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), m_startupData->m_startMode);
160 script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL));
161 // Free the startup data to cause its member variable deref's happen on the worker's thread (since
162 // all ref/derefs of these objects are happening on the thread at this point). Note that
163 // WorkerThread::~WorkerThread happens on a different thread where it was created.
164 m_startupData = nullptr;
168 ThreadIdentifier threadID = m_threadID;
170 ASSERT(m_workerGlobalScope->hasOneRef());
172 // The below assignment will destroy the context, which will in turn notify messaging proxy.
173 // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
174 m_workerGlobalScope = nullptr;
176 // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away!
177 threadGlobalData().destroy();
179 // The thread object may be already destroyed from notification now, don't try to access "this".
180 detachThread(threadID);
183 void WorkerThread::runEventLoop()
185 // Does not return until terminated.
186 m_runLoop.run(m_workerGlobalScope.get());
189 void WorkerThread::stop()
191 // Mutex protection is necessary because stop() can be called before the context is fully created.
192 DeprecatedMutexLocker lock(m_threadCreationMutex);
194 // 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.
195 if (m_workerGlobalScope) {
196 m_workerGlobalScope->script()->scheduleExecutionTermination();
198 m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) {
199 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
201 workerGlobalScope.stopActiveDOMObjects();
202 workerGlobalScope.notifyObserversOfStop();
204 // Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
205 // which become dangling once Heap is destroyed.
206 workerGlobalScope.removeAllEventListeners();
208 // Stick a shutdown command at the end of the queue, so that we deal
209 // with all the cleanup tasks the databases post first.
210 workerGlobalScope.postTask({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context) {
211 WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
212 // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
213 workerGlobalScope.clearScript();
219 m_runLoop.terminate();
222 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads()
224 std::lock_guard<std::mutex> lock(threadSetMutex());
226 for (auto* workerThread : workerThreads()) {
227 workerThread->runLoop().postTask([] (ScriptExecutionContext&) {
228 WTF::releaseFastMallocFreeMemory();
233 } // namespace WebCore