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 COMPUTER, 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 COMPUTER, 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.
31
#include "WorkerThread.h"
33
#include "DatabaseContext.h"
34
#include "DedicatedWorkerContext.h"
35
#include "InspectorInstrumentation.h"
37
#include "ScriptSourceCode.h"
38
#include "ScriptValue.h"
39
#include "ThreadGlobalData.h"
42
#include <wtf/Noncopyable.h>
43
#include <wtf/text/WTFString.h>
45
#if ENABLE(SQL_DATABASE)
46
#include "DatabaseTask.h"
47
#include "DatabaseTracker.h"
50
#if PLATFORM(CHROMIUM)
51
#include <public/Platform.h>
52
#include <public/WebWorkerRunLoop.h>
57
static Mutex& threadCountMutex()
59
AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
63
unsigned WorkerThread::m_threadCount = 0;
65
unsigned WorkerThread::workerThreadCount()
67
MutexLocker lock(threadCountMutex());
71
struct WorkerThreadStartupData {
72
WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED;
74
static PassOwnPtr<WorkerThreadStartupData> create(const KURL& scriptURL, const String& userAgent, const GroupSettings* settings, const String& sourceCode, WorkerThreadStartMode startMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin)
76
return adoptPtr(new WorkerThreadStartupData(scriptURL, userAgent, settings, sourceCode, startMode, contentSecurityPolicy, contentSecurityPolicyType, topOrigin));
81
OwnPtr<GroupSettings> m_groupSettings;
83
WorkerThreadStartMode m_startMode;
84
String m_contentSecurityPolicy;
85
ContentSecurityPolicy::HeaderType m_contentSecurityPolicyType;
86
RefPtr<SecurityOrigin> m_topOrigin;
88
WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const GroupSettings*, const String& sourceCode, WorkerThreadStartMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin);
91
WorkerThreadStartupData::WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const GroupSettings* settings, const String& sourceCode, WorkerThreadStartMode startMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin)
92
: m_scriptURL(scriptURL.copy())
93
, m_userAgent(userAgent.isolatedCopy())
94
, m_sourceCode(sourceCode.isolatedCopy())
95
, m_startMode(startMode)
96
, m_contentSecurityPolicy(contentSecurityPolicy.isolatedCopy())
97
, m_contentSecurityPolicyType(contentSecurityPolicyType)
98
, m_topOrigin(topOrigin ? topOrigin->isolatedCopy() : 0)
103
m_groupSettings = GroupSettings::create();
104
m_groupSettings->setLocalStorageQuotaBytes(settings->localStorageQuotaBytes());
105
m_groupSettings->setIndexedDBQuotaBytes(settings->indexedDBQuotaBytes());
106
m_groupSettings->setIndexedDBDatabasePath(settings->indexedDBDatabasePath().isolatedCopy());
109
WorkerThread::WorkerThread(const KURL& scriptURL, const String& userAgent, const GroupSettings* settings, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin)
111
, m_workerLoaderProxy(workerLoaderProxy)
112
, m_workerReportingProxy(workerReportingProxy)
113
, m_startupData(WorkerThreadStartupData::create(scriptURL, userAgent, settings, sourceCode, startMode, contentSecurityPolicy, contentSecurityPolicyType, topOrigin))
114
#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
115
, m_notificationClient(0)
118
MutexLocker lock(threadCountMutex());
122
WorkerThread::~WorkerThread()
124
MutexLocker lock(threadCountMutex());
125
ASSERT(m_threadCount > 0);
129
bool WorkerThread::start()
131
// Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts.
132
MutexLocker lock(m_threadCreationMutex);
137
m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker");
142
void WorkerThread::workerThreadStart(void* thread)
144
static_cast<WorkerThread*>(thread)->workerThread();
147
void WorkerThread::workerThread()
150
MutexLocker lock(m_threadCreationMutex);
151
m_workerContext = createWorkerContext(m_startupData->m_scriptURL, m_startupData->m_userAgent, m_startupData->m_groupSettings.release(), m_startupData->m_contentSecurityPolicy, m_startupData->m_contentSecurityPolicyType, m_startupData->m_topOrigin.release());
153
if (m_runLoop.terminated()) {
154
// The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
155
// forbidExecution() couldn't be called from stop().
156
m_workerContext->script()->forbidExecution();
159
#if PLATFORM(CHROMIUM)
160
// The corresponding call to didStopWorkerRunLoop is in
161
// ~WorkerScriptController.
162
WebKit::Platform::current()->didStartWorkerRunLoop(WebKit::WebWorkerRunLoop(&m_runLoop));
165
WorkerScriptController* script = m_workerContext->script();
166
#if ENABLE(INSPECTOR)
167
InspectorInstrumentation::willEvaluateWorkerScript(workerContext(), m_startupData->m_startMode);
169
script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL));
170
// Free the startup data to cause its member variable deref's happen on the worker's thread (since
171
// all ref/derefs of these objects are happening on the thread at this point). Note that
172
// WorkerThread::~WorkerThread happens on a different thread where it was created.
173
m_startupData.clear();
177
ThreadIdentifier threadID = m_threadID;
179
ASSERT(m_workerContext->hasOneRef());
181
// The below assignment will destroy the context, which will in turn notify messaging proxy.
182
// We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
185
// Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away!
186
threadGlobalData().destroy();
188
// The thread object may be already destroyed from notification now, don't try to access "this".
189
detachThread(threadID);
192
void WorkerThread::runEventLoop()
194
// Does not return until terminated.
195
m_runLoop.run(m_workerContext.get());
198
class WorkerThreadShutdownFinishTask : public ScriptExecutionContext::Task {
200
static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
202
return adoptPtr(new WorkerThreadShutdownFinishTask());
205
virtual void performTask(ScriptExecutionContext *context)
207
ASSERT(context->isWorkerContext());
208
WorkerContext* workerContext = static_cast<WorkerContext*>(context);
209
#if ENABLE(INSPECTOR)
210
workerContext->clearInspector();
212
// It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
213
workerContext->clearScript();
216
virtual bool isCleanupTask() const { return true; }
219
class WorkerThreadShutdownStartTask : public ScriptExecutionContext::Task {
221
static PassOwnPtr<WorkerThreadShutdownStartTask> create()
223
return adoptPtr(new WorkerThreadShutdownStartTask());
226
virtual void performTask(ScriptExecutionContext *context)
228
ASSERT(context->isWorkerContext());
229
WorkerContext* workerContext = static_cast<WorkerContext*>(context);
231
#if ENABLE(SQL_DATABASE)
232
// FIXME: Should we stop the databases as part of stopActiveDOMObjects() below?
233
DatabaseTaskSynchronizer cleanupSync;
234
DatabaseContext::stopDatabases(workerContext, &cleanupSync);
237
workerContext->stopActiveDOMObjects();
239
workerContext->notifyObserversOfStop();
241
// Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
242
// which become dangling once Heap is destroyed.
243
workerContext->removeAllEventListeners();
245
#if ENABLE(SQL_DATABASE)
246
// We wait for the database thread to clean up all its stuff so that we
247
// can do more stringent leak checks as we exit.
248
cleanupSync.waitForTaskCompletion();
251
// Stick a shutdown command at the end of the queue, so that we deal
252
// with all the cleanup tasks the databases post first.
253
workerContext->postTask(WorkerThreadShutdownFinishTask::create());
256
virtual bool isCleanupTask() const { return true; }
259
void WorkerThread::stop()
261
// Mutex protection is necessary because stop() can be called before the context is fully created.
262
MutexLocker lock(m_threadCreationMutex);
264
// 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.
265
if (m_workerContext) {
266
m_workerContext->script()->scheduleExecutionTermination();
268
#if ENABLE(SQL_DATABASE)
269
DatabaseTracker::tracker().interruptAllDatabasesForContext(m_workerContext.get());
271
m_runLoop.postTask(WorkerThreadShutdownStartTask::create());
273
m_runLoop.terminate();
276
} // namespace WebCore
278
#endif // ENABLE(WORKERS)