1 // Copyright 2016 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4
5 #include "libcef/common/thread_impl.h"
6
7 #include "libcef/common/task_runner_impl.h"
8
9 #include "base/bind.h"
10 #include "base/threading/thread_restrictions.h"
11
12 namespace {
13
StopAndDestroy(base::Thread * thread)14 void StopAndDestroy(base::Thread* thread) {
15 // Calling PlatformThread::Join() on the UI thread is otherwise disallowed.
16 base::ScopedAllowBaseSyncPrimitivesForTesting scoped_allow_sync_primitives;
17
18 // Deleting |thread| will implicitly stop and join it.
19 delete thread;
20 }
21
22 } // namespace
23
24 // static
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)25 CefRefPtr<CefThread> CefThread::CreateThread(
26 const CefString& display_name,
27 cef_thread_priority_t priority,
28 cef_message_loop_type_t message_loop_type,
29 bool stoppable,
30 cef_com_init_mode_t com_init_mode) {
31 if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) {
32 NOTREACHED() << "called on invalid thread";
33 return nullptr;
34 }
35
36 CefRefPtr<CefThreadImpl> thread_impl = new CefThreadImpl();
37 if (!thread_impl->Create(display_name, priority, message_loop_type, stoppable,
38 com_init_mode)) {
39 return nullptr;
40 }
41 return thread_impl;
42 }
43
CefThreadImpl()44 CefThreadImpl::CefThreadImpl() : thread_id_(kInvalidPlatformThreadId) {}
45
~CefThreadImpl()46 CefThreadImpl::~CefThreadImpl() {
47 if (thread_.get()) {
48 if (!owner_task_runner_->RunsTasksInCurrentSequence()) {
49 // Delete |thread_| on the correct thread.
50 owner_task_runner_->PostTask(
51 FROM_HERE,
52 base::BindOnce(StopAndDestroy, base::Unretained(thread_.release())));
53 } else {
54 StopAndDestroy(thread_.release());
55 }
56 }
57 }
58
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)59 bool CefThreadImpl::Create(const CefString& display_name,
60 cef_thread_priority_t priority,
61 cef_message_loop_type_t message_loop_type,
62 bool stoppable,
63 cef_com_init_mode_t com_init_mode) {
64 owner_task_runner_ = CefTaskRunnerImpl::GetCurrentTaskRunner();
65 DCHECK(owner_task_runner_);
66 if (!owner_task_runner_)
67 return false;
68
69 thread_.reset(new base::Thread(display_name));
70
71 base::Thread::Options options;
72
73 switch (priority) {
74 case TP_BACKGROUND:
75 options.priority = base::ThreadPriority::BACKGROUND;
76 break;
77 case TP_DISPLAY:
78 options.priority = base::ThreadPriority::DISPLAY;
79 break;
80 case TP_REALTIME_AUDIO:
81 options.priority = base::ThreadPriority::REALTIME_AUDIO;
82 break;
83 default:
84 break;
85 }
86
87 switch (message_loop_type) {
88 case ML_TYPE_UI:
89 options.message_pump_type = base::MessagePumpType::UI;
90 break;
91 case ML_TYPE_IO:
92 options.message_pump_type = base::MessagePumpType::IO;
93 break;
94 default:
95 break;
96 }
97
98 options.joinable = stoppable;
99
100 #if BUILDFLAG(IS_WIN)
101 if (com_init_mode != COM_INIT_MODE_NONE) {
102 if (com_init_mode == COM_INIT_MODE_STA)
103 options.message_pump_type = base::MessagePumpType::UI;
104 thread_->init_com_with_mta(com_init_mode == COM_INIT_MODE_MTA);
105 }
106 #endif
107
108 if (!thread_->StartWithOptions(std::move(options))) {
109 thread_.reset();
110 return false;
111 }
112
113 thread_task_runner_ = new CefTaskRunnerImpl(thread_->task_runner());
114 thread_id_ = thread_->GetThreadId();
115 return true;
116 }
117
GetTaskRunner()118 CefRefPtr<CefTaskRunner> CefThreadImpl::GetTaskRunner() {
119 return thread_task_runner_;
120 }
121
GetPlatformThreadId()122 cef_platform_thread_id_t CefThreadImpl::GetPlatformThreadId() {
123 return thread_id_;
124 }
125
Stop()126 void CefThreadImpl::Stop() {
127 if (!owner_task_runner_)
128 return;
129 if (!owner_task_runner_->RunsTasksInCurrentSequence()) {
130 NOTREACHED() << "called on invalid thread";
131 return;
132 }
133
134 if (thread_)
135 StopAndDestroy(thread_.release());
136 }
137
IsRunning()138 bool CefThreadImpl::IsRunning() {
139 if (!owner_task_runner_)
140 return false;
141 if (!owner_task_runner_->RunsTasksInCurrentSequence()) {
142 NOTREACHED() << "called on invalid thread";
143 return false;
144 }
145
146 return thread_ && thread_->IsRunning();
147 }
148