Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 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 #include "core/workers/WorkerThread.h"
30
31 #include "bindings/v8/ScriptSourceCode.h"
32 #include "core/inspector/InspectorInstrumentation.h"
33 #include "core/workers/DedicatedWorkerGlobalScope.h"
34 #include "core/workers/WorkerClients.h"
35 #include "core/workers/WorkerReportingProxy.h"
36 #include "core/workers/WorkerThreadStartupData.h"
37 #include "platform/PlatformThreadData.h"
38 #include "platform/heap/ThreadState.h"
39 #include "platform/weborigin/KURL.h"
40 #include "public/platform/Platform.h"
41 #include "public/platform/WebWaitableEvent.h"
42 #include "public/platform/WebWorkerRunLoop.h"
43 #include "wtf/Noncopyable.h"
44 #include "wtf/text/WTFString.h"
45
46 #include <utility>
47
48 namespace WebCore {
49
50 static Mutex& threadSetMutex()
51 {
52     AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
53     return mutex;
54 }
55
56 static HashSet<WorkerThread*>& workerThreads()
57 {
58     DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ());
59     return threads;
60 }
61
62 unsigned WorkerThread::workerThreadCount()
63 {
64     MutexLocker lock(threadSetMutex());
65     return workerThreads().size();
66 }
67
68 WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> startupData)
69     : m_threadID(0)
70     , m_workerLoaderProxy(workerLoaderProxy)
71     , m_workerReportingProxy(workerReportingProxy)
72     , m_startupData(startupData)
73     , m_notificationClient(0)
74     , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent()))
75 {
76     MutexLocker lock(threadSetMutex());
77     workerThreads().add(this);
78 }
79
80 WorkerThread::~WorkerThread()
81 {
82     MutexLocker lock(threadSetMutex());
83     ASSERT(workerThreads().contains(this));
84     workerThreads().remove(this);
85 }
86
87 bool WorkerThread::start()
88 {
89     // Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts.
90     MutexLocker lock(m_threadCreationMutex);
91
92     if (m_threadID)
93         return true;
94
95     m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker");
96
97     return m_threadID;
98 }
99
100 void WorkerThread::workerThreadStart(void* thread)
101 {
102     static_cast<WorkerThread*>(thread)->workerThread();
103 }
104
105 void WorkerThread::workerThread()
106 {
107     KURL scriptURL = m_startupData->m_scriptURL;
108     String sourceCode = m_startupData->m_sourceCode;
109     WorkerThreadStartMode startMode = m_startupData->m_startMode;
110
111     {
112         MutexLocker lock(m_threadCreationMutex);
113         ThreadState::attach();
114         m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release());
115         m_runLoop.setWorkerGlobalScope(workerGlobalScope());
116
117         if (m_runLoop.terminated()) {
118             // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
119             // forbidExecution() couldn't be called from stop().
120             m_workerGlobalScope->script()->forbidExecution();
121         }
122     }
123     // The corresponding call to didStopWorkerRunLoop is in
124     // ~WorkerScriptController.
125     blink::Platform::current()->didStartWorkerRunLoop(blink::WebWorkerRunLoop(&m_runLoop));
126
127     // Notify proxy that a new WorkerGlobalScope has been created and started.
128     m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get());
129
130     WorkerScriptController* script = m_workerGlobalScope->script();
131     InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), startMode);
132     script->evaluate(ScriptSourceCode(sourceCode, scriptURL));
133
134     runEventLoop();
135
136     // This should be called before we start the shutdown procedure.
137     workerReportingProxy().willDestroyWorkerGlobalScope();
138
139     ThreadIdentifier threadID = m_threadID;
140
141     // The below assignment will destroy the context, which will in turn notify messaging proxy.
142     // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
143     // If Oilpan is enabled, we detach of the context/global scope, with the final heap cleanup below sweeping it out.
144 #if !ENABLE(OILPAN)
145     ASSERT(m_workerGlobalScope->hasOneRef());
146 #endif
147     m_workerGlobalScope->dispose();
148     m_workerGlobalScope = nullptr;
149
150     // Detach the ThreadState, cleaning out the thread's heap by
151     // performing a final GC. The cleanup operation will at the end
152     // assert that the heap is empty. If the heap does not become
153     // empty, there are still pointers into the heap and those
154     // pointers will be dangling after thread termination because we
155     // are destroying the heap. It is important to detach while the
156     // thread is still valid. In particular, finalizers for objects in
157     // the heap for this thread will need to access thread local data.
158     ThreadState::detach();
159
160     // Notify the proxy that the WorkerGlobalScope has been disposed of.
161     // This can free this thread object, hence it must not be touched afterwards.
162     workerReportingProxy().workerGlobalScopeDestroyed();
163
164     // Clean up PlatformThreadData before WTF::WTFThreadData goes away!
165     PlatformThreadData::current().destroy();
166
167     // The thread object may be already destroyed from notification now, don't try to access "this".
168     detachThread(threadID);
169 }
170
171 void WorkerThread::runEventLoop()
172 {
173     // Does not return until terminated.
174     m_runLoop.run();
175 }
176
177 class WorkerThreadShutdownFinishTask : public ExecutionContextTask {
178 public:
179     static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
180     {
181         return adoptPtr(new WorkerThreadShutdownFinishTask());
182     }
183
184     virtual void performTask(ExecutionContext *context)
185     {
186         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
187         workerGlobalScope->clearInspector();
188         // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
189         workerGlobalScope->clearScript();
190     }
191
192     virtual bool isCleanupTask() const { return true; }
193 };
194
195 class WorkerThreadShutdownStartTask : public ExecutionContextTask {
196 public:
197     static PassOwnPtr<WorkerThreadShutdownStartTask> create()
198     {
199         return adoptPtr(new WorkerThreadShutdownStartTask());
200     }
201
202     virtual void performTask(ExecutionContext *context)
203     {
204         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
205
206         workerGlobalScope->stopActiveDOMObjects();
207
208         // Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
209         // which become dangling once Heap is destroyed.
210         workerGlobalScope->removeAllEventListeners();
211
212         // Stick a shutdown command at the end of the queue, so that we deal
213         // with all the cleanup tasks the databases post first.
214         workerGlobalScope->postTask(WorkerThreadShutdownFinishTask::create());
215     }
216
217     virtual bool isCleanupTask() const { return true; }
218 };
219
220 void WorkerThread::stop()
221 {
222     // Prevent the deadlock between GC and an attempt to stop a thread.
223     ThreadState::SafePointScope safePointScope(ThreadState::HeapPointersOnStack);
224
225     // Mutex protection is necessary because stop() can be called before the context is fully created.
226     MutexLocker lock(m_threadCreationMutex);
227
228     // Signal the thread to notify that the thread's stopping.
229     if (m_shutdownEvent)
230         m_shutdownEvent->signal();
231
232     // 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.
233     if (m_workerGlobalScope) {
234         m_workerGlobalScope->script()->scheduleExecutionTermination();
235         m_workerGlobalScope->wasRequestedToTerminate();
236         m_runLoop.postTaskAndTerminate(WorkerThreadShutdownStartTask::create());
237         return;
238     }
239     m_runLoop.terminate();
240 }
241
242 bool WorkerThread::isCurrentThread() const
243 {
244     return m_threadID == currentThread();
245 }
246
247 } // namespace WebCore