Upstream version 9.38.198.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/core/v8/ScriptSourceCode.h"
32 #include "core/dom/Microtask.h"
33 #include "core/inspector/InspectorInstrumentation.h"
34 #include "core/inspector/WorkerInspectorController.h"
35 #include "core/workers/DedicatedWorkerGlobalScope.h"
36 #include "core/workers/WorkerClients.h"
37 #include "core/workers/WorkerReportingProxy.h"
38 #include "core/workers/WorkerThreadStartupData.h"
39 #include "platform/PlatformThreadData.h"
40 #include "platform/Task.h"
41 #include "platform/ThreadTimers.h"
42 #include "platform/heap/ThreadState.h"
43 #include "platform/weborigin/KURL.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebThread.h"
46 #include "public/platform/WebWaitableEvent.h"
47 #include "public/platform/WebWorkerRunLoop.h"
48 #include "wtf/Noncopyable.h"
49 #include "wtf/text/WTFString.h"
50
51 #include <utility>
52
53 namespace blink {
54
55 namespace {
56 const int64 kShortIdleHandlerDelayMs = 1000;
57 const int64 kLongIdleHandlerDelayMs = 10*1000;
58
59 class MicrotaskRunner : public WebThread::TaskObserver {
60 public:
61     virtual void willProcessTask() OVERRIDE { }
62     virtual void didProcessTask() OVERRIDE
63     {
64         Microtask::performCheckpoint();
65     }
66 };
67
68 } // namespace
69
70 static Mutex& threadSetMutex()
71 {
72     AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
73     return mutex;
74 }
75
76 static HashSet<WorkerThread*>& workerThreads()
77 {
78     DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ());
79     return threads;
80 }
81
82 unsigned WorkerThread::workerThreadCount()
83 {
84     MutexLocker lock(threadSetMutex());
85     return workerThreads().size();
86 }
87
88 class WorkerSharedTimer : public SharedTimer {
89 public:
90     explicit WorkerSharedTimer(WorkerThread* workerThread)
91         : m_workerThread(workerThread)
92         , m_nextFireTime(0.0)
93         , m_running(false)
94     { }
95
96     typedef void (*SharedTimerFunction)();
97     virtual void setFiredFunction(SharedTimerFunction func)
98     {
99         m_sharedTimerFunction = func;
100         if (!m_sharedTimerFunction)
101             m_nextFireTime = 0.0;
102     }
103
104     virtual void setFireInterval(double interval)
105     {
106         ASSERT(m_sharedTimerFunction);
107
108         // See BlinkPlatformImpl::setSharedTimerFireInterval for explanation of
109         // why ceil is used in the interval calculation.
110         int64 delay = static_cast<int64>(ceil(interval * 1000));
111
112         if (delay < 0) {
113             delay = 0;
114             m_nextFireTime = 0.0;
115         }
116
117         m_running = true;
118         m_nextFireTime = currentTime() + interval;
119         m_workerThread->postDelayedTask(createSameThreadTask(&WorkerSharedTimer::OnTimeout, this), delay);
120     }
121
122     virtual void stop()
123     {
124         m_running = false;
125     }
126
127     double nextFireTime() { return m_nextFireTime; }
128
129 private:
130     void OnTimeout()
131     {
132         ASSERT(m_workerThread->workerGlobalScope());
133         if (m_sharedTimerFunction && m_running && !m_workerThread->workerGlobalScope()->isClosing())
134             m_sharedTimerFunction();
135     }
136
137     WorkerThread* m_workerThread;
138     SharedTimerFunction m_sharedTimerFunction;
139     double m_nextFireTime;
140     bool m_running;
141 };
142
143 class WorkerThreadTask : public blink::WebThread::Task {
144     WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED;
145 public:
146     static PassOwnPtr<WorkerThreadTask> create(const WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
147     {
148         return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented));
149     }
150
151     virtual ~WorkerThreadTask() { }
152
153     virtual void run() OVERRIDE
154     {
155         WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope();
156         // Tasks could be put on the message loop after the cleanup task,
157         // ensure none of those are ran.
158         if (!workerGlobalScope)
159             return;
160
161         if (m_isInstrumented)
162             InspectorInstrumentation::willPerformExecutionContextTask(workerGlobalScope, m_task.get());
163         if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask())
164             m_task->performTask(workerGlobalScope);
165         if (m_isInstrumented)
166             InspectorInstrumentation::didPerformExecutionContextTask(workerGlobalScope);
167     }
168
169 private:
170     WorkerThreadTask(const WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
171         : m_workerThread(workerThread)
172         , m_task(task)
173         , m_isInstrumented(isInstrumented)
174     {
175         if (m_isInstrumented)
176             m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty();
177         if (m_isInstrumented)
178             InspectorInstrumentation::didPostExecutionContextTask(m_workerThread.workerGlobalScope(), m_task.get());
179     }
180
181     const WorkerThread& m_workerThread;
182     OwnPtr<ExecutionContextTask> m_task;
183     bool m_isInstrumented;
184 };
185
186 class RunDebuggerQueueTask FINAL : public ExecutionContextTask {
187 public:
188     static PassOwnPtr<RunDebuggerQueueTask> create(WorkerThread* thread)
189     {
190         return adoptPtr(new RunDebuggerQueueTask(thread));
191     }
192     virtual void performTask(ExecutionContext* context) OVERRIDE
193     {
194         ASSERT(context->isWorkerGlobalScope());
195         m_thread->runDebuggerTask(WorkerThread::DontWaitForMessage);
196     }
197
198 private:
199     explicit RunDebuggerQueueTask(WorkerThread* thread) : m_thread(thread) { }
200
201     WorkerThread* m_thread;
202 };
203
204 WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> startupData)
205     : m_terminated(false)
206     , m_workerLoaderProxy(workerLoaderProxy)
207     , m_workerReportingProxy(workerReportingProxy)
208     , m_startupData(startupData)
209     , m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent()))
210 {
211     MutexLocker lock(threadSetMutex());
212     workerThreads().add(this);
213 }
214
215 WorkerThread::~WorkerThread()
216 {
217     MutexLocker lock(threadSetMutex());
218     ASSERT(workerThreads().contains(this));
219     workerThreads().remove(this);
220 }
221
222 void WorkerThread::start()
223 {
224     if (m_thread)
225         return;
226
227     m_thread = adoptPtr(blink::Platform::current()->createThread("WebCore: Worker"));
228     m_thread->postTask(new Task(WTF::bind(&WorkerThread::initialize, this)));
229 }
230
231 void WorkerThread::interruptAndDispatchInspectorCommands()
232 {
233     MutexLocker locker(m_workerInspectorControllerMutex);
234     if (m_workerInspectorController)
235         m_workerInspectorController->interruptAndDispatchInspectorCommands();
236 }
237
238 void WorkerThread::initialize()
239 {
240     KURL scriptURL = m_startupData->m_scriptURL;
241     String sourceCode = m_startupData->m_sourceCode;
242     WorkerThreadStartMode startMode = m_startupData->m_startMode;
243
244     {
245         MutexLocker lock(m_threadCreationMutex);
246
247         // The worker was terminated before the thread had a chance to run.
248         if (m_terminated) {
249             // Notify the proxy that the WorkerGlobalScope has been disposed of.
250             // This can free this thread object, hence it must not be touched afterwards.
251             m_workerReportingProxy.workerThreadTerminated();
252             return;
253         }
254
255         m_microtaskRunner = adoptPtr(new MicrotaskRunner);
256         m_thread->addTaskObserver(m_microtaskRunner.get());
257         m_pendingGCRunner = adoptPtr(new PendingGCRunner);
258         m_messageLoopInterruptor = adoptPtr(new MessageLoopInterruptor(m_thread.get()));
259         m_thread->addTaskObserver(m_pendingGCRunner.get());
260         ThreadState::attach();
261         ThreadState::current()->addInterruptor(m_messageLoopInterruptor.get());
262         m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release());
263
264         m_sharedTimer = adoptPtr(new WorkerSharedTimer(this));
265         PlatformThreadData::current().threadTimers().setSharedTimer(m_sharedTimer.get());
266     }
267
268     // The corresponding call to didStopWorkerRunLoop is in
269     // ~WorkerScriptController.
270     blink::Platform::current()->didStartWorkerRunLoop(blink::WebWorkerRunLoop(this));
271
272     // Notify proxy that a new WorkerGlobalScope has been created and started.
273     m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get());
274
275     WorkerScriptController* script = m_workerGlobalScope->script();
276     if (!script->isExecutionForbidden())
277         script->initializeContextIfNeeded();
278     InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), startMode);
279     script->evaluate(ScriptSourceCode(sourceCode, scriptURL));
280
281     postInitialize();
282
283     postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), kShortIdleHandlerDelayMs);
284 }
285
286 void WorkerThread::cleanup()
287 {
288
289     // This should be called before we start the shutdown procedure.
290     workerReportingProxy().willDestroyWorkerGlobalScope();
291
292     // The below assignment will destroy the context, which will in turn notify messaging proxy.
293     // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
294     // If Oilpan is enabled, we detach of the context/global scope, with the final heap cleanup below sweeping it out.
295 #if !ENABLE(OILPAN)
296     ASSERT(m_workerGlobalScope->hasOneRef());
297 #endif
298     m_workerGlobalScope->dispose();
299     m_workerGlobalScope = nullptr;
300
301     ThreadState::current()->removeInterruptor(m_messageLoopInterruptor.get());
302
303     // Detach the ThreadState, cleaning out the thread's heap by
304     // performing a final GC. The cleanup operation will at the end
305     // assert that the heap is empty. If the heap does not become
306     // empty, there are still pointers into the heap and those
307     // pointers will be dangling after thread termination because we
308     // are destroying the heap. It is important to detach while the
309     // thread is still valid. In particular, finalizers for objects in
310     // the heap for this thread will need to access thread local data.
311     ThreadState::detach();
312
313     m_thread->removeTaskObserver(m_microtaskRunner.get());
314     m_microtaskRunner = nullptr;
315     m_thread->removeTaskObserver(m_pendingGCRunner.get());
316     m_pendingGCRunner = nullptr;
317     m_messageLoopInterruptor = nullptr;
318
319     // Notify the proxy that the WorkerGlobalScope has been disposed of.
320     // This can free this thread object, hence it must not be touched afterwards.
321     workerReportingProxy().workerThreadTerminated();
322
323     // Clean up PlatformThreadData before WTF::WTFThreadData goes away!
324     PlatformThreadData::current().destroy();
325 }
326
327 class WorkerThreadShutdownFinishTask : public ExecutionContextTask {
328 public:
329     static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
330     {
331         return adoptPtr(new WorkerThreadShutdownFinishTask());
332     }
333
334     virtual void performTask(ExecutionContext *context)
335     {
336         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
337         workerGlobalScope->clearInspector();
338         // It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
339         workerGlobalScope->clearScript();
340         workerGlobalScope->thread()->m_thread->postTask(new Task(WTF::bind(&WorkerThread::cleanup, workerGlobalScope->thread())));
341     }
342
343     virtual bool isCleanupTask() const { return true; }
344 };
345
346 class WorkerThreadShutdownStartTask : public ExecutionContextTask {
347 public:
348     static PassOwnPtr<WorkerThreadShutdownStartTask> create()
349     {
350         return adoptPtr(new WorkerThreadShutdownStartTask());
351     }
352
353     virtual void performTask(ExecutionContext *context)
354     {
355         WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
356         workerGlobalScope->stopFetch();
357         workerGlobalScope->stopActiveDOMObjects();
358         PlatformThreadData::current().threadTimers().setSharedTimer(nullptr);
359
360         // Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
361         // which become dangling once Heap is destroyed.
362         workerGlobalScope->removeAllEventListeners();
363
364         // Stick a shutdown command at the end of the queue, so that we deal
365         // with all the cleanup tasks the databases post first.
366         workerGlobalScope->postTask(WorkerThreadShutdownFinishTask::create());
367     }
368
369     virtual bool isCleanupTask() const { return true; }
370 };
371
372 void WorkerThread::stop()
373 {
374     // Prevent the deadlock between GC and an attempt to stop a thread.
375     ThreadState::SafePointScope safePointScope(ThreadState::HeapPointersOnStack);
376
377     // Protect against this method and initialize() racing each other.
378     MutexLocker lock(m_threadCreationMutex);
379
380     // If stop has already been called, just return.
381     if (m_terminated)
382         return;
383     m_terminated = true;
384
385     // Signal the thread to notify that the thread's stopping.
386     if (m_shutdownEvent)
387         m_shutdownEvent->signal();
388
389     if (!m_workerGlobalScope)
390         return;
391
392     // 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.
393     m_workerGlobalScope->script()->scheduleExecutionTermination();
394     m_workerGlobalScope->wasRequestedToTerminate();
395     InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScope.get());
396     m_debuggerMessageQueue.kill();
397     postTask(WorkerThreadShutdownStartTask::create());
398 }
399
400 bool WorkerThread::isCurrentThread() const
401 {
402     return m_thread && m_thread->isCurrentThread();
403 }
404
405 void WorkerThread::idleHandler()
406 {
407     ASSERT(m_workerGlobalScope.get());
408     int64 delay = kLongIdleHandlerDelayMs;
409
410     // Do a script engine idle notification if the next event is distant enough.
411     const double kMinIdleTimespan = 0.3;
412     if (m_sharedTimer->nextFireTime() == 0.0 || m_sharedTimer->nextFireTime() > currentTime() + kMinIdleTimespan) {
413         bool hasMoreWork = !m_workerGlobalScope->idleNotification();
414         if (hasMoreWork)
415             delay = kShortIdleHandlerDelayMs;
416     }
417
418     postDelayedTask(createSameThreadTask(&WorkerThread::idleHandler, this), delay);
419 }
420
421 void WorkerThread::postTask(PassOwnPtr<ExecutionContextTask> task)
422 {
423     m_thread->postTask(WorkerThreadTask::create(*this, task, true).leakPtr());
424 }
425
426 void WorkerThread::postDelayedTask(PassOwnPtr<ExecutionContextTask> task, long long delayMs)
427 {
428     m_thread->postDelayedTask(WorkerThreadTask::create(*this, task, true).leakPtr(), delayMs);
429 }
430
431 void WorkerThread::postDebuggerTask(PassOwnPtr<ExecutionContextTask> task)
432 {
433     m_debuggerMessageQueue.append(WorkerThreadTask::create(*this, task, false));
434     postTask(RunDebuggerQueueTask::create(this));
435 }
436
437 MessageQueueWaitResult WorkerThread::runDebuggerTask(WaitMode waitMode)
438 {
439     ASSERT(isCurrentThread());
440     MessageQueueWaitResult result;
441     double absoluteTime = MessageQueue<blink::WebThread::Task>::infiniteTime();
442     OwnPtr<blink::WebThread::Task> task;
443     {
444         if (waitMode == DontWaitForMessage)
445             absoluteTime = 0.0;
446         ThreadState::SafePointScope safePointScope(ThreadState::NoHeapPointersOnStack);
447         task = m_debuggerMessageQueue.waitForMessageWithTimeout(result, absoluteTime);
448     }
449
450     if (result == MessageQueueMessageReceived) {
451         InspectorInstrumentation::willProcessTask(workerGlobalScope());
452         task->run();
453         InspectorInstrumentation::didProcessTask(workerGlobalScope());
454     }
455
456     return result;
457 }
458
459 void WorkerThread::willEnterNestedLoop()
460 {
461     InspectorInstrumentation::willEnterNestedRunLoop(m_workerGlobalScope.get());
462 }
463
464 void WorkerThread::didLeaveNestedLoop()
465 {
466     InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get());
467 }
468
469 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* workerInspectorController)
470 {
471     MutexLocker locker(m_workerInspectorControllerMutex);
472     m_workerInspectorController = workerInspectorController;
473 }
474
475 } // namespace blink