1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/message_loop/message_loop_current.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/message_loop/message_pump_for_io.h"
10 #include "base/message_loop/message_pump_for_ui.h"
11 #include "base/no_destructor.h"
12 #include "base/threading/thread_local.h"
13
14 namespace base {
15
16 namespace {
17
GetTLSMessageLoop()18 base::ThreadLocalPointer<MessageLoop>* GetTLSMessageLoop() {
19 static NoDestructor<ThreadLocalPointer<MessageLoop>> lazy_tls_ptr;
20 return lazy_tls_ptr.get();
21 }
22
23 } // namespace
24
25 //------------------------------------------------------------------------------
26 // MessageLoopCurrent
27
28 // static
Get()29 MessageLoopCurrent MessageLoopCurrent::Get() {
30 return MessageLoopCurrent(GetTLSMessageLoop()->Get());
31 }
32
33 // static
IsSet()34 bool MessageLoopCurrent::IsSet() {
35 return !!GetTLSMessageLoop()->Get();
36 }
37
AddDestructionObserver(DestructionObserver * destruction_observer)38 void MessageLoopCurrent::AddDestructionObserver(
39 DestructionObserver* destruction_observer) {
40 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
41 current_->destruction_observers_.AddObserver(destruction_observer);
42 }
43
RemoveDestructionObserver(DestructionObserver * destruction_observer)44 void MessageLoopCurrent::RemoveDestructionObserver(
45 DestructionObserver* destruction_observer) {
46 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
47 current_->destruction_observers_.RemoveObserver(destruction_observer);
48 }
49
task_runner() const50 const scoped_refptr<SingleThreadTaskRunner>& MessageLoopCurrent::task_runner()
51 const {
52 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
53 return current_->task_runner();
54 }
55
SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner)56 void MessageLoopCurrent::SetTaskRunner(
57 scoped_refptr<SingleThreadTaskRunner> task_runner) {
58 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
59 current_->SetTaskRunner(std::move(task_runner));
60 }
61
IsIdleForTesting()62 bool MessageLoopCurrent::IsIdleForTesting() {
63 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
64 return current_->IsIdleForTesting();
65 }
66
AddTaskObserver(TaskObserver * task_observer)67 void MessageLoopCurrent::AddTaskObserver(TaskObserver* task_observer) {
68 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
69 current_->AddTaskObserver(task_observer);
70 }
71
RemoveTaskObserver(TaskObserver * task_observer)72 void MessageLoopCurrent::RemoveTaskObserver(TaskObserver* task_observer) {
73 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
74 current_->RemoveTaskObserver(task_observer);
75 }
76
SetNestableTasksAllowed(bool allowed)77 void MessageLoopCurrent::SetNestableTasksAllowed(bool allowed) {
78 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
79 if (allowed) {
80 // Kick the native pump just in case we enter a OS-driven nested message
81 // loop that does not go through RunLoop::Run().
82 current_->pump_->ScheduleWork();
83 }
84 current_->task_execution_allowed_ = allowed;
85 }
86
NestableTasksAllowed() const87 bool MessageLoopCurrent::NestableTasksAllowed() const {
88 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
89 return current_->task_execution_allowed_;
90 }
91
ScopedNestableTaskAllower()92 MessageLoopCurrent::ScopedNestableTaskAllower::ScopedNestableTaskAllower()
93 : loop_(GetTLSMessageLoop()->Get()),
94 old_state_(loop_->NestableTasksAllowed()) {
95 loop_->SetNestableTasksAllowed(true);
96 }
97
~ScopedNestableTaskAllower()98 MessageLoopCurrent::ScopedNestableTaskAllower::~ScopedNestableTaskAllower() {
99 loop_->SetNestableTasksAllowed(old_state_);
100 }
101
102 // static
BindToCurrentThreadInternal(MessageLoop * current)103 void MessageLoopCurrent::BindToCurrentThreadInternal(MessageLoop* current) {
104 DCHECK(!GetTLSMessageLoop()->Get())
105 << "Can't register a second MessageLoop on the same thread.";
106 GetTLSMessageLoop()->Set(current);
107 }
108
109 // static
UnbindFromCurrentThreadInternal(MessageLoop * current)110 void MessageLoopCurrent::UnbindFromCurrentThreadInternal(MessageLoop* current) {
111 DCHECK_EQ(current, GetTLSMessageLoop()->Get());
112 GetTLSMessageLoop()->Set(nullptr);
113 }
114
IsBoundToCurrentThreadInternal(MessageLoop * message_loop)115 bool MessageLoopCurrent::IsBoundToCurrentThreadInternal(
116 MessageLoop* message_loop) {
117 return GetTLSMessageLoop()->Get() == message_loop;
118 }
119
120 #if !defined(OS_NACL)
121
122 //------------------------------------------------------------------------------
123 // MessageLoopCurrentForUI
124
125 // static
Get()126 MessageLoopCurrentForUI MessageLoopCurrentForUI::Get() {
127 MessageLoop* loop = GetTLSMessageLoop()->Get();
128 DCHECK(loop);
129 #if defined(OS_ANDROID)
130 DCHECK(loop->IsType(MessageLoop::TYPE_UI) ||
131 loop->IsType(MessageLoop::TYPE_JAVA));
132 #else // defined(OS_ANDROID)
133 DCHECK(loop->IsType(MessageLoop::TYPE_UI));
134 #endif // defined(OS_ANDROID)
135 auto* loop_for_ui = static_cast<MessageLoopForUI*>(loop);
136 return MessageLoopCurrentForUI(
137 loop_for_ui, static_cast<MessagePumpForUI*>(loop_for_ui->pump_.get()));
138 }
139
140 // static
IsSet()141 bool MessageLoopCurrentForUI::IsSet() {
142 MessageLoop* loop = GetTLSMessageLoop()->Get();
143 return loop &&
144 #if defined(OS_ANDROID)
145 (loop->IsType(MessageLoop::TYPE_UI) ||
146 loop->IsType(MessageLoop::TYPE_JAVA));
147 #else // defined(OS_ANDROID)
148 loop->IsType(MessageLoop::TYPE_UI);
149 #endif // defined(OS_ANDROID)
150 }
151
152 #if defined(USE_OZONE) && !defined(OS_FUCHSIA) && !defined(OS_WIN)
WatchFileDescriptor(int fd,bool persistent,MessagePumpForUI::Mode mode,MessagePumpForUI::FdWatchController * controller,MessagePumpForUI::FdWatcher * delegate)153 bool MessageLoopCurrentForUI::WatchFileDescriptor(
154 int fd,
155 bool persistent,
156 MessagePumpForUI::Mode mode,
157 MessagePumpForUI::FdWatchController* controller,
158 MessagePumpForUI::FdWatcher* delegate) {
159 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
160 return pump_->WatchFileDescriptor(fd, persistent, mode, controller, delegate);
161 }
162 #endif
163
164 #if defined(OS_IOS)
Attach()165 void MessageLoopCurrentForUI::Attach() {
166 static_cast<MessageLoopForUI*>(current_)->Attach();
167 }
168 #endif // defined(OS_IOS)
169
170 #if defined(OS_ANDROID)
Abort()171 void MessageLoopCurrentForUI::Abort() {
172 static_cast<MessageLoopForUI*>(current_)->Abort();
173 }
174 #endif // defined(OS_ANDROID)
175
176 #endif // !defined(OS_NACL)
177
178 //------------------------------------------------------------------------------
179 // MessageLoopCurrentForIO
180
181 // static
Get()182 MessageLoopCurrentForIO MessageLoopCurrentForIO::Get() {
183 MessageLoop* loop = GetTLSMessageLoop()->Get();
184 DCHECK(loop);
185 DCHECK_EQ(MessageLoop::TYPE_IO, loop->type());
186 auto* loop_for_io = static_cast<MessageLoopForIO*>(loop);
187 return MessageLoopCurrentForIO(
188 loop_for_io, static_cast<MessagePumpForIO*>(loop_for_io->pump_.get()));
189 }
190
191 // static
IsSet()192 bool MessageLoopCurrentForIO::IsSet() {
193 MessageLoop* loop = GetTLSMessageLoop()->Get();
194 return loop && loop->IsType(MessageLoop::TYPE_IO);
195 }
196
197 #if !defined(OS_NACL_SFI)
198
199 #if defined(OS_WIN)
RegisterIOHandler(HANDLE file,MessagePumpForIO::IOHandler * handler)200 HRESULT MessageLoopCurrentForIO::RegisterIOHandler(
201 HANDLE file,
202 MessagePumpForIO::IOHandler* handler) {
203 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
204 return pump_->RegisterIOHandler(file, handler);
205 }
206
RegisterJobObject(HANDLE job,MessagePumpForIO::IOHandler * handler)207 bool MessageLoopCurrentForIO::RegisterJobObject(
208 HANDLE job,
209 MessagePumpForIO::IOHandler* handler) {
210 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
211 return pump_->RegisterJobObject(job, handler);
212 }
213
WaitForIOCompletion(DWORD timeout,MessagePumpForIO::IOHandler * filter)214 bool MessageLoopCurrentForIO::WaitForIOCompletion(
215 DWORD timeout,
216 MessagePumpForIO::IOHandler* filter) {
217 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
218 return pump_->WaitForIOCompletion(timeout, filter);
219 }
220 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
WatchFileDescriptor(int fd,bool persistent,MessagePumpForIO::Mode mode,MessagePumpForIO::FdWatchController * controller,MessagePumpForIO::FdWatcher * delegate)221 bool MessageLoopCurrentForIO::WatchFileDescriptor(
222 int fd,
223 bool persistent,
224 MessagePumpForIO::Mode mode,
225 MessagePumpForIO::FdWatchController* controller,
226 MessagePumpForIO::FdWatcher* delegate) {
227 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
228 return pump_->WatchFileDescriptor(fd, persistent, mode, controller, delegate);
229 }
230 #endif // defined(OS_WIN)
231
232 #endif // !defined(OS_NACL_SFI)
233
234 #if defined(OS_FUCHSIA)
235 // Additional watch API for native platform resources.
WatchZxHandle(zx_handle_t handle,bool persistent,zx_signals_t signals,MessagePumpForIO::ZxHandleWatchController * controller,MessagePumpForIO::ZxHandleWatcher * delegate)236 bool MessageLoopCurrentForIO::WatchZxHandle(
237 zx_handle_t handle,
238 bool persistent,
239 zx_signals_t signals,
240 MessagePumpForIO::ZxHandleWatchController* controller,
241 MessagePumpForIO::ZxHandleWatcher* delegate) {
242 DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_);
243 return pump_->WatchZxHandle(handle, persistent, signals, controller,
244 delegate);
245 }
246 #endif
247
248 } // namespace base
249