OLD | NEW |
| (Empty) |
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 "bindings/core/v8/V8GCController.h" | |
33 #include "bindings/core/v8/V8Initializer.h" | |
34 #include "core/dom/Microtask.h" | |
35 #include "core/inspector/InspectorInstrumentation.h" | |
36 #include "core/inspector/WorkerInspectorController.h" | |
37 #include "core/workers/DedicatedWorkerGlobalScope.h" | |
38 #include "core/workers/WorkerClients.h" | |
39 #include "core/workers/WorkerReportingProxy.h" | |
40 #include "core/workers/WorkerThreadStartupData.h" | |
41 #include "platform/PlatformThreadData.h" | |
42 #include "platform/Task.h" | |
43 #include "platform/ThreadSafeFunctional.h" | |
44 #include "platform/ThreadTimers.h" | |
45 #include "platform/heap/SafePoint.h" | |
46 #include "platform/heap/ThreadState.h" | |
47 #include "platform/weborigin/KURL.h" | |
48 #include "public/platform/Platform.h" | |
49 #include "public/platform/WebThread.h" | |
50 #include "public/platform/WebWaitableEvent.h" | |
51 #include "wtf/Noncopyable.h" | |
52 #include "wtf/WeakPtr.h" | |
53 #include "wtf/text/WTFString.h" | |
54 | |
55 namespace blink { | |
56 | |
57 namespace { | |
58 const int64_t kShortIdleHandlerDelayMs = 1000; | |
59 const int64_t kLongIdleHandlerDelayMs = 10*1000; | |
60 | |
61 class MicrotaskRunner : public WebThread::TaskObserver { | |
62 public: | |
63 explicit MicrotaskRunner(WorkerThread* workerThread) | |
64 : m_workerThread(workerThread) | |
65 { | |
66 } | |
67 | |
68 virtual void willProcessTask() override { } | |
69 virtual void didProcessTask() override | |
70 { | |
71 Microtask::performCheckpoint(); | |
72 if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope()
) { | |
73 if (WorkerScriptController* scriptController = globalScope->script()
) | |
74 scriptController->rejectedPromises()->processQueue(); | |
75 } | |
76 } | |
77 | |
78 private: | |
79 // Thread owns the microtask runner; reference remains | |
80 // valid for the lifetime of this object. | |
81 WorkerThread* m_workerThread; | |
82 }; | |
83 | |
84 } // namespace | |
85 | |
86 static Mutex& threadSetMutex() | |
87 { | |
88 AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex); | |
89 return mutex; | |
90 } | |
91 | |
92 static HashSet<WorkerThread*>& workerThreads() | |
93 { | |
94 DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ()); | |
95 return threads; | |
96 } | |
97 | |
98 unsigned WorkerThread::workerThreadCount() | |
99 { | |
100 MutexLocker lock(threadSetMutex()); | |
101 return workerThreads().size(); | |
102 } | |
103 | |
104 class WorkerThreadCancelableTask final : public ExecutionContextTask { | |
105 WTF_MAKE_NONCOPYABLE(WorkerThreadCancelableTask); WTF_MAKE_FAST_ALLOCATED(Wo
rkerThreadCancelableTask); | |
106 public: | |
107 static PassOwnPtr<WorkerThreadCancelableTask> create(PassOwnPtr<Closure> clo
sure) | |
108 { | |
109 return adoptPtr(new WorkerThreadCancelableTask(closure)); | |
110 } | |
111 | |
112 virtual ~WorkerThreadCancelableTask() { } | |
113 | |
114 virtual void performTask(ExecutionContext*) override | |
115 { | |
116 if (!m_taskCanceled) | |
117 (*m_closure)(); | |
118 } | |
119 | |
120 WeakPtr<WorkerThreadCancelableTask> createWeakPtr() { return m_weakFactory.c
reateWeakPtr(); } | |
121 void cancelTask() { m_taskCanceled = true; } | |
122 | |
123 private: | |
124 explicit WorkerThreadCancelableTask(PassOwnPtr<Closure> closure) | |
125 : m_closure(closure) | |
126 , m_weakFactory(this) | |
127 , m_taskCanceled(false) | |
128 { } | |
129 | |
130 OwnPtr<Closure> m_closure; | |
131 WeakPtrFactory<WorkerThreadCancelableTask> m_weakFactory; | |
132 bool m_taskCanceled; | |
133 }; | |
134 | |
135 class WorkerSharedTimer : public SharedTimer { | |
136 public: | |
137 explicit WorkerSharedTimer(WorkerThread* workerThread) | |
138 : m_workerThread(workerThread) | |
139 , m_running(false) | |
140 { } | |
141 | |
142 typedef void (*SharedTimerFunction)(); | |
143 virtual void setFiredFunction(SharedTimerFunction func) | |
144 { | |
145 m_sharedTimerFunction = func; | |
146 } | |
147 | |
148 virtual void setFireInterval(double interval) | |
149 { | |
150 ASSERT(m_sharedTimerFunction); | |
151 | |
152 // See BlinkPlatformImpl::setSharedTimerFireInterval for explanation of | |
153 // why ceil is used in the interval calculation. | |
154 int64_t delay = static_cast<int64_t>(ceil(interval * 1000)); | |
155 | |
156 if (delay < 0) { | |
157 delay = 0; | |
158 } | |
159 | |
160 m_running = true; | |
161 | |
162 if (m_lastQueuedTask.get()) | |
163 m_lastQueuedTask->cancelTask(); | |
164 | |
165 // Now queue the task as a cancellable one. | |
166 OwnPtr<WorkerThreadCancelableTask> task = WorkerThreadCancelableTask::cr
eate(bind(&WorkerSharedTimer::OnTimeout, this)); | |
167 m_lastQueuedTask = task->createWeakPtr(); | |
168 m_workerThread->postDelayedTask(FROM_HERE, task.release(), delay); | |
169 } | |
170 | |
171 virtual void stop() | |
172 { | |
173 m_running = false; | |
174 m_lastQueuedTask = nullptr; | |
175 } | |
176 | |
177 private: | |
178 void OnTimeout() | |
179 { | |
180 ASSERT(m_workerThread->workerGlobalScope()); | |
181 | |
182 m_lastQueuedTask = nullptr; | |
183 | |
184 if (m_sharedTimerFunction && m_running && !m_workerThread->workerGlobalS
cope()->isClosing()) | |
185 m_sharedTimerFunction(); | |
186 } | |
187 | |
188 WorkerThread* m_workerThread; | |
189 SharedTimerFunction m_sharedTimerFunction; | |
190 bool m_running; | |
191 | |
192 // The task to run OnTimeout, if any. While OnTimeout resets | |
193 // m_lastQueuedTask, this must be a weak pointer because the | |
194 // worker runloop may delete the task as it is shutting down. | |
195 WeakPtr<WorkerThreadCancelableTask> m_lastQueuedTask; | |
196 }; | |
197 | |
198 class WorkerThreadTask : public WebThread::Task { | |
199 WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED(WorkerThread
Task); | |
200 public: | |
201 static PassOwnPtr<WorkerThreadTask> create(WorkerThread& workerThread, PassO
wnPtr<ExecutionContextTask> task, bool isInstrumented) | |
202 { | |
203 return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented)
); | |
204 } | |
205 | |
206 virtual ~WorkerThreadTask() { } | |
207 | |
208 virtual void run() override | |
209 { | |
210 WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope(
); | |
211 // Tasks could be put on the message loop after the cleanup task, | |
212 // ensure none of those are ran. | |
213 if (!workerGlobalScope) | |
214 return; | |
215 | |
216 if (m_isInstrumented) | |
217 InspectorInstrumentation::willPerformExecutionContextTask(workerGlob
alScope, m_task.get()); | |
218 if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) ||
m_task->isCleanupTask()) | |
219 m_task->performTask(workerGlobalScope); | |
220 if (m_isInstrumented) | |
221 InspectorInstrumentation::didPerformExecutionContextTask(workerGloba
lScope); | |
222 } | |
223 | |
224 private: | |
225 WorkerThreadTask(WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask
> task, bool isInstrumented) | |
226 : m_workerThread(workerThread) | |
227 , m_task(task) | |
228 , m_isInstrumented(isInstrumented) | |
229 { | |
230 if (m_isInstrumented) | |
231 m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty(); | |
232 if (m_isInstrumented) | |
233 InspectorInstrumentation::didPostExecutionContextTask(m_workerThread
.workerGlobalScope(), m_task.get()); | |
234 } | |
235 | |
236 WorkerThread& m_workerThread; | |
237 OwnPtr<ExecutionContextTask> m_task; | |
238 bool m_isInstrumented; | |
239 }; | |
240 | |
241 class RunDebuggerQueueTask final : public ExecutionContextTask { | |
242 public: | |
243 static PassOwnPtr<RunDebuggerQueueTask> create(WorkerThread* thread) | |
244 { | |
245 return adoptPtr(new RunDebuggerQueueTask(thread)); | |
246 } | |
247 virtual void performTask(ExecutionContext* context) override | |
248 { | |
249 ASSERT(context->isWorkerGlobalScope()); | |
250 m_thread->runDebuggerTask(WorkerThread::DontWaitForMessage); | |
251 } | |
252 | |
253 private: | |
254 explicit RunDebuggerQueueTask(WorkerThread* thread) : m_thread(thread) { } | |
255 | |
256 WorkerThread* m_thread; | |
257 }; | |
258 | |
259 WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, Work
erReportingProxy& workerReportingProxy, PassOwnPtr<WorkerThreadStartupData> star
tupData) | |
260 : m_started(false) | |
261 , m_terminated(false) | |
262 , m_workerLoaderProxy(workerLoaderProxy) | |
263 , m_workerReportingProxy(workerReportingProxy) | |
264 , m_startupData(startupData) | |
265 , m_isolate(nullptr) | |
266 , m_shutdownEvent(adoptPtr(Platform::current()->createWaitableEvent())) | |
267 , m_terminationEvent(adoptPtr(Platform::current()->createWaitableEvent())) | |
268 { | |
269 MutexLocker lock(threadSetMutex()); | |
270 workerThreads().add(this); | |
271 } | |
272 | |
273 WorkerThread::~WorkerThread() | |
274 { | |
275 MutexLocker lock(threadSetMutex()); | |
276 ASSERT(workerThreads().contains(this)); | |
277 workerThreads().remove(this); | |
278 } | |
279 | |
280 void WorkerThread::start() | |
281 { | |
282 if (m_started) | |
283 return; | |
284 | |
285 m_started = true; | |
286 backingThread().postTask(FROM_HERE, new Task(threadSafeBind(&WorkerThread::i
nitialize, AllowCrossThreadAccess(this)))); | |
287 } | |
288 | |
289 void WorkerThread::interruptAndDispatchInspectorCommands() | |
290 { | |
291 MutexLocker locker(m_workerInspectorControllerMutex); | |
292 if (m_workerInspectorController) | |
293 m_workerInspectorController->interruptAndDispatchInspectorCommands(); | |
294 } | |
295 | |
296 PlatformThreadId WorkerThread::platformThreadId() | |
297 { | |
298 if (!m_started) | |
299 return 0; | |
300 return backingThread().platformThread().threadId(); | |
301 } | |
302 | |
303 void WorkerThread::initialize() | |
304 { | |
305 KURL scriptURL = m_startupData->m_scriptURL; | |
306 String sourceCode = m_startupData->m_sourceCode; | |
307 WorkerThreadStartMode startMode = m_startupData->m_startMode; | |
308 OwnPtr<Vector<char>> cachedMetaData = m_startupData->m_cachedMetaData.releas
e(); | |
309 V8CacheOptions v8CacheOptions = m_startupData->m_v8CacheOptions; | |
310 | |
311 { | |
312 MutexLocker lock(m_threadCreationMutex); | |
313 | |
314 // The worker was terminated before the thread had a chance to run. | |
315 if (m_terminated) { | |
316 // Notify the proxy that the WorkerGlobalScope has been disposed of. | |
317 // This can free this thread object, hence it must not be touched af
terwards. | |
318 m_workerReportingProxy.workerThreadTerminated(); | |
319 return; | |
320 } | |
321 | |
322 m_microtaskRunner = adoptPtr(new MicrotaskRunner(this)); | |
323 backingThread().addTaskObserver(m_microtaskRunner.get()); | |
324 backingThread().attachGC(); | |
325 | |
326 m_isolate = initializeIsolate(); | |
327 m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release()); | |
328 m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.ge
t() ? cachedMetaData->size() : 0); | |
329 | |
330 PlatformThreadData::current().threadTimers().setSharedTimer(adoptPtr(new
WorkerSharedTimer(this))); | |
331 } | |
332 | |
333 // The corresponding call to stopRunLoop() is in ~WorkerScriptController(). | |
334 didStartRunLoop(); | |
335 | |
336 // Notify proxy that a new WorkerGlobalScope has been created and started. | |
337 m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get()); | |
338 | |
339 WorkerScriptController* script = m_workerGlobalScope->script(); | |
340 if (!script->isExecutionForbidden()) | |
341 script->initializeContextIfNeeded(); | |
342 if (startMode == PauseWorkerGlobalScopeOnStart) | |
343 m_workerGlobalScope->workerInspectorController()->pauseOnStart(); | |
344 | |
345 OwnPtr<CachedMetadataHandler> handler(workerGlobalScope()->createWorkerScrip
tCachedMetadataHandler(scriptURL, cachedMetaData.get())); | |
346 bool success = script->evaluate(ScriptSourceCode(sourceCode, scriptURL), nul
lptr, handler.get(), v8CacheOptions); | |
347 m_workerGlobalScope->didEvaluateWorkerScript(); | |
348 m_workerReportingProxy.didEvaluateWorkerScript(success); | |
349 | |
350 postInitialize(); | |
351 | |
352 postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler,
this), kShortIdleHandlerDelayMs); | |
353 } | |
354 | |
355 void WorkerThread::cleanup() | |
356 { | |
357 // This should be called before we start the shutdown procedure. | |
358 workerReportingProxy().willDestroyWorkerGlobalScope(); | |
359 | |
360 // The below assignment will destroy the context, which will in turn notify
messaging proxy. | |
361 // We cannot let any objects survive past thread exit, because no other thre
ad will run GC or otherwise destroy them. | |
362 // If Oilpan is enabled, we detach of the context/global scope, with the fin
al heap cleanup below sweeping it out. | |
363 #if !ENABLE(OILPAN) | |
364 ASSERT(m_workerGlobalScope->hasOneRef()); | |
365 #endif | |
366 m_workerGlobalScope->notifyContextDestroyed(); | |
367 m_workerGlobalScope = nullptr; | |
368 | |
369 backingThread().detachGC(); | |
370 destroyIsolate(); | |
371 | |
372 backingThread().removeTaskObserver(m_microtaskRunner.get()); | |
373 m_microtaskRunner = nullptr; | |
374 | |
375 // Notify the proxy that the WorkerGlobalScope has been disposed of. | |
376 // This can free this thread object, hence it must not be touched afterwards
. | |
377 workerReportingProxy().workerThreadTerminated(); | |
378 | |
379 m_terminationEvent->signal(); | |
380 | |
381 // Clean up PlatformThreadData before WTF::WTFThreadData goes away! | |
382 PlatformThreadData::current().destroy(); | |
383 } | |
384 | |
385 class WorkerThreadShutdownFinishTask : public ExecutionContextTask { | |
386 public: | |
387 static PassOwnPtr<WorkerThreadShutdownFinishTask> create() | |
388 { | |
389 return adoptPtr(new WorkerThreadShutdownFinishTask()); | |
390 } | |
391 | |
392 virtual void performTask(ExecutionContext *context) | |
393 { | |
394 WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); | |
395 workerGlobalScope->dispose(); | |
396 | |
397 WorkerThread* workerThread = workerGlobalScope->thread(); | |
398 workerThread->willDestroyIsolate(); | |
399 workerThread->backingThread().postTask(FROM_HERE, new Task(WTF::bind(&Wo
rkerThread::cleanup, workerThread))); | |
400 } | |
401 | |
402 virtual bool isCleanupTask() const { return true; } | |
403 }; | |
404 | |
405 class WorkerThreadShutdownStartTask : public ExecutionContextTask { | |
406 public: | |
407 static PassOwnPtr<WorkerThreadShutdownStartTask> create() | |
408 { | |
409 return adoptPtr(new WorkerThreadShutdownStartTask()); | |
410 } | |
411 | |
412 virtual void performTask(ExecutionContext *context) | |
413 { | |
414 WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context); | |
415 workerGlobalScope->stopActiveDOMObjects(); | |
416 PlatformThreadData::current().threadTimers().setSharedTimer(nullptr); | |
417 | |
418 // Event listeners would keep DOMWrapperWorld objects alive for too long
. Also, they have references to JS objects, | |
419 // which become dangling once Heap is destroyed. | |
420 workerGlobalScope->removeAllEventListeners(); | |
421 | |
422 // Stick a shutdown command at the end of the queue, so that we deal | |
423 // with all the cleanup tasks the databases post first. | |
424 workerGlobalScope->postTask(FROM_HERE, WorkerThreadShutdownFinishTask::c
reate()); | |
425 } | |
426 | |
427 virtual bool isCleanupTask() const { return true; } | |
428 }; | |
429 | |
430 void WorkerThread::stop() | |
431 { | |
432 // Prevent the deadlock between GC and an attempt to stop a thread. | |
433 SafePointScope safePointScope(ThreadState::HeapPointersOnStack); | |
434 stopInternal(); | |
435 } | |
436 | |
437 void WorkerThread::stopInShutdownSequence() | |
438 { | |
439 stopInternal(); | |
440 } | |
441 | |
442 void WorkerThread::terminateAndWait() | |
443 { | |
444 stop(); | |
445 m_terminationEvent->wait(); | |
446 } | |
447 | |
448 bool WorkerThread::terminated() | |
449 { | |
450 MutexLocker lock(m_threadCreationMutex); | |
451 return m_terminated; | |
452 } | |
453 | |
454 void WorkerThread::stopInternal() | |
455 { | |
456 // Protect against this method and initialize() racing each other. | |
457 MutexLocker lock(m_threadCreationMutex); | |
458 | |
459 // If stop has already been called, just return. | |
460 if (m_terminated) | |
461 return; | |
462 m_terminated = true; | |
463 | |
464 // Signal the thread to notify that the thread's stopping. | |
465 if (m_shutdownEvent) | |
466 m_shutdownEvent->signal(); | |
467 | |
468 if (!m_workerGlobalScope) | |
469 return; | |
470 | |
471 // Ensure that tasks are being handled by thread event loop. If script execu
tion weren't forbidden, a while(1) loop in JS could keep the thread alive foreve
r. | |
472 terminateV8Execution(); | |
473 | |
474 InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScop
e.get()); | |
475 m_debuggerMessageQueue.kill(); | |
476 postTask(FROM_HERE, WorkerThreadShutdownStartTask::create()); | |
477 } | |
478 | |
479 void WorkerThread::didStartRunLoop() | |
480 { | |
481 ASSERT(isCurrentThread()); | |
482 Platform::current()->didStartWorkerRunLoop(); | |
483 } | |
484 | |
485 void WorkerThread::didStopRunLoop() | |
486 { | |
487 ASSERT(isCurrentThread()); | |
488 Platform::current()->didStopWorkerRunLoop(); | |
489 } | |
490 | |
491 void WorkerThread::terminateAndWaitForAllWorkers() | |
492 { | |
493 // Keep this lock to prevent WorkerThread instances from being destroyed. | |
494 MutexLocker lock(threadSetMutex()); | |
495 HashSet<WorkerThread*> threads = workerThreads(); | |
496 for (WorkerThread* thread : threads) | |
497 thread->stopInShutdownSequence(); | |
498 | |
499 for (WorkerThread* thread : threads) | |
500 thread->terminationEvent()->wait(); | |
501 } | |
502 | |
503 bool WorkerThread::isCurrentThread() | |
504 { | |
505 return m_started && backingThread().isCurrentThread(); | |
506 } | |
507 | |
508 void WorkerThread::idleHandler() | |
509 { | |
510 ASSERT(m_workerGlobalScope.get()); | |
511 int64_t delay = kLongIdleHandlerDelayMs; | |
512 | |
513 // Do a script engine idle notification if the next event is distant enough. | |
514 const double kMinIdleTimespan = 0.3; | |
515 const double nextFireTime = PlatformThreadData::current().threadTimers().nex
tFireTime(); | |
516 if (nextFireTime == 0.0 || nextFireTime > currentTime() + kMinIdleTimespan)
{ | |
517 bool hasMoreWork = !isolate()->IdleNotificationDeadline(Platform::curren
t()->monotonicallyIncreasingTime() + 1.0); | |
518 if (hasMoreWork) | |
519 delay = kShortIdleHandlerDelayMs; | |
520 } | |
521 | |
522 postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler,
this), delay); | |
523 } | |
524 | |
525 void WorkerThread::postTask(const WebTraceLocation& location, PassOwnPtr<Executi
onContextTask> task) | |
526 { | |
527 backingThread().postTask(location, WorkerThreadTask::create(*this, task, tru
e).leakPtr()); | |
528 } | |
529 | |
530 void WorkerThread::postDelayedTask(const WebTraceLocation& location, PassOwnPtr<
ExecutionContextTask> task, long long delayMs) | |
531 { | |
532 backingThread().postDelayedTask(location, WorkerThreadTask::create(*this, ta
sk, true).leakPtr(), delayMs); | |
533 } | |
534 | |
535 v8::Isolate* WorkerThread::initializeIsolate() | |
536 { | |
537 ASSERT(isCurrentThread()); | |
538 ASSERT(!m_isolate); | |
539 v8::Isolate* isolate = V8PerIsolateData::initialize(); | |
540 V8Initializer::initializeWorker(isolate); | |
541 | |
542 m_interruptor = adoptPtr(new V8IsolateInterruptor(isolate)); | |
543 ThreadState::current()->addInterruptor(m_interruptor.get()); | |
544 ThreadState::current()->registerTraceDOMWrappers(isolate, V8GCController::tr
aceDOMWrappers); | |
545 | |
546 return isolate; | |
547 } | |
548 | |
549 void WorkerThread::willDestroyIsolate() | |
550 { | |
551 ASSERT(isCurrentThread()); | |
552 ASSERT(m_isolate); | |
553 V8PerIsolateData::willBeDestroyed(m_isolate); | |
554 ThreadState::current()->removeInterruptor(m_interruptor.get()); | |
555 } | |
556 | |
557 void WorkerThread::destroyIsolate() | |
558 { | |
559 ASSERT(isCurrentThread()); | |
560 V8PerIsolateData::destroy(m_isolate); | |
561 m_isolate = nullptr; | |
562 } | |
563 | |
564 void WorkerThread::terminateV8Execution() | |
565 { | |
566 ASSERT(isMainThread()); | |
567 m_workerGlobalScope->script()->willScheduleExecutionTermination(); | |
568 v8::V8::TerminateExecution(m_isolate); | |
569 } | |
570 | |
571 void WorkerThread::postDebuggerTask(const WebTraceLocation& location, PassOwnPtr
<ExecutionContextTask> task) | |
572 { | |
573 m_debuggerMessageQueue.append(WorkerThreadTask::create(*this, task, false)); | |
574 postTask(location, RunDebuggerQueueTask::create(this)); | |
575 } | |
576 | |
577 MessageQueueWaitResult WorkerThread::runDebuggerTask(WaitMode waitMode) | |
578 { | |
579 ASSERT(isCurrentThread()); | |
580 MessageQueueWaitResult result; | |
581 double absoluteTime = MessageQueue<WebThread::Task>::infiniteTime(); | |
582 OwnPtr<WebThread::Task> task; | |
583 { | |
584 if (waitMode == DontWaitForMessage) | |
585 absoluteTime = 0.0; | |
586 SafePointScope safePointScope(ThreadState::NoHeapPointersOnStack); | |
587 task = m_debuggerMessageQueue.waitForMessageWithTimeout(result, absolute
Time); | |
588 } | |
589 | |
590 if (result == MessageQueueMessageReceived) { | |
591 InspectorInstrumentation::willProcessTask(workerGlobalScope()); | |
592 task->run(); | |
593 InspectorInstrumentation::didProcessTask(workerGlobalScope()); | |
594 } | |
595 | |
596 return result; | |
597 } | |
598 | |
599 void WorkerThread::willEnterNestedLoop() | |
600 { | |
601 InspectorInstrumentation::willEnterNestedRunLoop(m_workerGlobalScope.get()); | |
602 } | |
603 | |
604 void WorkerThread::didLeaveNestedLoop() | |
605 { | |
606 InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get()); | |
607 } | |
608 | |
609 void WorkerThread::setWorkerInspectorController(WorkerInspectorController* worke
rInspectorController) | |
610 { | |
611 MutexLocker locker(m_workerInspectorControllerMutex); | |
612 m_workerInspectorController = workerInspectorController; | |
613 } | |
614 | |
615 } // namespace blink | |
OLD | NEW |