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" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 101 DEFINE_THREAD_SAFE_STATIC_LOCAL( |
101 EnumerationHistogram, exit_code_histogram, | 102 EnumerationHistogram, exit_code_histogram, |
102 new EnumerationHistogram("WorkerThread.ExitCode", | 103 new EnumerationHistogram("WorkerThread.ExitCode", |
103 static_cast<int>(ExitCode::kLastEnum))); | 104 static_cast<int>(ExitCode::kLastEnum))); |
104 exit_code_histogram.Count(static_cast<int>(exit_code_)); | 105 exit_code_histogram.Count(static_cast<int>(exit_code_)); |
105 } | 106 } |
106 | 107 |
107 void WorkerThread::Start(std::unique_ptr<WorkerThreadStartupData> startup_data, | 108 void WorkerThread::Start(std::unique_ptr<WorkerThreadStartupData> startup_data, |
108 ParentFrameTaskRunners* parent_frame_task_runners) { | 109 ParentFrameTaskRunners* parent_frame_task_runners) { |
109 DCHECK(IsMainThread()); | 110 DCHECK(IsMainThread()); |
110 | |
111 if (requested_to_start_) | 111 if (requested_to_start_) |
112 return; | 112 return; |
113 | 113 |
114 requested_to_start_ = true; | 114 requested_to_start_ = true; |
115 parent_frame_task_runners_ = parent_frame_task_runners; | 115 parent_frame_task_runners_ = parent_frame_task_runners; |
| 116 |
| 117 // Synchronously initialize the per-global-scope scheduler to prevent someone |
| 118 // from posting a task to the thread before the scheduler is ready. |
| 119 WaitableEvent waitable_event; |
| 120 GetWorkerBackingThread().BackingThread().PostTask( |
| 121 BLINK_FROM_HERE, |
| 122 CrossThreadBind(&WorkerThread::InitializeSchedulerOnWorkerThread, |
| 123 CrossThreadUnretained(this), |
| 124 CrossThreadUnretained(&waitable_event))); |
| 125 waitable_event.Wait(); |
| 126 |
116 GetWorkerBackingThread().BackingThread().PostTask( | 127 GetWorkerBackingThread().BackingThread().PostTask( |
117 BLINK_FROM_HERE, CrossThreadBind(&WorkerThread::InitializeOnWorkerThread, | 128 BLINK_FROM_HERE, CrossThreadBind(&WorkerThread::InitializeOnWorkerThread, |
118 CrossThreadUnretained(this), | 129 CrossThreadUnretained(this), |
119 WTF::Passed(std::move(startup_data)))); | 130 WTF::Passed(std::move(startup_data)))); |
120 } | 131 } |
121 | 132 |
122 void WorkerThread::Terminate() { | 133 void WorkerThread::Terminate() { |
123 DCHECK(IsMainThread()); | 134 DCHECK(IsMainThread()); |
124 TerminateInternal(TerminationMode::kGraceful); | 135 TerminateInternal(TerminationMode::kGraceful); |
125 } | 136 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 } | 194 } |
184 | 195 |
185 v8::Isolate* WorkerThread::GetIsolate() { | 196 v8::Isolate* WorkerThread::GetIsolate() { |
186 return GetWorkerBackingThread().GetIsolate(); | 197 return GetWorkerBackingThread().GetIsolate(); |
187 } | 198 } |
188 | 199 |
189 bool WorkerThread::IsCurrentThread() { | 200 bool WorkerThread::IsCurrentThread() { |
190 return GetWorkerBackingThread().BackingThread().IsCurrentThread(); | 201 return GetWorkerBackingThread().BackingThread().IsCurrentThread(); |
191 } | 202 } |
192 | 203 |
193 void WorkerThread::PostTask(const WebTraceLocation& location, | |
194 std::unique_ptr<WTF::Closure> task) { | |
195 DCHECK(IsCurrentThread()); | |
196 if (IsInShutdown()) | |
197 return; | |
198 GetWorkerBackingThread().BackingThread().PostTask( | |
199 location, | |
200 WTF::Bind( | |
201 &WorkerThread::PerformTaskOnWorkerThread<WTF::kSameThreadAffinity>, | |
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 GetWorkerBackingThread().BackingThread().PostTask( | |
210 location, | |
211 CrossThreadBind( | |
212 &WorkerThread::PerformTaskOnWorkerThread<WTF::kCrossThreadAffinity>, | |
213 CrossThreadUnretained(this), WTF::Passed(std::move(task)))); | |
214 } | |
215 | |
216 void WorkerThread::AppendDebuggerTask( | 204 void WorkerThread::AppendDebuggerTask( |
217 std::unique_ptr<CrossThreadClosure> task) { | 205 std::unique_ptr<CrossThreadClosure> task) { |
218 DCHECK(IsMainThread()); | 206 DCHECK(IsMainThread()); |
219 if (IsInShutdown()) | 207 if (requested_to_terminate_) |
220 return; | 208 return; |
221 inspector_task_runner_->AppendTask(CrossThreadBind( | 209 inspector_task_runner_->AppendTask(CrossThreadBind( |
222 &WorkerThread::PerformDebuggerTaskOnWorkerThread, | 210 &WorkerThread::PerformDebuggerTaskOnWorkerThread, |
223 CrossThreadUnretained(this), WTF::Passed(std::move(task)))); | 211 CrossThreadUnretained(this), WTF::Passed(std::move(task)))); |
224 { | 212 { |
225 MutexLocker lock(thread_state_mutex_); | 213 MutexLocker lock(thread_state_mutex_); |
226 if (GetIsolate() && thread_state_ != ThreadState::kReadyToShutdown) | 214 if (GetIsolate() && thread_state_ != ThreadState::kReadyToShutdown) |
227 inspector_task_runner_->InterruptAndRunAllTasksDontWait(GetIsolate()); | 215 inspector_task_runner_->InterruptAndRunAllTasksDontWait(GetIsolate()); |
228 } | 216 } |
229 GetWorkerBackingThread().BackingThread().PostTask( | 217 TaskRunnerHelper::Get(TaskType::kUnthrottled, this) |
230 BLINK_FROM_HERE, | 218 ->PostTask(BLINK_FROM_HERE, |
231 CrossThreadBind(&WorkerThread::PerformDebuggerTaskDontWaitOnWorkerThread, | 219 CrossThreadBind( |
232 CrossThreadUnretained(this))); | 220 &WorkerThread::PerformDebuggerTaskDontWaitOnWorkerThread, |
| 221 CrossThreadUnretained(this))); |
233 } | 222 } |
234 | 223 |
235 void WorkerThread::StartRunningDebuggerTasksOnPauseOnWorkerThread() { | 224 void WorkerThread::StartRunningDebuggerTasksOnPauseOnWorkerThread() { |
236 DCHECK(IsCurrentThread()); | 225 DCHECK(IsCurrentThread()); |
237 if (worker_inspector_controller_) | 226 if (worker_inspector_controller_) |
238 worker_inspector_controller_->FlushProtocolNotifications(); | 227 worker_inspector_controller_->FlushProtocolNotifications(); |
239 paused_in_debugger_ = true; | 228 paused_in_debugger_ = true; |
240 ThreadDebugger::IdleStarted(GetIsolate()); | 229 ThreadDebugger::IdleStarted(GetIsolate()); |
241 std::unique_ptr<CrossThreadClosure> task; | 230 std::unique_ptr<CrossThreadClosure> task; |
242 do { | 231 do { |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 DCHECK(IsThreadStateMutexLocked(lock)); | 412 DCHECK(IsThreadStateMutexLocked(lock)); |
424 | 413 |
425 DCHECK(exit_code == ExitCode::kSyncForciblyTerminated || | 414 DCHECK(exit_code == ExitCode::kSyncForciblyTerminated || |
426 exit_code == ExitCode::kAsyncForciblyTerminated); | 415 exit_code == ExitCode::kAsyncForciblyTerminated); |
427 SetExitCode(lock, exit_code); | 416 SetExitCode(lock, exit_code); |
428 | 417 |
429 GetIsolate()->TerminateExecution(); | 418 GetIsolate()->TerminateExecution(); |
430 forcible_termination_task_handle_.Cancel(); | 419 forcible_termination_task_handle_.Cancel(); |
431 } | 420 } |
432 | 421 |
433 bool WorkerThread::IsInShutdown() { | 422 void WorkerThread::InitializeSchedulerOnWorkerThread( |
434 // Check if we've started termination or shutdown sequence. Avoid acquiring | 423 WaitableEvent* waitable_event) { |
435 // a lock here to avoid introducing a risk of deadlock. Note that accessing | 424 DCHECK(IsCurrentThread()); |
436 // |m_requestedToTerminate| on the main thread or |m_threadState| on the | 425 global_scope_scheduler_ = |
437 // worker thread is safe as the flag is set only on the thread. | 426 GetWorkerBackingThread().CreateGlobalScopeScheduler(); |
438 if (IsMainThread() && requested_to_terminate_) | 427 waitable_event->Signal(); |
439 return true; | |
440 if (IsCurrentThread() && thread_state_ == ThreadState::kReadyToShutdown) | |
441 return true; | |
442 return false; | |
443 } | 428 } |
444 | 429 |
445 void WorkerThread::InitializeOnWorkerThread( | 430 void WorkerThread::InitializeOnWorkerThread( |
446 std::unique_ptr<WorkerThreadStartupData> startup_data) { | 431 std::unique_ptr<WorkerThreadStartupData> startup_data) { |
447 DCHECK(IsCurrentThread()); | 432 DCHECK(IsCurrentThread()); |
448 DCHECK_EQ(ThreadState::kNotStarted, thread_state_); | 433 DCHECK_EQ(ThreadState::kNotStarted, thread_state_); |
449 | 434 |
450 KURL script_url = startup_data->script_url_; | 435 KURL script_url = startup_data->script_url_; |
451 String source_code = startup_data->source_code_; | 436 String source_code = startup_data->source_code_; |
452 WorkerThreadStartMode start_mode = startup_data->start_mode_; | 437 WorkerThreadStartMode start_mode = startup_data->start_mode_; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 inspector_task_runner_->Kill(); | 514 inspector_task_runner_->Kill(); |
530 GetWorkerReportingProxy().WillDestroyWorkerGlobalScope(); | 515 GetWorkerReportingProxy().WillDestroyWorkerGlobalScope(); |
531 probe::AllAsyncTasksCanceled(GlobalScope()); | 516 probe::AllAsyncTasksCanceled(GlobalScope()); |
532 | 517 |
533 GlobalScope()->NotifyContextDestroyed(); | 518 GlobalScope()->NotifyContextDestroyed(); |
534 if (worker_inspector_controller_) { | 519 if (worker_inspector_controller_) { |
535 worker_inspector_controller_->Dispose(); | 520 worker_inspector_controller_->Dispose(); |
536 worker_inspector_controller_.Clear(); | 521 worker_inspector_controller_.Clear(); |
537 } | 522 } |
538 GlobalScope()->Dispose(); | 523 GlobalScope()->Dispose(); |
| 524 global_scope_scheduler_->Dispose(); |
539 console_message_storage_.Clear(); | 525 console_message_storage_.Clear(); |
540 GetWorkerBackingThread().BackingThread().RemoveTaskObserver(this); | 526 GetWorkerBackingThread().BackingThread().RemoveTaskObserver(this); |
541 } | 527 } |
542 | 528 |
543 void WorkerThread::PerformShutdownOnWorkerThread() { | 529 void WorkerThread::PerformShutdownOnWorkerThread() { |
544 DCHECK(IsCurrentThread()); | 530 DCHECK(IsCurrentThread()); |
545 DCHECK(CheckRequestedToTerminateOnWorkerThread()); | 531 DCHECK(CheckRequestedToTerminateOnWorkerThread()); |
546 DCHECK_EQ(ThreadState::kReadyToShutdown, thread_state_); | 532 DCHECK_EQ(ThreadState::kReadyToShutdown, thread_state_); |
547 | 533 |
548 // The below assignment will destroy the context, which will in turn notify | 534 // The below assignment will destroy the context, which will in turn notify |
549 // messaging proxy. We cannot let any objects survive past thread exit, | 535 // messaging proxy. We cannot let any objects survive past thread exit, |
550 // because no other thread will run GC or otherwise destroy them. If Oilpan | 536 // because no other thread will run GC or otherwise destroy them. If Oilpan |
551 // is enabled, we detach of the context/global scope, with the final heap | 537 // is enabled, we detach of the context/global scope, with the final heap |
552 // cleanup below sweeping it out. | 538 // cleanup below sweeping it out. |
553 global_scope_ = nullptr; | 539 global_scope_ = nullptr; |
554 | 540 |
555 if (IsOwningBackingThread()) | 541 if (IsOwningBackingThread()) |
556 GetWorkerBackingThread().Shutdown(); | 542 GetWorkerBackingThread().Shutdown(); |
557 // We must not touch workerBackingThread() from now on. | 543 // We must not touch workerBackingThread() from now on. |
558 | 544 |
559 // Notify the proxy that the WorkerOrWorkletGlobalScope has been disposed | 545 // Notify the proxy that the WorkerOrWorkletGlobalScope has been disposed |
560 // of. This can free this thread object, hence it must not be touched | 546 // of. This can free this thread object, hence it must not be touched |
561 // afterwards. | 547 // afterwards. |
562 GetWorkerReportingProxy().DidTerminateWorkerThread(); | 548 GetWorkerReportingProxy().DidTerminateWorkerThread(); |
563 | 549 |
564 shutdown_event_->Signal(); | 550 shutdown_event_->Signal(); |
565 } | 551 } |
566 | 552 |
567 template <WTF::FunctionThreadAffinity threadAffinity> | |
568 void WorkerThread::PerformTaskOnWorkerThread( | |
569 std::unique_ptr<Function<void(), threadAffinity>> task) { | |
570 DCHECK(IsCurrentThread()); | |
571 if (thread_state_ != ThreadState::kRunning) | |
572 return; | |
573 | |
574 { | |
575 DEFINE_THREAD_SAFE_STATIC_LOCAL( | |
576 CustomCountHistogram, scoped_us_counter, | |
577 new CustomCountHistogram("WorkerThread.Task.Time", 0, 10000000, 50)); | |
578 ScopedUsHistogramTimer timer(scoped_us_counter); | |
579 (*task)(); | |
580 } | |
581 } | |
582 | |
583 void WorkerThread::PerformDebuggerTaskOnWorkerThread( | 553 void WorkerThread::PerformDebuggerTaskOnWorkerThread( |
584 std::unique_ptr<CrossThreadClosure> task) { | 554 std::unique_ptr<CrossThreadClosure> task) { |
585 DCHECK(IsCurrentThread()); | 555 DCHECK(IsCurrentThread()); |
586 InspectorTaskRunner::IgnoreInterruptsScope scope( | 556 InspectorTaskRunner::IgnoreInterruptsScope scope( |
587 inspector_task_runner_.get()); | 557 inspector_task_runner_.get()); |
588 { | 558 { |
589 MutexLocker lock(thread_state_mutex_); | 559 MutexLocker lock(thread_state_mutex_); |
590 DCHECK_EQ(ThreadState::kRunning, thread_state_); | 560 DCHECK_EQ(ThreadState::kRunning, thread_state_); |
591 running_debugger_task_ = true; | 561 running_debugger_task_ = true; |
592 } | 562 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 MutexLocker lock(thread_state_mutex_); | 629 MutexLocker lock(thread_state_mutex_); |
660 return requested_to_terminate_; | 630 return requested_to_terminate_; |
661 } | 631 } |
662 | 632 |
663 ExitCode WorkerThread::GetExitCodeForTesting() { | 633 ExitCode WorkerThread::GetExitCodeForTesting() { |
664 MutexLocker lock(thread_state_mutex_); | 634 MutexLocker lock(thread_state_mutex_); |
665 return exit_code_; | 635 return exit_code_; |
666 } | 636 } |
667 | 637 |
668 } // namespace blink | 638 } // namespace blink |
OLD | NEW |