| // Copyright 2016 The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that can |
| // be found in the LICENSE file. |
| |
| #include "libcef/common/thread_impl.h" |
| |
| #include "libcef/common/task_runner_impl.h" |
| |
| #include "base/bind.h" |
| #include "base/threading/thread_restrictions.h" |
| |
| namespace { |
| |
| void StopAndDestroy(base::Thread* thread) { |
| // Calling PlatformThread::Join() on the UI thread is otherwise disallowed. |
| base::ScopedAllowBaseSyncPrimitivesForTesting scoped_allow_sync_primitives; |
| |
| // Deleting |thread| will implicitly stop and join it. |
| delete thread; |
| } |
| |
| } // namespace |
| |
| // static |
| CefRefPtr<CefThread> CefThread::CreateThread( |
| const CefString& display_name, |
| cef_thread_priority_t priority, |
| cef_message_loop_type_t message_loop_type, |
| bool stoppable, |
| cef_com_init_mode_t com_init_mode) { |
| if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) { |
| NOTREACHED() << "called on invalid thread"; |
| return nullptr; |
| } |
| |
| CefRefPtr<CefThreadImpl> thread_impl = new CefThreadImpl(); |
| if (!thread_impl->Create(display_name, priority, message_loop_type, stoppable, |
| com_init_mode)) { |
| return nullptr; |
| } |
| return thread_impl; |
| } |
| |
| CefThreadImpl::CefThreadImpl() : thread_id_(kInvalidPlatformThreadId) {} |
| |
| CefThreadImpl::~CefThreadImpl() { |
| if (thread_.get()) { |
| if (!owner_task_runner_->RunsTasksInCurrentSequence()) { |
| // Delete |thread_| on the correct thread. |
| owner_task_runner_->PostTask( |
| FROM_HERE, |
| base::Bind(StopAndDestroy, base::Unretained(thread_.release()))); |
| } else { |
| StopAndDestroy(thread_.release()); |
| } |
| } |
| } |
| |
| bool CefThreadImpl::Create(const CefString& display_name, |
| cef_thread_priority_t priority, |
| cef_message_loop_type_t message_loop_type, |
| bool stoppable, |
| cef_com_init_mode_t com_init_mode) { |
| owner_task_runner_ = CefTaskRunnerImpl::GetCurrentTaskRunner(); |
| DCHECK(owner_task_runner_); |
| if (!owner_task_runner_) |
| return false; |
| |
| thread_.reset(new base::Thread(display_name)); |
| |
| base::Thread::Options options; |
| |
| switch (priority) { |
| case TP_BACKGROUND: |
| options.priority = base::ThreadPriority::BACKGROUND; |
| break; |
| case TP_DISPLAY: |
| options.priority = base::ThreadPriority::DISPLAY; |
| break; |
| case TP_REALTIME_AUDIO: |
| options.priority = base::ThreadPriority::REALTIME_AUDIO; |
| break; |
| default: |
| break; |
| } |
| |
| switch (message_loop_type) { |
| case ML_TYPE_UI: |
| options.message_pump_type = base::MessagePumpType::UI; |
| break; |
| case ML_TYPE_IO: |
| options.message_pump_type = base::MessagePumpType::IO; |
| break; |
| default: |
| break; |
| } |
| |
| options.joinable = stoppable; |
| |
| #if defined(OS_WIN) |
| if (com_init_mode != COM_INIT_MODE_NONE) { |
| if (com_init_mode == COM_INIT_MODE_STA) |
| options.message_pump_type = base::MessagePumpType::UI; |
| thread_->init_com_with_mta(com_init_mode == COM_INIT_MODE_MTA); |
| } |
| #endif |
| |
| if (!thread_->StartWithOptions(options)) { |
| thread_.reset(); |
| return false; |
| } |
| |
| thread_task_runner_ = new CefTaskRunnerImpl(thread_->task_runner()); |
| thread_id_ = thread_->GetThreadId(); |
| return true; |
| } |
| |
| CefRefPtr<CefTaskRunner> CefThreadImpl::GetTaskRunner() { |
| return thread_task_runner_; |
| } |
| |
| cef_platform_thread_id_t CefThreadImpl::GetPlatformThreadId() { |
| return thread_id_; |
| } |
| |
| void CefThreadImpl::Stop() { |
| if (!owner_task_runner_) |
| return; |
| if (!owner_task_runner_->RunsTasksInCurrentSequence()) { |
| NOTREACHED() << "called on invalid thread"; |
| return; |
| } |
| |
| if (thread_) |
| StopAndDestroy(thread_.release()); |
| } |
| |
| bool CefThreadImpl::IsRunning() { |
| if (!owner_task_runner_) |
| return false; |
| if (!owner_task_runner_->RunsTasksInCurrentSequence()) { |
| NOTREACHED() << "called on invalid thread"; |
| return false; |
| } |
| |
| return thread_ && thread_->IsRunning(); |
| } |