| // 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(); | |
| } |