OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 13 matching lines...) Expand all Loading... | |
24 * | 24 * |
25 */ | 25 */ |
26 | 26 |
27 #include "core/workers/WorkerThread.h" | 27 #include "core/workers/WorkerThread.h" |
28 | 28 |
29 #include <limits.h> | 29 #include <limits.h> |
30 #include <memory> | 30 #include <memory> |
31 #include "bindings/core/v8/Microtask.h" | 31 #include "bindings/core/v8/Microtask.h" |
32 #include "bindings/core/v8/ScriptSourceCode.h" | 32 #include "bindings/core/v8/ScriptSourceCode.h" |
33 #include "bindings/core/v8/WorkerOrWorkletScriptController.h" | 33 #include "bindings/core/v8/WorkerOrWorkletScriptController.h" |
34 #include "core/dom/TaskRunnerHelper.h" | |
34 #include "core/inspector/ConsoleMessageStorage.h" | 35 #include "core/inspector/ConsoleMessageStorage.h" |
35 #include "core/inspector/InspectorTaskRunner.h" | 36 #include "core/inspector/InspectorTaskRunner.h" |
36 #include "core/inspector/WorkerInspectorController.h" | 37 #include "core/inspector/WorkerInspectorController.h" |
37 #include "core/inspector/WorkerThreadDebugger.h" | 38 #include "core/inspector/WorkerThreadDebugger.h" |
38 #include "core/origin_trials/OriginTrialContext.h" | 39 #include "core/origin_trials/OriginTrialContext.h" |
39 #include "core/probe/CoreProbes.h" | 40 #include "core/probe/CoreProbes.h" |
40 #include "core/workers/ThreadedWorkletGlobalScope.h" | 41 #include "core/workers/ThreadedWorkletGlobalScope.h" |
41 #include "core/workers/WorkerBackingThread.h" | 42 #include "core/workers/WorkerBackingThread.h" |
42 #include "core/workers/WorkerClients.h" | 43 #include "core/workers/WorkerClients.h" |
43 #include "core/workers/WorkerGlobalScope.h" | 44 #include "core/workers/WorkerGlobalScope.h" |
44 #include "core/workers/WorkerReportingProxy.h" | 45 #include "core/workers/WorkerReportingProxy.h" |
45 #include "core/workers/WorkerThreadStartupData.h" | 46 #include "core/workers/WorkerThreadStartupData.h" |
46 #include "platform/CrossThreadFunctional.h" | 47 #include "platform/CrossThreadFunctional.h" |
47 #include "platform/Histogram.h" | 48 #include "platform/Histogram.h" |
48 #include "platform/WaitableEvent.h" | 49 #include "platform/WaitableEvent.h" |
49 #include "platform/WebThreadSupportingGC.h" | 50 #include "platform/WebThreadSupportingGC.h" |
50 #include "platform/heap/SafePoint.h" | 51 #include "platform/heap/SafePoint.h" |
51 #include "platform/heap/ThreadState.h" | 52 #include "platform/heap/ThreadState.h" |
52 #include "platform/weborigin/KURL.h" | 53 #include "platform/weborigin/KURL.h" |
54 #include "public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h" | |
53 #include "wtf/Functional.h" | 55 #include "wtf/Functional.h" |
54 #include "wtf/Noncopyable.h" | 56 #include "wtf/Noncopyable.h" |
55 #include "wtf/PtrUtil.h" | 57 #include "wtf/PtrUtil.h" |
56 #include "wtf/Threading.h" | 58 #include "wtf/Threading.h" |
57 #include "wtf/text/WTFString.h" | 59 #include "wtf/text/WTFString.h" |
58 | 60 |
59 namespace blink { | 61 namespace blink { |
60 | 62 |
61 using ExitCode = WorkerThread::ExitCode; | 63 using ExitCode = WorkerThread::ExitCode; |
62 | 64 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
100 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 102 DEFINE_THREAD_SAFE_STATIC_LOCAL( |
101 EnumerationHistogram, exitCodeHistogram, | 103 EnumerationHistogram, exitCodeHistogram, |
102 new EnumerationHistogram("WorkerThread.ExitCode", | 104 new EnumerationHistogram("WorkerThread.ExitCode", |
103 static_cast<int>(ExitCode::LastEnum))); | 105 static_cast<int>(ExitCode::LastEnum))); |
104 exitCodeHistogram.count(static_cast<int>(m_exitCode)); | 106 exitCodeHistogram.count(static_cast<int>(m_exitCode)); |
105 } | 107 } |
106 | 108 |
107 void WorkerThread::start(std::unique_ptr<WorkerThreadStartupData> startupData, | 109 void WorkerThread::start(std::unique_ptr<WorkerThreadStartupData> startupData, |
108 ParentFrameTaskRunners* parentFrameTaskRunners) { | 110 ParentFrameTaskRunners* parentFrameTaskRunners) { |
109 DCHECK(isMainThread()); | 111 DCHECK(isMainThread()); |
110 | |
111 if (m_requestedToStart) | 112 if (m_requestedToStart) |
112 return; | 113 return; |
113 | 114 |
114 m_requestedToStart = true; | 115 m_requestedToStart = true; |
115 m_parentFrameTaskRunners = parentFrameTaskRunners; | 116 m_parentFrameTaskRunners = parentFrameTaskRunners; |
116 workerBackingThread().backingThread().postTask( | 117 m_threadControlTaskRunner = |
118 workerBackingThread().backingThread().platformThread().getWebTaskRunner(); | |
119 | |
120 // Synchronously initialize the per-global-scope scheduler to prevent someone | |
121 // from posting a task to the thread before the scheduler is ready. | |
122 WaitableEvent waitableEvent; | |
123 m_threadControlTaskRunner->postTask( | |
124 BLINK_FROM_HERE, | |
125 crossThreadBind(&WorkerThread::initializeSchedulerOnWorkerThread, | |
126 crossThreadUnretained(this), | |
127 crossThreadUnretained(&waitableEvent))); | |
kinuko
2017/04/10 06:30:06
Is it the requirement of NewTaskQueue implementati
Sami
2017/04/10 16:58:10
Yes, that's the case.
| |
128 waitableEvent.wait(); | |
129 | |
130 m_threadControlTaskRunner->postTask( | |
117 BLINK_FROM_HERE, crossThreadBind(&WorkerThread::initializeOnWorkerThread, | 131 BLINK_FROM_HERE, crossThreadBind(&WorkerThread::initializeOnWorkerThread, |
118 crossThreadUnretained(this), | 132 crossThreadUnretained(this), |
119 WTF::passed(std::move(startupData)))); | 133 WTF::passed(std::move(startupData)))); |
120 } | 134 } |
121 | 135 |
122 void WorkerThread::terminate() { | 136 void WorkerThread::terminate() { |
123 DCHECK(isMainThread()); | 137 DCHECK(isMainThread()); |
124 terminateInternal(TerminationMode::Graceful); | 138 terminateInternal(TerminationMode::Graceful); |
125 } | 139 } |
126 | 140 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
183 } | 197 } |
184 | 198 |
185 v8::Isolate* WorkerThread::isolate() { | 199 v8::Isolate* WorkerThread::isolate() { |
186 return workerBackingThread().isolate(); | 200 return workerBackingThread().isolate(); |
187 } | 201 } |
188 | 202 |
189 bool WorkerThread::isCurrentThread() { | 203 bool WorkerThread::isCurrentThread() { |
190 return workerBackingThread().backingThread().isCurrentThread(); | 204 return workerBackingThread().backingThread().isCurrentThread(); |
191 } | 205 } |
192 | 206 |
193 void WorkerThread::postTask(const WebTraceLocation& location, | |
194 std::unique_ptr<WTF::Closure> task) { | |
195 DCHECK(isCurrentThread()); | |
196 if (isInShutdown()) | |
197 return; | |
198 workerBackingThread().backingThread().postTask( | |
199 location, | |
200 WTF::bind( | |
201 &WorkerThread::performTaskOnWorkerThread<WTF::SameThreadAffinity>, | |
202 WTF::unretained(this), WTF::passed(std::move(task)))); | |
203 } | |
204 | |
205 void WorkerThread::postTask(const WebTraceLocation& location, | |
206 std::unique_ptr<WTF::CrossThreadClosure> task) { | |
207 if (isInShutdown()) | |
208 return; | |
209 workerBackingThread().backingThread().postTask( | |
210 location, | |
211 crossThreadBind( | |
212 &WorkerThread::performTaskOnWorkerThread<WTF::CrossThreadAffinity>, | |
213 crossThreadUnretained(this), WTF::passed(std::move(task)))); | |
214 } | |
215 | |
216 void WorkerThread::appendDebuggerTask( | 207 void WorkerThread::appendDebuggerTask( |
217 std::unique_ptr<CrossThreadClosure> task) { | 208 std::unique_ptr<CrossThreadClosure> task) { |
218 DCHECK(isMainThread()); | 209 DCHECK(isMainThread()); |
219 if (isInShutdown()) | 210 if (m_requestedToTerminate) |
220 return; | 211 return; |
221 m_inspectorTaskRunner->appendTask(crossThreadBind( | 212 m_inspectorTaskRunner->appendTask(crossThreadBind( |
222 &WorkerThread::performDebuggerTaskOnWorkerThread, | 213 &WorkerThread::performDebuggerTaskOnWorkerThread, |
223 crossThreadUnretained(this), WTF::passed(std::move(task)))); | 214 crossThreadUnretained(this), WTF::passed(std::move(task)))); |
224 { | 215 { |
225 MutexLocker lock(m_threadStateMutex); | 216 MutexLocker lock(m_threadStateMutex); |
226 if (isolate() && m_threadState != ThreadState::ReadyToShutdown) | 217 if (isolate() && m_threadState != ThreadState::ReadyToShutdown) |
227 m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate()); | 218 m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate()); |
228 } | 219 } |
229 workerBackingThread().backingThread().postTask( | 220 TaskRunnerHelper::get(TaskType::Unthrottled, this) |
230 BLINK_FROM_HERE, | 221 ->postTask(BLINK_FROM_HERE, |
231 crossThreadBind(&WorkerThread::performDebuggerTaskDontWaitOnWorkerThread, | 222 crossThreadBind( |
232 crossThreadUnretained(this))); | 223 &WorkerThread::performDebuggerTaskDontWaitOnWorkerThread, |
224 crossThreadUnretained(this))); | |
233 } | 225 } |
234 | 226 |
235 void WorkerThread::startRunningDebuggerTasksOnPauseOnWorkerThread() { | 227 void WorkerThread::startRunningDebuggerTasksOnPauseOnWorkerThread() { |
236 DCHECK(isCurrentThread()); | 228 DCHECK(isCurrentThread()); |
237 if (m_workerInspectorController) | 229 if (m_workerInspectorController) |
238 m_workerInspectorController->flushProtocolNotifications(); | 230 m_workerInspectorController->flushProtocolNotifications(); |
239 m_pausedInDebugger = true; | 231 m_pausedInDebugger = true; |
240 ThreadDebugger::idleStarted(isolate()); | 232 ThreadDebugger::idleStarted(isolate()); |
241 std::unique_ptr<CrossThreadClosure> task; | 233 std::unique_ptr<CrossThreadClosure> task; |
242 do { | 234 do { |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
361 WTF::unretained(this)), | 353 WTF::unretained(this)), |
362 m_forcibleTerminationDelayInMs); | 354 m_forcibleTerminationDelayInMs); |
363 break; | 355 break; |
364 } | 356 } |
365 } | 357 } |
366 } | 358 } |
367 | 359 |
368 m_workerThreadLifecycleContext->notifyContextDestroyed(); | 360 m_workerThreadLifecycleContext->notifyContextDestroyed(); |
369 m_inspectorTaskRunner->kill(); | 361 m_inspectorTaskRunner->kill(); |
370 | 362 |
371 workerBackingThread().backingThread().postTask( | 363 m_threadControlTaskRunner->postTask( |
372 BLINK_FROM_HERE, | 364 BLINK_FROM_HERE, |
373 crossThreadBind(&WorkerThread::prepareForShutdownOnWorkerThread, | 365 crossThreadBind(&WorkerThread::prepareForShutdownOnWorkerThread, |
374 crossThreadUnretained(this))); | 366 crossThreadUnretained(this))); |
375 workerBackingThread().backingThread().postTask( | 367 m_threadControlTaskRunner->postTask( |
376 BLINK_FROM_HERE, | 368 BLINK_FROM_HERE, |
377 crossThreadBind(&WorkerThread::performShutdownOnWorkerThread, | 369 crossThreadBind(&WorkerThread::performShutdownOnWorkerThread, |
378 crossThreadUnretained(this))); | 370 crossThreadUnretained(this))); |
379 } | 371 } |
380 | 372 |
381 bool WorkerThread::shouldScheduleToTerminateExecution(const MutexLocker& lock) { | 373 bool WorkerThread::shouldScheduleToTerminateExecution(const MutexLocker& lock) { |
382 DCHECK(isMainThread()); | 374 DCHECK(isMainThread()); |
383 DCHECK(isThreadStateMutexLocked(lock)); | 375 DCHECK(isThreadStateMutexLocked(lock)); |
384 | 376 |
385 switch (m_threadState) { | 377 switch (m_threadState) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
423 DCHECK(isThreadStateMutexLocked(lock)); | 415 DCHECK(isThreadStateMutexLocked(lock)); |
424 | 416 |
425 DCHECK(exitCode == ExitCode::SyncForciblyTerminated || | 417 DCHECK(exitCode == ExitCode::SyncForciblyTerminated || |
426 exitCode == ExitCode::AsyncForciblyTerminated); | 418 exitCode == ExitCode::AsyncForciblyTerminated); |
427 setExitCode(lock, exitCode); | 419 setExitCode(lock, exitCode); |
428 | 420 |
429 isolate()->TerminateExecution(); | 421 isolate()->TerminateExecution(); |
430 m_forcibleTerminationTaskHandle.cancel(); | 422 m_forcibleTerminationTaskHandle.cancel(); |
431 } | 423 } |
432 | 424 |
433 bool WorkerThread::isInShutdown() { | 425 void WorkerThread::initializeSchedulerOnWorkerThread( |
434 // Check if we've started termination or shutdown sequence. Avoid acquiring | 426 WaitableEvent* waitableEvent) { |
435 // a lock here to avoid introducing a risk of deadlock. Note that accessing | 427 DCHECK(isCurrentThread()); |
436 // |m_requestedToTerminate| on the main thread or |m_threadState| on the | 428 scheduler::WebThreadImplForWorkerScheduler& workerScheduler = |
437 // worker thread is safe as the flag is set only on the thread. | 429 static_cast<scheduler::WebThreadImplForWorkerScheduler&>( |
438 if (isMainThread() && m_requestedToTerminate) | 430 workerBackingThread().backingThread().platformThread()); |
439 return true; | 431 m_globalScopeScheduler = WTF::makeUnique<scheduler::GlobalScopeScheduler>( |
440 if (isCurrentThread() && m_threadState == ThreadState::ReadyToShutdown) | 432 workerScheduler.getWorkerScheduler()); |
441 return true; | 433 waitableEvent->signal(); |
442 return false; | |
443 } | 434 } |
444 | 435 |
445 void WorkerThread::initializeOnWorkerThread( | 436 void WorkerThread::initializeOnWorkerThread( |
446 std::unique_ptr<WorkerThreadStartupData> startupData) { | 437 std::unique_ptr<WorkerThreadStartupData> startupData) { |
447 DCHECK(isCurrentThread()); | 438 DCHECK(isCurrentThread()); |
448 DCHECK_EQ(ThreadState::NotStarted, m_threadState); | 439 DCHECK_EQ(ThreadState::NotStarted, m_threadState); |
449 | 440 |
450 KURL scriptURL = startupData->m_scriptURL; | 441 KURL scriptURL = startupData->m_scriptURL; |
451 String sourceCode = startupData->m_sourceCode; | 442 String sourceCode = startupData->m_sourceCode; |
452 WorkerThreadStartMode startMode = startupData->m_startMode; | 443 WorkerThreadStartMode startMode = startupData->m_startMode; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
530 probe::allAsyncTasksCanceled(globalScope()); | 521 probe::allAsyncTasksCanceled(globalScope()); |
531 | 522 |
532 globalScope()->notifyContextDestroyed(); | 523 globalScope()->notifyContextDestroyed(); |
533 if (m_workerInspectorController) { | 524 if (m_workerInspectorController) { |
534 m_workerInspectorController->dispose(); | 525 m_workerInspectorController->dispose(); |
535 m_workerInspectorController.clear(); | 526 m_workerInspectorController.clear(); |
536 } | 527 } |
537 globalScope()->dispose(); | 528 globalScope()->dispose(); |
538 m_consoleMessageStorage.clear(); | 529 m_consoleMessageStorage.clear(); |
539 workerBackingThread().backingThread().removeTaskObserver(this); | 530 workerBackingThread().backingThread().removeTaskObserver(this); |
531 | |
532 // Cancel all queued tasks. | |
533 m_globalScopeScheduler->dispose(); | |
540 } | 534 } |
541 | 535 |
542 void WorkerThread::performShutdownOnWorkerThread() { | 536 void WorkerThread::performShutdownOnWorkerThread() { |
543 DCHECK(isCurrentThread()); | 537 DCHECK(isCurrentThread()); |
544 DCHECK(checkRequestedToTerminateOnWorkerThread()); | 538 DCHECK(checkRequestedToTerminateOnWorkerThread()); |
545 DCHECK_EQ(ThreadState::ReadyToShutdown, m_threadState); | 539 DCHECK_EQ(ThreadState::ReadyToShutdown, m_threadState); |
546 | 540 |
547 // The below assignment will destroy the context, which will in turn notify | 541 // The below assignment will destroy the context, which will in turn notify |
548 // messaging proxy. We cannot let any objects survive past thread exit, | 542 // messaging proxy. We cannot let any objects survive past thread exit, |
549 // because no other thread will run GC or otherwise destroy them. If Oilpan | 543 // because no other thread will run GC or otherwise destroy them. If Oilpan |
550 // is enabled, we detach of the context/global scope, with the final heap | 544 // is enabled, we detach of the context/global scope, with the final heap |
551 // cleanup below sweeping it out. | 545 // cleanup below sweeping it out. |
552 m_globalScope = nullptr; | 546 m_globalScope = nullptr; |
553 | 547 |
554 if (isOwningBackingThread()) | 548 if (isOwningBackingThread()) |
555 workerBackingThread().shutdown(); | 549 workerBackingThread().shutdown(); |
556 // We must not touch workerBackingThread() from now on. | 550 // We must not touch workerBackingThread() from now on. |
557 | 551 |
558 // Notify the proxy that the WorkerOrWorkletGlobalScope has been disposed | 552 // Notify the proxy that the WorkerOrWorkletGlobalScope has been disposed |
559 // of. This can free this thread object, hence it must not be touched | 553 // of. This can free this thread object, hence it must not be touched |
560 // afterwards. | 554 // afterwards. |
561 workerReportingProxy().didTerminateWorkerThread(); | 555 workerReportingProxy().didTerminateWorkerThread(); |
562 | 556 |
563 m_shutdownEvent->signal(); | 557 m_shutdownEvent->signal(); |
564 } | 558 } |
565 | 559 |
566 template <WTF::FunctionThreadAffinity threadAffinity> | |
567 void WorkerThread::performTaskOnWorkerThread( | |
568 std::unique_ptr<Function<void(), threadAffinity>> task) { | |
569 DCHECK(isCurrentThread()); | |
570 if (m_threadState != ThreadState::Running) | |
571 return; | |
572 | |
573 { | |
574 DEFINE_THREAD_SAFE_STATIC_LOCAL( | |
575 CustomCountHistogram, scopedUsCounter, | |
576 new CustomCountHistogram("WorkerThread.Task.Time", 0, 10000000, 50)); | |
577 ScopedUsHistogramTimer timer(scopedUsCounter); | |
578 (*task)(); | |
579 } | |
580 } | |
581 | |
582 void WorkerThread::performDebuggerTaskOnWorkerThread( | 560 void WorkerThread::performDebuggerTaskOnWorkerThread( |
583 std::unique_ptr<CrossThreadClosure> task) { | 561 std::unique_ptr<CrossThreadClosure> task) { |
584 DCHECK(isCurrentThread()); | 562 DCHECK(isCurrentThread()); |
585 InspectorTaskRunner::IgnoreInterruptsScope scope(m_inspectorTaskRunner.get()); | 563 InspectorTaskRunner::IgnoreInterruptsScope scope(m_inspectorTaskRunner.get()); |
586 { | 564 { |
587 MutexLocker lock(m_threadStateMutex); | 565 MutexLocker lock(m_threadStateMutex); |
588 DCHECK_EQ(ThreadState::Running, m_threadState); | 566 DCHECK_EQ(ThreadState::Running, m_threadState); |
589 m_runningDebuggerTask = true; | 567 m_runningDebuggerTask = true; |
590 } | 568 } |
591 ThreadDebugger::idleFinished(isolate()); | 569 ThreadDebugger::idleFinished(isolate()); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
656 MutexLocker lock(m_threadStateMutex); | 634 MutexLocker lock(m_threadStateMutex); |
657 return m_requestedToTerminate; | 635 return m_requestedToTerminate; |
658 } | 636 } |
659 | 637 |
660 ExitCode WorkerThread::getExitCodeForTesting() { | 638 ExitCode WorkerThread::getExitCodeForTesting() { |
661 MutexLocker lock(m_threadStateMutex); | 639 MutexLocker lock(m_threadStateMutex); |
662 return m_exitCode; | 640 return m_exitCode; |
663 } | 641 } |
664 | 642 |
665 } // namespace blink | 643 } // namespace blink |
OLD | NEW |