|  | // Copyright 2018 The Chromium 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 "base/message_loop/message_loop_current.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/message_loop/message_pump_for_io.h" | 
|  | #include "base/message_loop/message_pump_for_ui.h" | 
|  | #include "base/no_destructor.h" | 
|  | #include "base/threading/thread_local.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | base::ThreadLocalPointer<MessageLoop>* GetTLSMessageLoop() { | 
|  | static NoDestructor<ThreadLocalPointer<MessageLoop>> lazy_tls_ptr; | 
|  | return lazy_tls_ptr.get(); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | //------------------------------------------------------------------------------ | 
|  | // MessageLoopCurrent | 
|  |  | 
|  | // static | 
|  | MessageLoopCurrent MessageLoopCurrent::Get() { | 
|  | return MessageLoopCurrent(GetTLSMessageLoop()->Get()); | 
|  | } | 
|  |  | 
|  | // static | 
|  | bool MessageLoopCurrent::IsSet() { | 
|  | return !!GetTLSMessageLoop()->Get(); | 
|  | } | 
|  |  | 
|  | void MessageLoopCurrent::AddDestructionObserver( | 
|  | DestructionObserver* destruction_observer) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | current_->destruction_observers_.AddObserver(destruction_observer); | 
|  | } | 
|  |  | 
|  | void MessageLoopCurrent::RemoveDestructionObserver( | 
|  | DestructionObserver* destruction_observer) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | current_->destruction_observers_.RemoveObserver(destruction_observer); | 
|  | } | 
|  |  | 
|  | const scoped_refptr<SingleThreadTaskRunner>& MessageLoopCurrent::task_runner() | 
|  | const { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return current_->task_runner(); | 
|  | } | 
|  |  | 
|  | void MessageLoopCurrent::SetTaskRunner( | 
|  | scoped_refptr<SingleThreadTaskRunner> task_runner) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | current_->SetTaskRunner(std::move(task_runner)); | 
|  | } | 
|  |  | 
|  | bool MessageLoopCurrent::IsIdleForTesting() { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return current_->IsIdleForTesting(); | 
|  | } | 
|  |  | 
|  | void MessageLoopCurrent::AddTaskObserver(TaskObserver* task_observer) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | current_->AddTaskObserver(task_observer); | 
|  | } | 
|  |  | 
|  | void MessageLoopCurrent::RemoveTaskObserver(TaskObserver* task_observer) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | current_->RemoveTaskObserver(task_observer); | 
|  | } | 
|  |  | 
|  | void MessageLoopCurrent::SetNestableTasksAllowed(bool allowed) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | if (allowed) { | 
|  | // Kick the native pump just in case we enter a OS-driven nested message | 
|  | // loop that does not go through RunLoop::Run(). | 
|  | current_->pump_->ScheduleWork(); | 
|  | } | 
|  | current_->task_execution_allowed_ = allowed; | 
|  | } | 
|  |  | 
|  | bool MessageLoopCurrent::NestableTasksAllowed() const { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return current_->task_execution_allowed_; | 
|  | } | 
|  |  | 
|  | MessageLoopCurrent::ScopedNestableTaskAllower::ScopedNestableTaskAllower() | 
|  | : loop_(GetTLSMessageLoop()->Get()), | 
|  | old_state_(loop_->NestableTasksAllowed()) { | 
|  | loop_->SetNestableTasksAllowed(true); | 
|  | } | 
|  |  | 
|  | MessageLoopCurrent::ScopedNestableTaskAllower::~ScopedNestableTaskAllower() { | 
|  | loop_->SetNestableTasksAllowed(old_state_); | 
|  | } | 
|  |  | 
|  | // static | 
|  | void MessageLoopCurrent::BindToCurrentThreadInternal(MessageLoop* current) { | 
|  | DCHECK(!GetTLSMessageLoop()->Get()) | 
|  | << "Can't register a second MessageLoop on the same thread."; | 
|  | GetTLSMessageLoop()->Set(current); | 
|  | } | 
|  |  | 
|  | // static | 
|  | void MessageLoopCurrent::UnbindFromCurrentThreadInternal(MessageLoop* current) { | 
|  | DCHECK_EQ(current, GetTLSMessageLoop()->Get()); | 
|  | GetTLSMessageLoop()->Set(nullptr); | 
|  | } | 
|  |  | 
|  | bool MessageLoopCurrent::IsBoundToCurrentThreadInternal( | 
|  | MessageLoop* message_loop) { | 
|  | return GetTLSMessageLoop()->Get() == message_loop; | 
|  | } | 
|  |  | 
|  | #if !defined(OS_NACL) | 
|  |  | 
|  | //------------------------------------------------------------------------------ | 
|  | // MessageLoopCurrentForUI | 
|  |  | 
|  | // static | 
|  | MessageLoopCurrentForUI MessageLoopCurrentForUI::Get() { | 
|  | MessageLoop* loop = GetTLSMessageLoop()->Get(); | 
|  | DCHECK(loop); | 
|  | #if defined(OS_ANDROID) | 
|  | DCHECK(loop->IsType(MessageLoop::TYPE_UI) || | 
|  | loop->IsType(MessageLoop::TYPE_JAVA)); | 
|  | #else   // defined(OS_ANDROID) | 
|  | DCHECK(loop->IsType(MessageLoop::TYPE_UI)); | 
|  | #endif  // defined(OS_ANDROID) | 
|  | auto* loop_for_ui = static_cast<MessageLoopForUI*>(loop); | 
|  | return MessageLoopCurrentForUI( | 
|  | loop_for_ui, static_cast<MessagePumpForUI*>(loop_for_ui->pump_.get())); | 
|  | } | 
|  |  | 
|  | // static | 
|  | bool MessageLoopCurrentForUI::IsSet() { | 
|  | MessageLoop* loop = GetTLSMessageLoop()->Get(); | 
|  | return loop && | 
|  | #if defined(OS_ANDROID) | 
|  | (loop->IsType(MessageLoop::TYPE_UI) || | 
|  | loop->IsType(MessageLoop::TYPE_JAVA)); | 
|  | #else   // defined(OS_ANDROID) | 
|  | loop->IsType(MessageLoop::TYPE_UI); | 
|  | #endif  // defined(OS_ANDROID) | 
|  | } | 
|  |  | 
|  | #if defined(USE_OZONE) && !defined(OS_FUCHSIA) && !defined(OS_WIN) | 
|  | bool MessageLoopCurrentForUI::WatchFileDescriptor( | 
|  | int fd, | 
|  | bool persistent, | 
|  | MessagePumpForUI::Mode mode, | 
|  | MessagePumpForUI::FdWatchController* controller, | 
|  | MessagePumpForUI::FdWatcher* delegate) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return pump_->WatchFileDescriptor(fd, persistent, mode, controller, delegate); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #if defined(OS_IOS) | 
|  | void MessageLoopCurrentForUI::Attach() { | 
|  | static_cast<MessageLoopForUI*>(current_)->Attach(); | 
|  | } | 
|  | #endif  // defined(OS_IOS) | 
|  |  | 
|  | #if defined(OS_ANDROID) | 
|  | void MessageLoopCurrentForUI::Start() { | 
|  | static_cast<MessageLoopForUI*>(current_)->Start(); | 
|  | } | 
|  |  | 
|  | void MessageLoopCurrentForUI::Abort() { | 
|  | static_cast<MessageLoopForUI*>(current_)->Abort(); | 
|  | } | 
|  | #endif  // defined(OS_ANDROID) | 
|  |  | 
|  | #endif  // !defined(OS_NACL) | 
|  |  | 
|  | //------------------------------------------------------------------------------ | 
|  | // MessageLoopCurrentForIO | 
|  |  | 
|  | // static | 
|  | MessageLoopCurrentForIO MessageLoopCurrentForIO::Get() { | 
|  | MessageLoop* loop = GetTLSMessageLoop()->Get(); | 
|  | DCHECK(loop); | 
|  | DCHECK_EQ(MessageLoop::TYPE_IO, loop->type()); | 
|  | auto* loop_for_io = static_cast<MessageLoopForIO*>(loop); | 
|  | return MessageLoopCurrentForIO( | 
|  | loop_for_io, static_cast<MessagePumpForIO*>(loop_for_io->pump_.get())); | 
|  | } | 
|  |  | 
|  | // static | 
|  | bool MessageLoopCurrentForIO::IsSet() { | 
|  | MessageLoop* loop = GetTLSMessageLoop()->Get(); | 
|  | return loop && loop->IsType(MessageLoop::TYPE_IO); | 
|  | } | 
|  |  | 
|  | #if !defined(OS_NACL_SFI) | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | void MessageLoopCurrentForIO::RegisterIOHandler( | 
|  | HANDLE file, | 
|  | MessagePumpForIO::IOHandler* handler) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | pump_->RegisterIOHandler(file, handler); | 
|  | } | 
|  |  | 
|  | bool MessageLoopCurrentForIO::RegisterJobObject( | 
|  | HANDLE job, | 
|  | MessagePumpForIO::IOHandler* handler) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return pump_->RegisterJobObject(job, handler); | 
|  | } | 
|  |  | 
|  | bool MessageLoopCurrentForIO::WaitForIOCompletion( | 
|  | DWORD timeout, | 
|  | MessagePumpForIO::IOHandler* filter) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return pump_->WaitForIOCompletion(timeout, filter); | 
|  | } | 
|  | #elif defined(OS_POSIX) || defined(OS_FUCHSIA) | 
|  | bool MessageLoopCurrentForIO::WatchFileDescriptor( | 
|  | int fd, | 
|  | bool persistent, | 
|  | MessagePumpForIO::Mode mode, | 
|  | MessagePumpForIO::FdWatchController* controller, | 
|  | MessagePumpForIO::FdWatcher* delegate) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return pump_->WatchFileDescriptor(fd, persistent, mode, controller, delegate); | 
|  | } | 
|  | #endif  // defined(OS_WIN) | 
|  |  | 
|  | #endif  // !defined(OS_NACL_SFI) | 
|  |  | 
|  | #if defined(OS_FUCHSIA) | 
|  | // Additional watch API for native platform resources. | 
|  | bool MessageLoopCurrentForIO::WatchZxHandle( | 
|  | zx_handle_t handle, | 
|  | bool persistent, | 
|  | zx_signals_t signals, | 
|  | MessagePumpForIO::ZxHandleWatchController* controller, | 
|  | MessagePumpForIO::ZxHandleWatcher* delegate) { | 
|  | DCHECK_CALLED_ON_VALID_THREAD(current_->bound_thread_checker_); | 
|  | return pump_->WatchZxHandle(handle, persistent, signals, controller, | 
|  | delegate); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | }  // namespace base |