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