Rename URL::copy() to URL::isolatedCopy() to match String.
[WebKit-https.git] / Source / WebCore / workers / WorkerThread.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  *
25  */
26
27 #include "config.h"
28
29 #include "WorkerThread.h"
30
31 #include "DedicatedWorkerGlobalScope.h"
32 #include "InspectorInstrumentation.h"
33 #include "ScriptSourceCode.h"
34 #include "SecurityOrigin.h"
35 #include "ThreadGlobalData.h"
36 #include "URL.h"
37 #include <utility>
38 #include <wtf/NeverDestroyed.h>
39 #include <wtf/Noncopyable.h>
40 #include <wtf/text/WTFString.h>
41
42 #if PLATFORM(IOS)
43 #include "FloatingPointEnvironment.h"
44 #include "WebCoreThread.h"
45 #endif
46
47 namespace WebCore {
48
49 static std::mutex& threadSetMutex()
50 {
51     static std::once_flag onceFlag;
52     static LazyNeverDestroyed<std::mutex> mutex;
53
54     std::call_once(onceFlag, []{
55         mutex.construct();
56     });
57
58     return mutex;
59 }
60
61 static HashSet<WorkerThread*>& workerThreads()
62 {
63     static NeverDestroyed<HashSet<WorkerThread*>> workerThreads;
64
65     return workerThreads;
66 }
67
68 unsigned WorkerThread::workerThreadCount()
69 {
70     std::lock_guard<std::mutex> lock(threadSetMutex());
71
72     return workerThreads().size();
73 }
74
75 struct WorkerThreadStartupData {
76     WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED;
77 public:
78     WorkerThreadStartupData(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin);
79
80     URL m_scriptURL;
81     String m_userAgent;
82     String m_sourceCode;
83     WorkerThreadStartMode m_startMode;
84     String m_contentSecurityPolicy;
85     ContentSecurityPolicy::HeaderType m_contentSecurityPolicyType;
86     RefPtr<SecurityOrigin> m_topOrigin;
87 };
88
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)
97 {
98 }
99
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)
101     : m_threadID(0)
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)
107 #endif
108 {
109     std::lock_guard<std::mutex> lock(threadSetMutex());
110
111     workerThreads().add(this);
112 }
113
114 WorkerThread::~WorkerThread()
115 {
116     std::lock_guard<std::mutex> lock(threadSetMutex());
117
118     ASSERT(workerThreads().contains(this));
119     workerThreads().remove(this);
120 }
121
122 bool WorkerThread::start()
123 {
124     // Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts.
125     MutexLocker lock(m_threadCreationMutex);
126
127     if (m_threadID)
128         return true;
129
130     m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker");
131
132     return m_threadID;
133 }
134
135 void WorkerThread::workerThreadStart(void* thread)
136 {
137     static_cast<WorkerThread*>(thread)->workerThread();
138 }
139
140 void WorkerThread::workerThread()
141 {
142     // Propagate the mainThread's fenv to workers.
143 #if PLATFORM(IOS)
144     FloatingPointEnvironment::singleton().propagateMainThreadEnvironment();
145 #endif
146
147     {
148         MutexLocker 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());
150
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();
155         }
156     }
157
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;
165
166     runEventLoop();
167
168     ThreadIdentifier threadID = m_threadID;
169
170     ASSERT(m_workerGlobalScope->hasOneRef());
171
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 = 0;
175
176     // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away!
177     threadGlobalData().destroy();
178
179     // The thread object may be already destroyed from notification now, don't try to access "this".
180     detachThread(threadID);
181 }
182
183 void WorkerThread::runEventLoop()
184 {
185     // Does not return until terminated.
186     m_runLoop.run(m_workerGlobalScope.get());
187 }
188
189 void WorkerThread::stop()
190 {
191     // Mutex protection is necessary because stop() can be called before the context is fully created.
192     MutexLocker lock(m_threadCreationMutex);
193
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();
197
198         m_runLoop.postTaskAndTerminate({ ScriptExecutionContext::Task::CleanupTask, [] (ScriptExecutionContext& context ) {
199             WorkerGlobalScope& workerGlobalScope = downcast<WorkerGlobalScope>(context);
200
201             workerGlobalScope.stopActiveDOMObjects();
202             workerGlobalScope.notifyObserversOfStop();
203
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();
207
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();
214             } });
215
216         } });
217         return;
218     }
219     m_runLoop.terminate();
220 }
221
222 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads()
223 {
224     std::lock_guard<std::mutex> lock(threadSetMutex());
225
226     for (auto* workerThread : workerThreads()) {
227         workerThread->runLoop().postTask([] (ScriptExecutionContext&) {
228             WTF::releaseFastMallocFreeMemory();
229         });
230     }
231 }
232
233 } // namespace WebCore