~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/workers/WorkerThread.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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.
 
24
 *
 
25
 */
 
26
 
 
27
#include "config.h"
 
28
 
 
29
#if ENABLE(WORKERS)
 
30
 
 
31
#include "WorkerThread.h"
 
32
 
 
33
#include "DatabaseContext.h"
 
34
#include "DedicatedWorkerContext.h"
 
35
#include "InspectorInstrumentation.h"
 
36
#include "KURL.h"
 
37
#include "ScriptSourceCode.h"
 
38
#include "ScriptValue.h"
 
39
#include "ThreadGlobalData.h"
 
40
 
 
41
#include <utility>
 
42
#include <wtf/Noncopyable.h>
 
43
#include <wtf/text/WTFString.h>
 
44
 
 
45
#if ENABLE(SQL_DATABASE)
 
46
#include "DatabaseTask.h"
 
47
#include "DatabaseTracker.h"
 
48
#endif
 
49
 
 
50
#if PLATFORM(CHROMIUM)
 
51
#include <public/Platform.h>
 
52
#include <public/WebWorkerRunLoop.h>
 
53
#endif
 
54
 
 
55
namespace WebCore {
 
56
 
 
57
static Mutex& threadCountMutex()
 
58
{
 
59
    AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
 
60
    return mutex;
 
61
}
 
62
 
 
63
unsigned WorkerThread::m_threadCount = 0;
 
64
 
 
65
unsigned WorkerThread::workerThreadCount()
 
66
{
 
67
    MutexLocker lock(threadCountMutex());
 
68
    return m_threadCount;
 
69
}
 
70
 
 
71
struct WorkerThreadStartupData {
 
72
    WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED;
 
73
public:
 
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)
 
75
    {
 
76
        return adoptPtr(new WorkerThreadStartupData(scriptURL, userAgent, settings, sourceCode, startMode, contentSecurityPolicy, contentSecurityPolicyType, topOrigin));
 
77
    }
 
78
 
 
79
    KURL m_scriptURL;
 
80
    String m_userAgent;
 
81
    OwnPtr<GroupSettings> m_groupSettings;
 
82
    String m_sourceCode;
 
83
    WorkerThreadStartMode m_startMode;
 
84
    String m_contentSecurityPolicy;
 
85
    ContentSecurityPolicy::HeaderType m_contentSecurityPolicyType;
 
86
    RefPtr<SecurityOrigin> m_topOrigin;
 
87
private:
 
88
    WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const GroupSettings*, const String& sourceCode, WorkerThreadStartMode, const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType contentSecurityPolicyType, const SecurityOrigin* topOrigin);
 
89
};
 
90
 
 
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)
 
99
{
 
100
    if (!settings)
 
101
        return;
 
102
 
 
103
    m_groupSettings = GroupSettings::create();
 
104
    m_groupSettings->setLocalStorageQuotaBytes(settings->localStorageQuotaBytes());
 
105
    m_groupSettings->setIndexedDBQuotaBytes(settings->indexedDBQuotaBytes());
 
106
    m_groupSettings->setIndexedDBDatabasePath(settings->indexedDBDatabasePath().isolatedCopy());
 
107
}
 
108
 
 
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)
 
110
    : m_threadID(0)
 
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)
 
116
#endif
 
117
{
 
118
    MutexLocker lock(threadCountMutex());
 
119
    m_threadCount++;
 
120
}
 
121
 
 
122
WorkerThread::~WorkerThread()
 
123
{
 
124
    MutexLocker lock(threadCountMutex());
 
125
    ASSERT(m_threadCount > 0);
 
126
    m_threadCount--;
 
127
}
 
128
 
 
129
bool WorkerThread::start()
 
130
{
 
131
    // Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts.
 
132
    MutexLocker lock(m_threadCreationMutex);
 
133
 
 
134
    if (m_threadID)
 
135
        return true;
 
136
 
 
137
    m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker");
 
138
 
 
139
    return m_threadID;
 
140
}
 
141
 
 
142
void WorkerThread::workerThreadStart(void* thread)
 
143
{
 
144
    static_cast<WorkerThread*>(thread)->workerThread();
 
145
}
 
146
 
 
147
void WorkerThread::workerThread()
 
148
{
 
149
    {
 
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());
 
152
 
 
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();
 
157
        }
 
158
    }
 
159
#if PLATFORM(CHROMIUM)
 
160
    // The corresponding call to didStopWorkerRunLoop is in
 
161
    // ~WorkerScriptController.
 
162
    WebKit::Platform::current()->didStartWorkerRunLoop(WebKit::WebWorkerRunLoop(&m_runLoop));
 
163
#endif
 
164
 
 
165
    WorkerScriptController* script = m_workerContext->script();
 
166
#if ENABLE(INSPECTOR)
 
167
    InspectorInstrumentation::willEvaluateWorkerScript(workerContext(), m_startupData->m_startMode);
 
168
#endif
 
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();
 
174
 
 
175
    runEventLoop();
 
176
 
 
177
    ThreadIdentifier threadID = m_threadID;
 
178
 
 
179
    ASSERT(m_workerContext->hasOneRef());
 
180
 
 
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.
 
183
    m_workerContext = 0;
 
184
 
 
185
    // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away!
 
186
    threadGlobalData().destroy();
 
187
 
 
188
    // The thread object may be already destroyed from notification now, don't try to access "this".
 
189
    detachThread(threadID);
 
190
}
 
191
 
 
192
void WorkerThread::runEventLoop()
 
193
{
 
194
    // Does not return until terminated.
 
195
    m_runLoop.run(m_workerContext.get());
 
196
}
 
197
 
 
198
class WorkerThreadShutdownFinishTask : public ScriptExecutionContext::Task {
 
199
public:
 
200
    static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
 
201
    {
 
202
        return adoptPtr(new WorkerThreadShutdownFinishTask());
 
203
    }
 
204
 
 
205
    virtual void performTask(ScriptExecutionContext *context)
 
206
    {
 
207
        ASSERT(context->isWorkerContext());
 
208
        WorkerContext* workerContext = static_cast<WorkerContext*>(context);
 
209
#if ENABLE(INSPECTOR)
 
210
        workerContext->clearInspector();
 
211
#endif
 
212
        // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
 
213
        workerContext->clearScript();
 
214
    }
 
215
 
 
216
    virtual bool isCleanupTask() const { return true; }
 
217
};
 
218
 
 
219
class WorkerThreadShutdownStartTask : public ScriptExecutionContext::Task {
 
220
public:
 
221
    static PassOwnPtr<WorkerThreadShutdownStartTask> create()
 
222
    {
 
223
        return adoptPtr(new WorkerThreadShutdownStartTask());
 
224
    }
 
225
 
 
226
    virtual void performTask(ScriptExecutionContext *context)
 
227
    {
 
228
        ASSERT(context->isWorkerContext());
 
229
        WorkerContext* workerContext = static_cast<WorkerContext*>(context);
 
230
 
 
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);
 
235
#endif
 
236
 
 
237
        workerContext->stopActiveDOMObjects();
 
238
 
 
239
        workerContext->notifyObserversOfStop();
 
240
 
 
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();
 
244
 
 
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();
 
249
#endif
 
250
 
 
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());
 
254
    }
 
255
 
 
256
    virtual bool isCleanupTask() const { return true; }
 
257
};
 
258
 
 
259
void WorkerThread::stop()
 
260
{
 
261
    // Mutex protection is necessary because stop() can be called before the context is fully created.
 
262
    MutexLocker lock(m_threadCreationMutex);
 
263
 
 
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();
 
267
 
 
268
#if ENABLE(SQL_DATABASE)
 
269
        DatabaseTracker::tracker().interruptAllDatabasesForContext(m_workerContext.get());
 
270
#endif
 
271
        m_runLoop.postTask(WorkerThreadShutdownStartTask::create());
 
272
    }
 
273
    m_runLoop.terminate();
 
274
}
 
275
 
 
276
} // namespace WebCore
 
277
 
 
278
#endif // ENABLE(WORKERS)