| 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" |
| 53 #include "platform/scheduler/child/webthread_impl_for_worker_scheduler.h" |
| 54 #include "platform/scheduler/child/worker_global_scope_scheduler.h" |
| 52 #include "platform/weborigin/KURL.h" | 55 #include "platform/weborigin/KURL.h" |
| 53 #include "platform/wtf/Functional.h" | 56 #include "platform/wtf/Functional.h" |
| 54 #include "platform/wtf/Noncopyable.h" | 57 #include "platform/wtf/Noncopyable.h" |
| 55 #include "platform/wtf/PtrUtil.h" | 58 #include "platform/wtf/PtrUtil.h" |
| 56 #include "platform/wtf/Threading.h" | 59 #include "platform/wtf/Threading.h" |
| 57 #include "platform/wtf/text/WTFString.h" | 60 #include "platform/wtf/text/WTFString.h" |
| 58 | 61 |
| 59 namespace blink { | 62 namespace blink { |
| 60 | 63 |
| 61 using ExitCode = WorkerThread::ExitCode; | 64 using ExitCode = WorkerThread::ExitCode; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 103 DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| 101 EnumerationHistogram, exit_code_histogram, | 104 EnumerationHistogram, exit_code_histogram, |
| 102 new EnumerationHistogram("WorkerThread.ExitCode", | 105 new EnumerationHistogram("WorkerThread.ExitCode", |
| 103 static_cast<int>(ExitCode::kLastEnum))); | 106 static_cast<int>(ExitCode::kLastEnum))); |
| 104 exit_code_histogram.Count(static_cast<int>(exit_code_)); | 107 exit_code_histogram.Count(static_cast<int>(exit_code_)); |
| 105 } | 108 } |
| 106 | 109 |
| 107 void WorkerThread::Start(std::unique_ptr<WorkerThreadStartupData> startup_data, | 110 void WorkerThread::Start(std::unique_ptr<WorkerThreadStartupData> startup_data, |
| 108 ParentFrameTaskRunners* parent_frame_task_runners) { | 111 ParentFrameTaskRunners* parent_frame_task_runners) { |
| 109 DCHECK(IsMainThread()); | 112 DCHECK(IsMainThread()); |
| 110 | |
| 111 if (requested_to_start_) | 113 if (requested_to_start_) |
| 112 return; | 114 return; |
| 113 | 115 |
| 114 requested_to_start_ = true; | 116 requested_to_start_ = true; |
| 115 parent_frame_task_runners_ = parent_frame_task_runners; | 117 parent_frame_task_runners_ = parent_frame_task_runners; |
| 118 |
| 119 // Synchronously initialize the per-global-scope scheduler to prevent someone |
| 120 // from posting a task to the thread before the scheduler is ready. |
| 121 WaitableEvent waitable_event; |
| 122 GetWorkerBackingThread().BackingThread().PostTask( |
| 123 BLINK_FROM_HERE, |
| 124 CrossThreadBind(&WorkerThread::InitializeSchedulerOnWorkerThread, |
| 125 CrossThreadUnretained(this), |
| 126 CrossThreadUnretained(&waitable_event))); |
| 127 waitable_event.Wait(); |
| 128 |
| 116 GetWorkerBackingThread().BackingThread().PostTask( | 129 GetWorkerBackingThread().BackingThread().PostTask( |
| 117 BLINK_FROM_HERE, CrossThreadBind(&WorkerThread::InitializeOnWorkerThread, | 130 BLINK_FROM_HERE, CrossThreadBind(&WorkerThread::InitializeOnWorkerThread, |
| 118 CrossThreadUnretained(this), | 131 CrossThreadUnretained(this), |
| 119 WTF::Passed(std::move(startup_data)))); | 132 WTF::Passed(std::move(startup_data)))); |
| 120 } | 133 } |
| 121 | 134 |
| 122 void WorkerThread::Terminate() { | 135 void WorkerThread::Terminate() { |
| 123 DCHECK(IsMainThread()); | 136 DCHECK(IsMainThread()); |
| 124 TerminateInternal(TerminationMode::kGraceful); | 137 TerminateInternal(TerminationMode::kGraceful); |
| 125 } | 138 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 } | 196 } |
| 184 | 197 |
| 185 v8::Isolate* WorkerThread::GetIsolate() { | 198 v8::Isolate* WorkerThread::GetIsolate() { |
| 186 return GetWorkerBackingThread().GetIsolate(); | 199 return GetWorkerBackingThread().GetIsolate(); |
| 187 } | 200 } |
| 188 | 201 |
| 189 bool WorkerThread::IsCurrentThread() { | 202 bool WorkerThread::IsCurrentThread() { |
| 190 return GetWorkerBackingThread().BackingThread().IsCurrentThread(); | 203 return GetWorkerBackingThread().BackingThread().IsCurrentThread(); |
| 191 } | 204 } |
| 192 | 205 |
| 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( | 206 void WorkerThread::AppendDebuggerTask( |
| 217 std::unique_ptr<CrossThreadClosure> task) { | 207 std::unique_ptr<CrossThreadClosure> task) { |
| 218 DCHECK(IsMainThread()); | 208 DCHECK(IsMainThread()); |
| 219 if (IsInShutdown()) | 209 if (requested_to_terminate_) |
| 220 return; | 210 return; |
| 221 inspector_task_runner_->AppendTask(CrossThreadBind( | 211 inspector_task_runner_->AppendTask(CrossThreadBind( |
| 222 &WorkerThread::PerformDebuggerTaskOnWorkerThread, | 212 &WorkerThread::PerformDebuggerTaskOnWorkerThread, |
| 223 CrossThreadUnretained(this), WTF::Passed(std::move(task)))); | 213 CrossThreadUnretained(this), WTF::Passed(std::move(task)))); |
| 224 { | 214 { |
| 225 MutexLocker lock(thread_state_mutex_); | 215 MutexLocker lock(thread_state_mutex_); |
| 226 if (GetIsolate() && thread_state_ != ThreadState::kReadyToShutdown) | 216 if (GetIsolate() && thread_state_ != ThreadState::kReadyToShutdown) |
| 227 inspector_task_runner_->InterruptAndRunAllTasksDontWait(GetIsolate()); | 217 inspector_task_runner_->InterruptAndRunAllTasksDontWait(GetIsolate()); |
| 228 } | 218 } |
| 229 GetWorkerBackingThread().BackingThread().PostTask( | 219 TaskRunnerHelper::Get(TaskType::kUnthrottled, this) |
| 230 BLINK_FROM_HERE, | 220 ->PostTask(BLINK_FROM_HERE, |
| 231 CrossThreadBind(&WorkerThread::PerformDebuggerTaskDontWaitOnWorkerThread, | 221 CrossThreadBind( |
| 232 CrossThreadUnretained(this))); | 222 &WorkerThread::PerformDebuggerTaskDontWaitOnWorkerThread, |
| 223 CrossThreadUnretained(this))); |
| 233 } | 224 } |
| 234 | 225 |
| 235 void WorkerThread::StartRunningDebuggerTasksOnPauseOnWorkerThread() { | 226 void WorkerThread::StartRunningDebuggerTasksOnPauseOnWorkerThread() { |
| 236 DCHECK(IsCurrentThread()); | 227 DCHECK(IsCurrentThread()); |
| 237 if (worker_inspector_controller_) | 228 if (worker_inspector_controller_) |
| 238 worker_inspector_controller_->FlushProtocolNotifications(); | 229 worker_inspector_controller_->FlushProtocolNotifications(); |
| 239 paused_in_debugger_ = true; | 230 paused_in_debugger_ = true; |
| 240 ThreadDebugger::IdleStarted(GetIsolate()); | 231 ThreadDebugger::IdleStarted(GetIsolate()); |
| 241 std::unique_ptr<CrossThreadClosure> task; | 232 std::unique_ptr<CrossThreadClosure> task; |
| 242 do { | 233 do { |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 DCHECK(IsThreadStateMutexLocked(lock)); | 414 DCHECK(IsThreadStateMutexLocked(lock)); |
| 424 | 415 |
| 425 DCHECK(exit_code == ExitCode::kSyncForciblyTerminated || | 416 DCHECK(exit_code == ExitCode::kSyncForciblyTerminated || |
| 426 exit_code == ExitCode::kAsyncForciblyTerminated); | 417 exit_code == ExitCode::kAsyncForciblyTerminated); |
| 427 SetExitCode(lock, exit_code); | 418 SetExitCode(lock, exit_code); |
| 428 | 419 |
| 429 GetIsolate()->TerminateExecution(); | 420 GetIsolate()->TerminateExecution(); |
| 430 forcible_termination_task_handle_.Cancel(); | 421 forcible_termination_task_handle_.Cancel(); |
| 431 } | 422 } |
| 432 | 423 |
| 433 bool WorkerThread::IsInShutdown() { | 424 void WorkerThread::InitializeSchedulerOnWorkerThread( |
| 434 // Check if we've started termination or shutdown sequence. Avoid acquiring | 425 WaitableEvent* waitable_event) { |
| 435 // a lock here to avoid introducing a risk of deadlock. Note that accessing | 426 DCHECK(IsCurrentThread()); |
| 436 // |m_requestedToTerminate| on the main thread or |m_threadState| on the | 427 DCHECK(!global_scope_scheduler_); |
| 437 // worker thread is safe as the flag is set only on the thread. | 428 scheduler::WebThreadImplForWorkerScheduler& web_thread_for_worker = |
| 438 if (IsMainThread() && requested_to_terminate_) | 429 static_cast<scheduler::WebThreadImplForWorkerScheduler&>( |
| 439 return true; | 430 GetWorkerBackingThread().BackingThread().PlatformThread()); |
| 440 if (IsCurrentThread() && thread_state_ == ThreadState::kReadyToShutdown) | 431 global_scope_scheduler_ = |
| 441 return true; | 432 WTF::MakeUnique<scheduler::WorkerGlobalScopeScheduler>( |
| 442 return false; | 433 web_thread_for_worker.GetWorkerScheduler()); |
| 434 waitable_event->Signal(); |
| 443 } | 435 } |
| 444 | 436 |
| 445 void WorkerThread::InitializeOnWorkerThread( | 437 void WorkerThread::InitializeOnWorkerThread( |
| 446 std::unique_ptr<WorkerThreadStartupData> startup_data) { | 438 std::unique_ptr<WorkerThreadStartupData> startup_data) { |
| 447 DCHECK(IsCurrentThread()); | 439 DCHECK(IsCurrentThread()); |
| 448 DCHECK_EQ(ThreadState::kNotStarted, thread_state_); | 440 DCHECK_EQ(ThreadState::kNotStarted, thread_state_); |
| 449 | 441 |
| 450 KURL script_url = startup_data->script_url_; | 442 KURL script_url = startup_data->script_url_; |
| 451 String source_code = startup_data->source_code_; | 443 String source_code = startup_data->source_code_; |
| 452 WorkerThreadStartMode start_mode = startup_data->start_mode_; | 444 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(); | 521 inspector_task_runner_->Kill(); |
| 530 GetWorkerReportingProxy().WillDestroyWorkerGlobalScope(); | 522 GetWorkerReportingProxy().WillDestroyWorkerGlobalScope(); |
| 531 probe::AllAsyncTasksCanceled(GlobalScope()); | 523 probe::AllAsyncTasksCanceled(GlobalScope()); |
| 532 | 524 |
| 533 GlobalScope()->NotifyContextDestroyed(); | 525 GlobalScope()->NotifyContextDestroyed(); |
| 534 if (worker_inspector_controller_) { | 526 if (worker_inspector_controller_) { |
| 535 worker_inspector_controller_->Dispose(); | 527 worker_inspector_controller_->Dispose(); |
| 536 worker_inspector_controller_.Clear(); | 528 worker_inspector_controller_.Clear(); |
| 537 } | 529 } |
| 538 GlobalScope()->Dispose(); | 530 GlobalScope()->Dispose(); |
| 531 global_scope_scheduler_->Dispose(); |
| 539 console_message_storage_.Clear(); | 532 console_message_storage_.Clear(); |
| 540 GetWorkerBackingThread().BackingThread().RemoveTaskObserver(this); | 533 GetWorkerBackingThread().BackingThread().RemoveTaskObserver(this); |
| 541 } | 534 } |
| 542 | 535 |
| 543 void WorkerThread::PerformShutdownOnWorkerThread() { | 536 void WorkerThread::PerformShutdownOnWorkerThread() { |
| 544 DCHECK(IsCurrentThread()); | 537 DCHECK(IsCurrentThread()); |
| 545 DCHECK(CheckRequestedToTerminateOnWorkerThread()); | 538 DCHECK(CheckRequestedToTerminateOnWorkerThread()); |
| 546 DCHECK_EQ(ThreadState::kReadyToShutdown, thread_state_); | 539 DCHECK_EQ(ThreadState::kReadyToShutdown, thread_state_); |
| 547 | 540 |
| 548 // 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 |
| 549 // messaging proxy. We cannot let any objects survive past thread exit, | 542 // 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 | 543 // 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 | 544 // is enabled, we detach of the context/global scope, with the final heap |
| 552 // cleanup below sweeping it out. | 545 // cleanup below sweeping it out. |
| 553 global_scope_ = nullptr; | 546 global_scope_ = nullptr; |
| 554 | 547 |
| 555 if (IsOwningBackingThread()) | 548 if (IsOwningBackingThread()) |
| 556 GetWorkerBackingThread().Shutdown(); | 549 GetWorkerBackingThread().Shutdown(); |
| 557 // We must not touch workerBackingThread() from now on. | 550 // We must not touch workerBackingThread() from now on. |
| 558 | 551 |
| 559 // Notify the proxy that the WorkerOrWorkletGlobalScope has been disposed | 552 // Notify the proxy that the WorkerOrWorkletGlobalScope has been disposed |
| 560 // 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 |
| 561 // afterwards. | 554 // afterwards. |
| 562 GetWorkerReportingProxy().DidTerminateWorkerThread(); | 555 GetWorkerReportingProxy().DidTerminateWorkerThread(); |
| 563 | 556 |
| 564 shutdown_event_->Signal(); | 557 shutdown_event_->Signal(); |
| 565 } | 558 } |
| 566 | 559 |
| 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( | 560 void WorkerThread::PerformDebuggerTaskOnWorkerThread( |
| 584 std::unique_ptr<CrossThreadClosure> task) { | 561 std::unique_ptr<CrossThreadClosure> task) { |
| 585 DCHECK(IsCurrentThread()); | 562 DCHECK(IsCurrentThread()); |
| 586 InspectorTaskRunner::IgnoreInterruptsScope scope( | 563 InspectorTaskRunner::IgnoreInterruptsScope scope( |
| 587 inspector_task_runner_.get()); | 564 inspector_task_runner_.get()); |
| 588 { | 565 { |
| 589 MutexLocker lock(thread_state_mutex_); | 566 MutexLocker lock(thread_state_mutex_); |
| 590 DCHECK_EQ(ThreadState::kRunning, thread_state_); | 567 DCHECK_EQ(ThreadState::kRunning, thread_state_); |
| 591 running_debugger_task_ = true; | 568 running_debugger_task_ = true; |
| 592 } | 569 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 MutexLocker lock(thread_state_mutex_); | 636 MutexLocker lock(thread_state_mutex_); |
| 660 return requested_to_terminate_; | 637 return requested_to_terminate_; |
| 661 } | 638 } |
| 662 | 639 |
| 663 ExitCode WorkerThread::GetExitCodeForTesting() { | 640 ExitCode WorkerThread::GetExitCodeForTesting() { |
| 664 MutexLocker lock(thread_state_mutex_); | 641 MutexLocker lock(thread_state_mutex_); |
| 665 return exit_code_; | 642 return exit_code_; |
| 666 } | 643 } |
| 667 | 644 |
| 668 } // namespace blink | 645 } // namespace blink |
| OLD | NEW |