diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-24 12:15:48 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 13:30:04 +0000 |
commit | b014812705fc80bff0a5c120dfcef88f349816dc (patch) | |
tree | 25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/base/message_loop | |
parent | 9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff) |
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/base/message_loop')
19 files changed, 942 insertions, 605 deletions
diff --git a/chromium/base/message_loop/message_loop.cc b/chromium/base/message_loop/message_loop.cc index b417f2fffe8..97ed778d8f1 100644 --- a/chromium/base/message_loop/message_loop.cc +++ b/chromium/base/message_loop/message_loop.cc @@ -12,11 +12,11 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_pump_default.h" +#include "base/message_loop/message_pump_for_io.h" #include "base/message_loop/message_pump_for_ui.h" #include "base/run_loop.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/threading/thread_id_name_manager.h" -#include "base/threading/thread_local.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" @@ -28,12 +28,6 @@ namespace base { namespace { -// A lazily created thread local storage for quick access to a thread's message -// loop, if one exists. -base::ThreadLocalPointer<MessageLoop>* GetTLSMessageLoop() { - static auto* lazy_tls_ptr = new base::ThreadLocalPointer<MessageLoop>(); - return lazy_tls_ptr; -} MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = nullptr; std::unique_ptr<MessagePump> ReturnPump(std::unique_ptr<MessagePump> pump) { @@ -44,14 +38,6 @@ std::unique_ptr<MessagePump> ReturnPump(std::unique_ptr<MessagePump> pump) { //------------------------------------------------------------------------------ -MessageLoop::TaskObserver::TaskObserver() = default; - -MessageLoop::TaskObserver::~TaskObserver() = default; - -MessageLoop::DestructionObserver::~DestructionObserver() = default; - -//------------------------------------------------------------------------------ - MessageLoop::MessageLoop(Type type) : MessageLoop(type, MessagePumpFactoryCallback()) { BindToCurrentThread(); @@ -67,7 +53,8 @@ MessageLoop::~MessageLoop() { // current one on this thread. Otherwise, this loop is being destructed before // it was bound to a thread, so a different message loop (or no loop at all) // may be current. - DCHECK((pump_ && current() == this) || (!pump_ && current() != this)); + DCHECK((pump_ && MessageLoopCurrent::IsBoundToCurrentThreadInternal(this)) || + (!pump_ && !MessageLoopCurrent::IsBoundToCurrentThreadInternal(this))); // iOS just attaches to the loop, it doesn't Run it. // TODO(stuartmorgan): Consider wiring up a Detach(). @@ -75,8 +62,10 @@ MessageLoop::~MessageLoop() { // There should be no active RunLoops on this thread, unless this MessageLoop // isn't bound to the current thread (see other condition at the top of this // method). - DCHECK((!pump_ && current() != this) || !RunLoop::IsRunningOnCurrentThread()); -#endif + DCHECK( + (!pump_ && !MessageLoopCurrent::IsBoundToCurrentThreadInternal(this)) || + !RunLoop::IsRunningOnCurrentThread()); +#endif // !defined(OS_IOS) #if defined(OS_WIN) if (in_high_res_mode_) @@ -111,16 +100,13 @@ MessageLoop::~MessageLoop() { task_runner_ = nullptr; // OK, now make it so that no one can find us. - if (current() == this) - GetTLSMessageLoop()->Set(nullptr); + if (MessageLoopCurrent::IsBoundToCurrentThreadInternal(this)) + MessageLoopCurrent::UnbindFromCurrentThreadInternal(this); } // static -MessageLoop* MessageLoop::current() { - // TODO(darin): sadly, we cannot enable this yet since people call us even - // when they have no intention of using us. - // DCHECK(loop) << "Ouch, did you forget to initialize me?"; - return GetTLSMessageLoop()->Get(); +MessageLoopCurrent MessageLoop::current() { + return MessageLoopCurrent::Get(); } // static @@ -166,50 +152,20 @@ std::unique_ptr<MessagePump> MessageLoop::CreateMessagePumpForType(Type type) { #endif } -void MessageLoop::AddDestructionObserver( - DestructionObserver* destruction_observer) { - DCHECK_EQ(this, current()); - destruction_observers_.AddObserver(destruction_observer); -} - -void MessageLoop::RemoveDestructionObserver( - DestructionObserver* destruction_observer) { - DCHECK_EQ(this, current()); - destruction_observers_.RemoveObserver(destruction_observer); -} - bool MessageLoop::IsType(Type type) const { return type_ == type; } -// static -Closure MessageLoop::QuitWhenIdleClosure() { - return Bind(&RunLoop::QuitCurrentWhenIdleDeprecated); -} - -void MessageLoop::SetNestableTasksAllowed(bool allowed) { - if (allowed) { - // Kick the native pump just in case we enter a OS-driven nested message - // loop that does not go through RunLoop::Run(). - pump_->ScheduleWork(); - } - task_execution_allowed_ = allowed; -} - -bool MessageLoop::NestableTasksAllowed() const { - return task_execution_allowed_; -} - // TODO(gab): Migrate TaskObservers to RunLoop as part of separating concerns // between MessageLoop and RunLoop and making MessageLoop a swappable // implementation detail. http://crbug.com/703346 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); task_observers_.AddObserver(task_observer); } void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); task_observers_.RemoveObserver(task_observer); } @@ -237,7 +193,8 @@ std::unique_ptr<MessageLoop> MessageLoop::CreateUnbound( } MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) - : type_(type), + : MessageLoopCurrent(this), + type_(type), pump_factory_(std::move(pump_factory)), incoming_task_queue_(new internal::IncomingTaskQueue(this)), unbound_task_runner_( @@ -245,17 +202,23 @@ MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) task_runner_(unbound_task_runner_) { // If type is TYPE_CUSTOM non-null pump_factory must be given. DCHECK(type_ != TYPE_CUSTOM || !pump_factory_.is_null()); + + // Bound in BindToCurrentThread(); + DETACH_FROM_THREAD(bound_thread_checker_); } void MessageLoop::BindToCurrentThread() { + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); + DCHECK(!pump_); if (!pump_factory_.is_null()) pump_ = std::move(pump_factory_).Run(); else pump_ = CreateMessagePumpForType(type_); - DCHECK(!current()) << "should only have one message loop per thread"; - GetTLSMessageLoop()->Set(this); + DCHECK(!MessageLoopCurrent::IsSet()) + << "should only have one message loop per thread"; + MessageLoopCurrent::BindToCurrentThreadInternal(this); incoming_task_queue_->StartScheduling(); unbound_task_runner_->BindToCurrentThread(); @@ -279,7 +242,8 @@ std::string MessageLoop::GetThreadName() const { void MessageLoop::SetTaskRunner( scoped_refptr<SingleThreadTaskRunner> task_runner) { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); + DCHECK(task_runner); DCHECK(task_runner->BelongsToCurrentThread()); DCHECK(!unbound_task_runner_); @@ -288,14 +252,15 @@ void MessageLoop::SetTaskRunner( } void MessageLoop::ClearTaskRunnerForTesting() { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); + DCHECK(!unbound_task_runner_); task_runner_ = nullptr; thread_task_runner_handle_.reset(); } void MessageLoop::Run(bool application_tasks_allowed) { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); if (application_tasks_allowed && !task_execution_allowed_) { // Allow nested task execution as explicitly requested. DCHECK(RunLoop::IsNestedOnCurrentThread()); @@ -308,18 +273,18 @@ void MessageLoop::Run(bool application_tasks_allowed) { } void MessageLoop::Quit() { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); pump_->Quit(); } void MessageLoop::EnsureWorkScheduled() { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); if (incoming_task_queue_->triage_tasks().HasTasks()) pump_->ScheduleWork(); } void MessageLoop::SetThreadTaskRunnerHandle() { - DCHECK_EQ(this, current()); + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); // Clear the previous thread task runner first, because only one can exist at // a time. thread_task_runner_handle_.reset(); @@ -471,12 +436,29 @@ bool MessageLoop::DoIdleWork() { } #if !defined(OS_NACL) + //------------------------------------------------------------------------------ // MessageLoopForUI MessageLoopForUI::MessageLoopForUI(std::unique_ptr<MessagePump> pump) : MessageLoop(TYPE_UI, BindOnce(&ReturnPump, std::move(pump))) {} +// static +MessageLoopCurrentForUI MessageLoopForUI::current() { + return MessageLoopCurrentForUI::Get(); +} + +// static +bool MessageLoopForUI::IsCurrent() { + return MessageLoopCurrentForUI::IsSet(); +} + +#if defined(OS_IOS) +void MessageLoopForUI::Attach() { + static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this); +} +#endif // defined(OS_IOS) + #if defined(OS_ANDROID) void MessageLoopForUI::Start() { // No Histogram support for UI message loop as it is managed by Java side @@ -486,87 +468,27 @@ void MessageLoopForUI::Start() { void MessageLoopForUI::Abort() { static_cast<MessagePumpForUI*>(pump_.get())->Abort(); } -#endif +#endif // defined(OS_ANDROID) -#if defined(OS_IOS) -void MessageLoopForUI::Attach() { - static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this); +#if defined(OS_WIN) +void MessageLoopForUI::EnableWmQuit() { + static_cast<MessagePumpForUI*>(pump_.get())->EnableWmQuit(); } -#endif - -#if (defined(USE_OZONE) && !defined(OS_FUCHSIA)) || \ - (defined(USE_X11) && !defined(USE_GLIB)) -bool MessageLoopForUI::WatchFileDescriptor( - int fd, - bool persistent, - MessagePumpLibevent::Mode mode, - MessagePumpLibevent::FdWatchController* controller, - MessagePumpLibevent::FdWatcher* delegate) { - return static_cast<MessagePumpForUI*>(pump_.get()) - ->WatchFileDescriptor(fd, persistent, mode, controller, delegate); -} -#endif +#endif // defined(OS_WIN) #endif // !defined(OS_NACL) //------------------------------------------------------------------------------ // MessageLoopForIO -#if !defined(OS_NACL_SFI) - -namespace { - -MessagePumpForIO* ToPumpIO(MessagePump* pump) { - return static_cast<MessagePumpForIO*>(pump); -} - -} // namespace - -#if defined(OS_WIN) -void MessageLoopForIO::RegisterIOHandler(HANDLE file, - MessagePumpForIO::IOHandler* handler) { - ToPumpIO(pump_.get())->RegisterIOHandler(file, handler); -} - -bool MessageLoopForIO::RegisterJobObject(HANDLE job, - MessagePumpForIO::IOHandler* handler) { - return ToPumpIO(pump_.get())->RegisterJobObject(job, handler); -} - -bool MessageLoopForIO::WaitForIOCompletion( - DWORD timeout, - MessagePumpForIO::IOHandler* filter) { - return ToPumpIO(pump_.get())->WaitForIOCompletion(timeout, filter); -} -#elif defined(OS_POSIX) -bool MessageLoopForIO::WatchFileDescriptor( - int fd, - bool persistent, - MessagePumpForIO::Mode mode, - MessagePumpForIO::FdWatchController* controller, - MessagePumpForIO::FdWatcher* delegate) { - return ToPumpIO(pump_.get())->WatchFileDescriptor( - fd, - persistent, - mode, - controller, - delegate); +// static +MessageLoopCurrentForIO MessageLoopForIO::current() { + return MessageLoopCurrentForIO::Get(); } -#endif -#endif // !defined(OS_NACL_SFI) - -#if defined(OS_FUCHSIA) -// Additional watch API for native platform resources. -bool MessageLoopForIO::WatchZxHandle( - zx_handle_t handle, - bool persistent, - zx_signals_t signals, - MessagePumpForIO::ZxHandleWatchController* controller, - MessagePumpForIO::ZxHandleWatcher* delegate) { - return ToPumpIO(pump_.get()) - ->WatchZxHandle(handle, persistent, signals, controller, delegate); +// static +bool MessageLoopForIO::IsCurrent() { + return MessageLoopCurrentForIO::IsSet(); } -#endif } // namespace base diff --git a/chromium/base/message_loop/message_loop.h b/chromium/base/message_loop/message_loop.h index 439d364fc54..bd191fd9779 100644 --- a/chromium/base/message_loop/message_loop.h +++ b/chromium/base/message_loop/message_loop.h @@ -13,18 +13,18 @@ #include "base/callback_forward.h" #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" #include "base/message_loop/incoming_task_queue.h" +#include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_loop_task_runner.h" #include "base/message_loop/message_pump.h" -#include "base/message_loop/message_pump_for_io.h" -#include "base/message_loop/message_pump_for_ui.h" #include "base/message_loop/timer_slack.h" #include "base/observer_list.h" #include "base/pending_task.h" #include "base/run_loop.h" #include "base/synchronization/lock.h" #include "base/threading/sequence_local_storage_map.h" +#include "base/threading/thread_checker.h" #include "base/time/time.h" #include "build/build_config.h" @@ -41,6 +41,18 @@ class ThreadTaskRunnerHandle; // time permits) and signals sent to a registered set of HANDLEs may also be // processed. // +// The MessageLoop's API should only be used directly by its owner (and users +// which the owner opts to share a MessageLoop* with). Other ways to access +// subsets of the MessageLoop API: +// - base::RunLoop : Drive the MessageLoop from the thread it's bound to. +// - base::Thread/SequencedTaskRunnerHandle : Post back to the MessageLoop +// from a task running on it. +// - SequenceLocalStorageSlot : Bind external state to this MessageLoop. +// - base::MessageLoopCurrent : Access statically exposed APIs of this +// MessageLoop. +// - Embedders may provide their own static accessors to post tasks on +// specific loops (e.g. content::BrowserThreads). +// // NOTE: Unless otherwise specified, a MessageLoop's methods may only be called // on the thread where the MessageLoop's Run method executes. // @@ -55,7 +67,7 @@ class ThreadTaskRunnerHandle; // Sample workaround when inner task processing is needed: // HRESULT hr; // { -// MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); +// MessageLoopCurrent::ScopedNestableTaskAllower allow; // hr = DoDragDrop(...); // Implicitly runs a modal message loop. // } // // Process |hr| (the result returned by DoDragDrop()). @@ -63,9 +75,17 @@ class ThreadTaskRunnerHandle; // Please be SURE your task is reentrant (nestable) and all global variables // are stable and accessible before calling SetNestableTasksAllowed(true). // +// TODO(gab): MessageLoop doesn't need to be a MessageLoopCurrent once callers +// that store MessageLoop::current() in a MessageLoop* variable have been +// updated to use a MessageLoopCurrent variable. class BASE_EXPORT MessageLoop : public MessagePump::Delegate, - public RunLoop::Delegate { + public RunLoop::Delegate, + public MessageLoopCurrent { public: + // TODO(gab): Migrate usage of this class to MessageLoopCurrent and remove + // this forwarded declaration. + using DestructionObserver = MessageLoopCurrent::DestructionObserver; + // A MessageLoop has a particular type, which indicates the set of // asynchronous events it may process in addition to tasks and timers. // @@ -108,8 +128,8 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate, ~MessageLoop() override; - // Returns the MessageLoop object for the current thread, or null if none. - static MessageLoop* current(); + // TODO(gab): Mass migrate callers to MessageLoopCurrent::Get(). + static MessageLoopCurrent current(); using MessagePumpFactory = std::unique_ptr<MessagePump>(); // Uses the given base::MessagePumpForUIFactory to override the default @@ -121,35 +141,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate, // value. static std::unique_ptr<MessagePump> CreateMessagePumpForType(Type type); - // A DestructionObserver is notified when the current MessageLoop is being - // destroyed. These observers are notified prior to MessageLoop::current() - // being changed to return NULL. This gives interested parties the chance to - // do final cleanup that depends on the MessageLoop. - // - // NOTE: Any tasks posted to the MessageLoop during this notification will - // not be run. Instead, they will be deleted. - // - class BASE_EXPORT DestructionObserver { - public: - virtual void WillDestroyCurrentMessageLoop() = 0; - - protected: - virtual ~DestructionObserver(); - }; - - // Add a DestructionObserver, which will start receiving notifications - // immediately. - void AddDestructionObserver(DestructionObserver* destruction_observer); - - // Remove a DestructionObserver. It is safe to call this method while a - // DestructionObserver is receiving a notification callback. - void RemoveDestructionObserver(DestructionObserver* destruction_observer); - - // Deprecated: use RunLoop instead. - // Construct a Closure that will call QuitWhenIdle(). Useful to schedule an - // arbitrary MessageLoop to QuitWhenIdle. - static Closure QuitWhenIdleClosure(); - // Set the timer slack for this message loop. void SetTimerSlack(TimerSlack timer_slack) { pump_->SetTimerSlack(timer_slack); @@ -170,7 +161,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate, std::string GetThreadName() const; // Gets the TaskRunner associated with this message loop. - const scoped_refptr<SingleThreadTaskRunner>& task_runner() { + const scoped_refptr<SingleThreadTaskRunner>& task_runner() const { return task_runner_; } @@ -185,72 +176,9 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate, // Must be called on the thread to which the message loop is bound. void ClearTaskRunnerForTesting(); - // Enables or disables the recursive task processing. This happens in the case - // of recursive message loops. Some unwanted message loops may occur when - // using common controls or printer functions. By default, recursive task - // processing is disabled. - // - // Please use |ScopedNestableTaskAllower| instead of calling these methods - // directly. In general, nestable message loops are to be avoided. They are - // dangerous and difficult to get right, so please use with extreme caution. - // - // The specific case where tasks get queued is: - // - The thread is running a message loop. - // - It receives a task #1 and executes it. - // - The task #1 implicitly starts a message loop, like a MessageBox in the - // unit test. This can also be StartDoc or GetSaveFileName. - // - The thread receives a task #2 before or while in this second message - // loop. - // - With NestableTasksAllowed set to true, the task #2 will run right away. - // Otherwise, it will get executed right after task #1 completes at "thread - // message loop level". - // - // DEPRECATED: Use RunLoop::Type on the relevant RunLoop instead of these - // methods. - // TODO(gab): Migrate usage and delete these methods. - void SetNestableTasksAllowed(bool allowed); - bool NestableTasksAllowed() const; - - // Enables nestable tasks on |loop| while in scope. - // DEPRECATED: This should not be used when the nested loop is driven by - // RunLoop (use RunLoop::Type::kNestableTasksAllowed instead). It can however - // still be useful in a few scenarios where re-entrancy is caused by a native - // message loop. - // TODO(gab): Remove usage of this class alongside RunLoop and rename it to - // ScopedApplicationTasksAllowedInNativeNestedLoop(?). - class ScopedNestableTaskAllower { - public: - explicit ScopedNestableTaskAllower(MessageLoop* loop) - : loop_(loop), - old_state_(loop_->NestableTasksAllowed()) { - loop_->SetNestableTasksAllowed(true); - } - ~ScopedNestableTaskAllower() { - loop_->SetNestableTasksAllowed(old_state_); - } - - private: - MessageLoop* const loop_; - const bool old_state_; - }; - - // A TaskObserver is an object that receives task notifications from the - // MessageLoop. - // - // NOTE: A TaskObserver implementation should be extremely fast! - class BASE_EXPORT TaskObserver { - public: - TaskObserver(); - - // This method is called before processing a task. - virtual void WillProcessTask(const PendingTask& pending_task) = 0; - - // This method is called after processing a task. - virtual void DidProcessTask(const PendingTask& pending_task) = 0; - - protected: - virtual ~TaskObserver(); - }; + // TODO(https://crbug.com/825327): Remove users of TaskObservers through + // MessageLoop::current() and migrate the type back here. + using TaskObserver = MessageLoopCurrent::TaskObserver; // These functions can only be called on the same thread that |this| is // running on. @@ -287,6 +215,9 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate, private: friend class internal::IncomingTaskQueue; + friend class MessageLoopCurrent; + friend class MessageLoopCurrentForIO; + friend class MessageLoopCurrentForUI; friend class ScheduleWorkTest; friend class Thread; FRIEND_TEST_ALL_PREFIXES(MessageLoopTest, DeleteUnboundLoop); @@ -385,6 +316,10 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate, std::unique_ptr<internal::ScopedSetSequenceLocalStorageMapForCurrentThread> scoped_set_sequence_local_storage_map_for_current_thread_; + // Verifies that calls are made on the thread on which BindToCurrentThread() + // was invoked. + THREAD_CHECKER(bound_thread_checker_); + DISALLOW_COPY_AND_ASSIGN(MessageLoop); }; @@ -394,8 +329,11 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate, // MessageLoopForUI extends MessageLoop with methods that are particular to a // MessageLoop instantiated with TYPE_UI. // -// This class is typically used like so: -// MessageLoopForUI::current()->...call some method... +// By instantiating a MessageLoopForUI on the current thread, the owner enables +// native UI message pumping. +// +// MessageLoopCurrentForUI is exposed statically on its thread via +// MessageLoopCurrentForUI::Get() to provide additional functionality. // class BASE_EXPORT MessageLoopForUI : public MessageLoop { public: @@ -404,23 +342,9 @@ class BASE_EXPORT MessageLoopForUI : public MessageLoop { explicit MessageLoopForUI(std::unique_ptr<MessagePump> pump); - // Returns the MessageLoopForUI of the current thread. - static MessageLoopForUI* current() { - MessageLoop* loop = MessageLoop::current(); - DCHECK(loop); -#if defined(OS_ANDROID) - DCHECK(loop->IsType(MessageLoop::TYPE_UI) || - loop->IsType(MessageLoop::TYPE_JAVA)); -#else - DCHECK(loop->IsType(MessageLoop::TYPE_UI)); -#endif - return static_cast<MessageLoopForUI*>(loop); - } - - static bool IsCurrent() { - MessageLoop* loop = MessageLoop::current(); - return loop && loop->IsType(MessageLoop::TYPE_UI); - } + // TODO(gab): Mass migrate callers to MessageLoopCurrentForUI::Get()/IsSet(). + static MessageLoopCurrentForUI current(); + static bool IsCurrent(); #if defined(OS_IOS) // On iOS, the main message loop cannot be Run(). Instead call Attach(), @@ -440,17 +364,9 @@ class BASE_EXPORT MessageLoopForUI : public MessageLoop { void Abort(); #endif -#if (defined(USE_OZONE) && !defined(OS_FUCHSIA)) || \ - (defined(USE_X11) && !defined(USE_GLIB)) - // Please see MessagePumpLibevent for definition. - static_assert(std::is_same<MessagePumpForUI, MessagePumpLibevent>::value, - "MessageLoopForUI::WatchFileDescriptor is not supported when " - "MessagePumpForUI is not a MessagePumpLibevent."); - bool WatchFileDescriptor(int fd, - bool persistent, - MessagePumpForUI::Mode mode, - MessagePumpForUI::FdWatchController* controller, - MessagePumpForUI::FdWatcher* delegate); +#if defined(OS_WIN) + // See method of the same name in the Windows MessagePumpForUI implementation. + void EnableWmQuit(); #endif }; @@ -466,53 +382,19 @@ static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForUI), // MessageLoopForIO extends MessageLoop with methods that are particular to a // MessageLoop instantiated with TYPE_IO. // -// This class is typically used like so: -// MessageLoopForIO::current()->...call some method... +// By instantiating a MessageLoopForIO on the current thread, the owner enables +// native async IO message pumping. +// +// MessageLoopCurrentForIO is exposed statically on its thread via +// MessageLoopCurrentForIO::Get() to provide additional functionality. // class BASE_EXPORT MessageLoopForIO : public MessageLoop { public: - MessageLoopForIO() : MessageLoop(TYPE_IO) { - } + MessageLoopForIO() : MessageLoop(TYPE_IO) {} - // Returns the MessageLoopForIO of the current thread. - static MessageLoopForIO* current() { - MessageLoop* loop = MessageLoop::current(); - DCHECK(loop); - DCHECK_EQ(MessageLoop::TYPE_IO, loop->type()); - return static_cast<MessageLoopForIO*>(loop); - } - - static bool IsCurrent() { - MessageLoop* loop = MessageLoop::current(); - return loop && loop->type() == MessageLoop::TYPE_IO; - } - -#if !defined(OS_NACL_SFI) - -#if defined(OS_WIN) - // Please see MessagePumpWin for definitions of these methods. - void RegisterIOHandler(HANDLE file, MessagePumpForIO::IOHandler* handler); - bool RegisterJobObject(HANDLE job, MessagePumpForIO::IOHandler* handler); - bool WaitForIOCompletion(DWORD timeout, MessagePumpForIO::IOHandler* filter); -#elif defined(OS_POSIX) - // Please see WatchableIOMessagePumpPosix for definition. - // Prefer base::FileDescriptorWatcher for non-critical IO. - bool WatchFileDescriptor(int fd, - bool persistent, - MessagePumpForIO::Mode mode, - MessagePumpForIO::FdWatchController* controller, - MessagePumpForIO::FdWatcher* delegate); -#endif // defined(OS_IOS) || defined(OS_POSIX) -#endif // !defined(OS_NACL_SFI) - -#if defined(OS_FUCHSIA) - // Additional watch API for native platform resources. - bool WatchZxHandle(zx_handle_t handle, - bool persistent, - zx_signals_t signals, - MessagePumpForIO::ZxHandleWatchController* controller, - MessagePumpForIO::ZxHandleWatcher* delegate); -#endif + // TODO(gab): Mass migrate callers to MessageLoopCurrentForIO::Get()/IsSet(). + static MessageLoopCurrentForIO current(); + static bool IsCurrent(); }; // Do not add any member variables to MessageLoopForIO! This is important b/c diff --git a/chromium/base/message_loop/message_loop_current.cc b/chromium/base/message_loop/message_loop_current.cc new file mode 100644 index 00000000000..0beef5ae0fc --- /dev/null +++ b/chromium/base/message_loop/message_loop_current.cc @@ -0,0 +1,252 @@ +// 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 diff --git a/chromium/base/message_loop/message_loop_current.h b/chromium/base/message_loop/message_loop_current.h new file mode 100644 index 00000000000..c5016dcf20a --- /dev/null +++ b/chromium/base/message_loop/message_loop_current.h @@ -0,0 +1,303 @@ +// 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. + +#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_CURRENT_H_ +#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_CURRENT_H_ + +#include "base/base_export.h" +#include "base/logging.h" +#include "base/memory/scoped_refptr.h" +#include "base/message_loop/message_pump_for_io.h" +#include "base/message_loop/message_pump_for_ui.h" +#include "base/pending_task.h" +#include "base/single_thread_task_runner.h" +#include "build/build_config.h" + +namespace base { + +class MessageLoop; + +// MessageLoopCurrent is a proxy to the public interface of the MessageLoop +// bound to the thread it's obtained on. +// +// MessageLoopCurrent(ForUI|ForIO) is available statically through +// MessageLoopCurrent(ForUI|ForIO)::Get() on threads that have a matching +// MessageLoop instance. APIs intended for all consumers on the thread should be +// on MessageLoopCurrent(ForUI|ForIO), while APIs intended for the owner of the +// instance should be on MessageLoop(ForUI|ForIO). +// +// Why: Historically MessageLoop::current() gave access to the full MessageLoop +// API, preventing both addition of powerful owner-only APIs as well as making +// it harder to remove callers of deprecated APIs (that need to stick around for +// a few owner-only use cases and re-accrue callers after cleanup per remaining +// publicly available). +// +// As such, many methods below are flagged as deprecated and should be removed +// (or moved back to MessageLoop) once all static callers have been migrated. +class BASE_EXPORT MessageLoopCurrent { + public: + // MessageLoopCurrent is effectively just a disguised pointer and is fine to + // copy around. + MessageLoopCurrent(const MessageLoopCurrent& other) = default; + MessageLoopCurrent& operator=(const MessageLoopCurrent& other) = default; + + // Returns a proxy object to interact with the MessageLoop running the + // current thread. It must only be used on the thread it was obtained. + static MessageLoopCurrent Get(); + + // Returns true if the current thread is running a MessageLoop. Prefer this to + // verifying the boolean value of Get() (so that Get() can ultimately DCHECK + // it's only invoked when IsSet()). + static bool IsSet(); + + // Allow MessageLoopCurrent to be used like a pointer to support the many + // callsites that used MessageLoop::current() that way when it was a + // MessageLoop*. + MessageLoopCurrent* operator->() { return this; } + explicit operator bool() const { return !!current_; } + + // TODO(gab): Migrate the types of variables that store MessageLoop::current() + // and remove this implicit cast back to MessageLoop*. + operator MessageLoop*() const { return current_; } + + // A DestructionObserver is notified when the current MessageLoop is being + // destroyed. These observers are notified prior to MessageLoop::current() + // being changed to return NULL. This gives interested parties the chance to + // do final cleanup that depends on the MessageLoop. + // + // NOTE: Any tasks posted to the MessageLoop during this notification will + // not be run. Instead, they will be deleted. + // + // Deprecation note: Prefer SequenceLocalStorageSlot<std::unique_ptr<Foo>> to + // DestructionObserver to bind an object's lifetime to the current + // thread/sequence. + class BASE_EXPORT DestructionObserver { + public: + virtual void WillDestroyCurrentMessageLoop() = 0; + + protected: + virtual ~DestructionObserver() = default; + }; + + // Add a DestructionObserver, which will start receiving notifications + // immediately. + void AddDestructionObserver(DestructionObserver* destruction_observer); + + // Remove a DestructionObserver. It is safe to call this method while a + // DestructionObserver is receiving a notification callback. + void RemoveDestructionObserver(DestructionObserver* destruction_observer); + + // Forwards to MessageLoop::task_runner(). + // DEPRECATED(https://crbug.com/616447): Use ThreadTaskRunnerHandle::Get() + // instead of MessageLoopCurrent::Get()->task_runner(). + const scoped_refptr<SingleThreadTaskRunner>& task_runner() const; + + // Forwards to MessageLoop::SetTaskRunner(). + // DEPRECATED(https://crbug.com/825327): only owners of the MessageLoop + // instance should replace its TaskRunner. + void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner); + + // A TaskObserver is an object that receives task notifications from the + // MessageLoop. + // + // NOTE: A TaskObserver implementation should be extremely fast! + class BASE_EXPORT TaskObserver { + public: + // This method is called before processing a task. + virtual void WillProcessTask(const PendingTask& pending_task) = 0; + + // This method is called after processing a task. + virtual void DidProcessTask(const PendingTask& pending_task) = 0; + + protected: + virtual ~TaskObserver() = default; + }; + + // Forwards to MessageLoop::(Add|Remove)TaskObserver. + // DEPRECATED(https://crbug.com/825327): only owners of the MessageLoop + // instance should add task observers on it. + void AddTaskObserver(TaskObserver* task_observer); + void RemoveTaskObserver(TaskObserver* task_observer); + + // Enables or disables the recursive task processing. This happens in the case + // of recursive message loops. Some unwanted message loops may occur when + // using common controls or printer functions. By default, recursive task + // processing is disabled. + // + // Please use |ScopedNestableTaskAllower| instead of calling these methods + // directly. In general, nestable message loops are to be avoided. They are + // dangerous and difficult to get right, so please use with extreme caution. + // + // The specific case where tasks get queued is: + // - The thread is running a message loop. + // - It receives a task #1 and executes it. + // - The task #1 implicitly starts a message loop, like a MessageBox in the + // unit test. This can also be StartDoc or GetSaveFileName. + // - The thread receives a task #2 before or while in this second message + // loop. + // - With NestableTasksAllowed set to true, the task #2 will run right away. + // Otherwise, it will get executed right after task #1 completes at "thread + // message loop level". + // + // DEPRECATED(https://crbug.com/750779): Use RunLoop::Type on the relevant + // RunLoop instead of these methods. + // TODO(gab): Migrate usage and delete these methods. + void SetNestableTasksAllowed(bool allowed); + bool NestableTasksAllowed() const; + + // Enables nestable tasks on the current MessageLoop while in scope. + // DEPRECATED(https://crbug.com/750779): This should not be used when the + // nested loop is driven by RunLoop (use RunLoop::Type::kNestableTasksAllowed + // instead). It can however still be useful in a few scenarios where re- + // entrancy is caused by a native message loop. + // TODO(gab): Remove usage of this class alongside RunLoop and rename it to + // ScopedApplicationTasksAllowedInNativeNestedLoop(?) for remaining use cases. + class BASE_EXPORT ScopedNestableTaskAllower { + public: + ScopedNestableTaskAllower(); + ~ScopedNestableTaskAllower(); + + private: + MessageLoop* const loop_; + const bool old_state_; + }; + + // Returns true if the message loop is idle (ignoring delayed tasks). This is + // the same condition which triggers DoWork() to return false: i.e. + // out of tasks which can be processed at the current run-level -- there might + // be deferred non-nestable tasks remaining if currently in a nested run + // level. + bool IsIdleForTesting(); + + // Binds |current| to the current thread. It will from then on be the + // MessageLoop driven by MessageLoopCurrent on this thread. This is only meant + // to be invoked by the MessageLoop itself. + static void BindToCurrentThreadInternal(MessageLoop* current); + + // Unbinds |current| from the current thread. Must be invoked on the same + // thread that invoked |BindToCurrentThreadInternal(current)|. This is only + // meant to be invoked by the MessageLoop itself. + static void UnbindFromCurrentThreadInternal(MessageLoop* current); + + // Returns true if |message_loop| is bound to MessageLoopCurrent on the + // current thread. This is only meant to be invoked by the MessageLoop itself. + static bool IsBoundToCurrentThreadInternal(MessageLoop* message_loop); + + protected: + explicit MessageLoopCurrent(MessageLoop* current) : current_(current) {} + + MessageLoop* const current_; +}; + +#if !defined(OS_NACL) + +// ForUI extension of MessageLoopCurrent. +class BASE_EXPORT MessageLoopCurrentForUI : public MessageLoopCurrent { + public: + // Returns an interface for the MessageLoopForUI of the current thread. + // Asserts that IsSet(). + static MessageLoopCurrentForUI Get(); + + // Returns true if the current thread is running a MessageLoopForUI. + static bool IsSet(); + + MessageLoopCurrentForUI* operator->() { return this; } + +#if defined(USE_OZONE) && !defined(OS_FUCHSIA) && !defined(OS_WIN) + // Please see MessagePumpLibevent for definition. + static_assert(std::is_same<MessagePumpForUI, MessagePumpLibevent>::value, + "MessageLoopCurrentForUI::WatchFileDescriptor is not supported " + "when MessagePumpForUI is not a MessagePumpLibevent."); + bool WatchFileDescriptor(int fd, + bool persistent, + MessagePumpForUI::Mode mode, + MessagePumpForUI::FdWatchController* controller, + MessagePumpForUI::FdWatcher* delegate); +#endif + +#if defined(OS_IOS) + // Forwards to MessageLoopForUI::Attach(). + // TODO(https://crbug.com/825327): Plumb the actual MessageLoopForUI* to + // callers and remove ability to access this method from + // MessageLoopCurrentForUI. + void Attach(); +#endif + +#if defined(OS_ANDROID) + // Forwards to MessageLoopForUI::Start(). + // TODO(https://crbug.com/825327): Plumb the actual MessageLoopForUI* to + // callers and remove ability to access this method from + // MessageLoopCurrentForUI. + void Start(); + + // Forwards to MessageLoopForUI::Abort(). + // TODO(https://crbug.com/825327): Plumb the actual MessageLoopForUI* to + // callers and remove ability to access this method from + // MessageLoopCurrentForUI. + void Abort(); +#endif + + private: + MessageLoopCurrentForUI(MessageLoop* current, MessagePumpForUI* pump) + : MessageLoopCurrent(current), pump_(pump) { + DCHECK(pump_); + } + + MessagePumpForUI* const pump_; +}; + +#endif // !defined(OS_NACL) + +// ForIO extension of MessageLoopCurrent. +class BASE_EXPORT MessageLoopCurrentForIO : public MessageLoopCurrent { + public: + // Returns an interface for the MessageLoopForIO of the current thread. + // Asserts that IsSet(). + static MessageLoopCurrentForIO Get(); + + // Returns true if the current thread is running a MessageLoopForIO. + static bool IsSet(); + + MessageLoopCurrentForIO* operator->() { return this; } + +#if !defined(OS_NACL_SFI) + +#if defined(OS_WIN) + // Please see MessagePumpWin for definitions of these methods. + void RegisterIOHandler(HANDLE file, MessagePumpForIO::IOHandler* handler); + bool RegisterJobObject(HANDLE job, MessagePumpForIO::IOHandler* handler); + bool WaitForIOCompletion(DWORD timeout, MessagePumpForIO::IOHandler* filter); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + // Please see WatchableIOMessagePumpPosix for definition. + // Prefer base::FileDescriptorWatcher for non-critical IO. + bool WatchFileDescriptor(int fd, + bool persistent, + MessagePumpForIO::Mode mode, + MessagePumpForIO::FdWatchController* controller, + MessagePumpForIO::FdWatcher* delegate); +#endif // defined(OS_WIN) + +#if defined(OS_FUCHSIA) + // Additional watch API for native platform resources. + bool WatchZxHandle(zx_handle_t handle, + bool persistent, + zx_signals_t signals, + MessagePumpForIO::ZxHandleWatchController* controller, + MessagePumpForIO::ZxHandleWatcher* delegate); +#endif // defined(OS_FUCHSIA) + +#endif // !defined(OS_NACL_SFI) + + private: + MessageLoopCurrentForIO(MessageLoop* current, MessagePumpForIO* pump) + : MessageLoopCurrent(current), pump_(pump) { + DCHECK(pump_); + } + + MessagePumpForIO* const pump_; +}; + +} // namespace base + +#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_CURRENT_H_ diff --git a/chromium/base/message_loop/message_loop_io_posix_unittest.cc b/chromium/base/message_loop/message_loop_io_posix_unittest.cc index 2c6d394bc86..4dd5f280280 100644 --- a/chromium/base/message_loop/message_loop_io_posix_unittest.cc +++ b/chromium/base/message_loop/message_loop_io_posix_unittest.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_pump_for_io.h" #include "base/posix/eintr_wrapper.h" #include "base/run_loop.h" @@ -134,9 +135,9 @@ TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherOutlivesMessageLoop) { { MessageLoopForIO message_loop; - message_loop.WatchFileDescriptor(write_fd_.get(), true, - MessagePumpForIO::WATCH_WRITE, &watcher, - &handler); + MessageLoopCurrentForIO::Get()->WatchFileDescriptor( + write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, &watcher, + &handler); // Don't run the message loop, just destroy it. } @@ -153,9 +154,9 @@ TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherDoubleStop) { MessagePumpForIO::FdWatchController watcher(FROM_HERE); TestHandler handler; - message_loop.WatchFileDescriptor(write_fd_.get(), true, - MessagePumpForIO::WATCH_WRITE, &watcher, - &handler); + MessageLoopCurrentForIO::Get()->WatchFileDescriptor( + write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, &watcher, + &handler); ASSERT_TRUE(watcher.StopWatchingFileDescriptor()); ASSERT_TRUE(watcher.StopWatchingFileDescriptor()); } @@ -170,9 +171,9 @@ TEST_F(MessageLoopForIoPosixTest, FileDescriptorWatcherDeleteInCallback) { handler.watcher_to_delete_ = std::make_unique<MessagePumpForIO::FdWatchController>(FROM_HERE); - message_loop.WatchFileDescriptor(write_fd_.get(), true, - MessagePumpForIO::WATCH_WRITE, - handler.watcher_to_delete_.get(), &handler); + MessageLoopCurrentForIO::Get()->WatchFileDescriptor( + write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE, + handler.watcher_to_delete_.get(), &handler); RunLoop().Run(); } @@ -183,7 +184,7 @@ TEST_F(MessageLoopForIoPosixTest, WatchReadable) { TestHandler handler; // Watch the pipe for readability. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, &watcher, &handler)); @@ -209,7 +210,7 @@ TEST_F(MessageLoopForIoPosixTest, WatchWritable) { TestHandler handler; // Watch the pipe for writability. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( write_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_WRITE, &watcher, &handler)); @@ -232,7 +233,7 @@ TEST_F(MessageLoopForIoPosixTest, RunUntilIdle) { TestHandler handler; // Watch the pipe for readability. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, &watcher, &handler)); @@ -261,7 +262,7 @@ TEST_F(MessageLoopForIoPosixTest, StopFromHandler) { OnceClosure()); // Create persistent watcher. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, &watcher, &handler)); @@ -282,7 +283,7 @@ TEST_F(MessageLoopForIoPosixTest, NonPersistentWatcher) { CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure()); // Create a non-persistent watcher. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, &watcher, &handler)); @@ -303,7 +304,7 @@ TEST_F(MessageLoopForIoPosixTest, PersistentWatcher) { CallClosureHandler handler(run_loop1.QuitClosure(), OnceClosure()); // Create persistent watcher. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, &watcher, &handler)); @@ -325,7 +326,7 @@ void StopWatchingAndWatchAgain(MessagePumpForIO::FdWatchController* controller, RunLoop* run_loop) { controller->StopWatchingFileDescriptor(); - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( fd, /*persistent=*/true, MessagePumpForIO::WATCH_READ, controller, new_handler)); @@ -345,7 +346,7 @@ TEST_F(MessageLoopForIoPosixTest, StopAndRestartFromHandler) { OnceClosure()); // Create persistent watcher. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ, &watcher, &handler1)); @@ -372,7 +373,7 @@ TEST_F(MessageLoopForIoPosixTest, IoEventThenTimer) { CallClosureHandler handler(watcher_run_loop.QuitClosure(), OnceClosure()); // Create a non-persistent watcher. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, &watcher, &handler)); @@ -403,7 +404,7 @@ TEST_F(MessageLoopForIoPosixTest, TimerThenIoEvent) { CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure()); // Create a non-persistent watcher. - ASSERT_TRUE(MessageLoopForIO::current()->WatchFileDescriptor( + ASSERT_TRUE(MessageLoopCurrentForIO::Get()->WatchFileDescriptor( read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ, &watcher, &handler)); diff --git a/chromium/base/message_loop/message_loop_task_runner_unittest.cc b/chromium/base/message_loop/message_loop_task_runner_unittest.cc index f2e71c40e4e..c7e9aa05962 100644 --- a/chromium/base/message_loop/message_loop_task_runner_unittest.cc +++ b/chromium/base/message_loop/message_loop_task_runner_unittest.cc @@ -262,8 +262,8 @@ class MessageLoopTaskRunnerThreadingTest : public testing::Test { } void Quit() const { - loop_.task_runner()->PostTask(FROM_HERE, - MessageLoop::QuitWhenIdleClosure()); + loop_.task_runner()->PostTask( + FROM_HERE, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); } void AssertOnIOThread() const { diff --git a/chromium/base/message_loop/message_loop_unittest.cc b/chromium/base/message_loop/message_loop_unittest.cc index e551e420d07..1c0911319dd 100644 --- a/chromium/base/message_loop/message_loop_unittest.cc +++ b/chromium/base/message_loop/message_loop_unittest.cc @@ -15,6 +15,7 @@ #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_pump_for_io.h" #include "base/pending_task.h" #include "base/posix/eintr_wrapper.h" @@ -235,7 +236,7 @@ void RecursiveFunc(TaskList* order, int cookie, int depth, order->RecordStart(RECURSIVE, cookie); if (depth > 0) { if (is_reentrant) - MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, BindOnce(&RecursiveFunc, order, cookie, depth - 1, is_reentrant)); @@ -390,7 +391,7 @@ TEST_P(MessageLoopTest, RunTasksWhileShuttingDownJavaThread) { #if defined(OS_WIN) void SubPumpFunc() { - MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); @@ -448,7 +449,7 @@ const wchar_t kMessageBoxTitle[] = L"MessageLoop Unit Test"; void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) { order->RecordStart(MESSAGEBOX, cookie); if (is_reentrant) - MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK); order->RecordEnd(MESSAGEBOX, cookie); } @@ -639,7 +640,7 @@ TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait) } void TestIOHandler::Init() { - MessageLoopForIO::current()->RegisterIOHandler(file_.Get(), this); + MessageLoopCurrentForIO::Get()->RegisterIOHandler(file_.Get(), this); DWORD read; EXPECT_FALSE(ReadFile(file_.Get(), buffer_, size(), &read, context())); @@ -656,8 +657,8 @@ void TestIOHandler::OnIOCompleted(MessagePumpForIO::IOContext* context, } void TestIOHandler::WaitForIO() { - EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this)); - EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this)); + EXPECT_TRUE(MessageLoopCurrentForIO::Get()->WaitForIOCompletion(300, this)); + EXPECT_TRUE(MessageLoopCurrentForIO::Get()->WaitForIOCompletion(400, this)); } void RunTest_IOHandler() { @@ -1096,7 +1097,7 @@ void NestingFunc(int* depth) { ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, BindOnce(&NestingFunc, depth)); - MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); RunLoop().Run(); } base::RunLoop::QuitCurrentWhenIdleDeprecated(); @@ -1117,7 +1118,7 @@ TEST_P(MessageLoopTypedTest, Nesting) { TEST_P(MessageLoopTypedTest, RecursiveDenial1) { MessageLoop loop(GetMessageLoopType()); - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); + EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); TaskList order; ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, BindOnce(&RecursiveFunc, &order, 1, 2, false)); @@ -1166,7 +1167,7 @@ void OrderedFunc(TaskList* order, int cookie) { TEST_P(MessageLoopTypedTest, RecursiveDenial3) { MessageLoop loop(GetMessageLoopType()); - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); + EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); TaskList order; ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, BindOnce(&RecursiveSlowFunc, &order, 1, 2, false)); @@ -1315,7 +1316,7 @@ namespace { void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) { order->RecordStart(RUNS, cookie); { - MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); + MessageLoopCurrent::ScopedNestableTaskAllower allow; run_loop->Run(); } order->RecordEnd(RUNS, cookie); @@ -1659,7 +1660,7 @@ TEST_P(MessageLoopTypedTest, RecursivePosts) { TEST_P(MessageLoopTypedTest, NestableTasksAllowedAtTopLevel) { MessageLoop loop(GetMessageLoopType()); - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); + EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); } // Nestable tasks shouldn't be allowed to run reentrantly by default (regression @@ -1671,7 +1672,7 @@ TEST_P(MessageLoopTypedTest, NestableTasksDisallowedByDefault) { FROM_HERE, BindOnce( [](RunLoop* run_loop) { - EXPECT_FALSE(MessageLoop::current()->NestableTasksAllowed()); + EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); run_loop->Quit(); }, Unretained(&run_loop))); @@ -1699,7 +1700,7 @@ TEST_P(MessageLoopTypedTest, NestableTasksProcessedWhenRunLoopAllows) { // nestable tasks are by default disallowed from this // layer. EXPECT_FALSE( - MessageLoop::current()->NestableTasksAllowed()); + MessageLoopCurrent::Get()->NestableTasksAllowed()); nested_run_loop->Quit(); }, Unretained(&nested_run_loop))); @@ -1719,11 +1720,11 @@ TEST_P(MessageLoopTypedTest, NestableTasksAllowedExplicitlyInScope) { BindOnce( [](RunLoop* run_loop) { { - MessageLoop::ScopedNestableTaskAllower allow_nestable_tasks( - MessageLoop::current()); - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); + MessageLoopCurrent::ScopedNestableTaskAllower + allow_nestable_tasks; + EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); } - EXPECT_FALSE(MessageLoop::current()->NestableTasksAllowed()); + EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); run_loop->Quit(); }, Unretained(&run_loop))); @@ -1737,11 +1738,11 @@ TEST_P(MessageLoopTypedTest, NestableTasksAllowedManually) { FROM_HERE, BindOnce( [](RunLoop* run_loop) { - EXPECT_FALSE(MessageLoop::current()->NestableTasksAllowed()); - MessageLoop::current()->SetNestableTasksAllowed(true); - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); - MessageLoop::current()->SetNestableTasksAllowed(false); - EXPECT_FALSE(MessageLoop::current()->NestableTasksAllowed()); + EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); + EXPECT_TRUE(MessageLoopCurrent::Get()->NestableTasksAllowed()); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(false); + EXPECT_FALSE(MessageLoopCurrent::Get()->NestableTasksAllowed()); run_loop->Quit(); }, Unretained(&run_loop))); @@ -1777,13 +1778,14 @@ INSTANTIATE_TEST_CASE_P( // Run()ning explicitly, via QuitClosure() etc (see https://crbug.com/720078) TEST_P(MessageLoopTest, WmQuitIsIgnored) { MessageLoop loop(MessageLoop::TYPE_UI); - RunLoop run_loop; + // Post a WM_QUIT message to the current thread. ::PostQuitMessage(0); // Post a task to the current thread, with a small delay to make it less // likely that we process the posted task before looking for WM_* messages. bool task_was_run = false; + RunLoop run_loop; loop.task_runner()->PostDelayedTask( FROM_HERE, BindOnce( @@ -1799,6 +1801,29 @@ TEST_P(MessageLoopTest, WmQuitIsIgnored) { EXPECT_TRUE(task_was_run); } +TEST_P(MessageLoopTest, WmQuitIsNotIgnoredWithEnableWmQuit) { + MessageLoop loop(MessageLoop::TYPE_UI); + static_cast<MessageLoopForUI*>(&loop)->EnableWmQuit(); + + // Post a WM_QUIT message to the current thread. + ::PostQuitMessage(0); + + // Post a task to the current thread, with a small delay to make it less + // likely that we process the posted task before looking for WM_* messages. + RunLoop run_loop; + loop.task_runner()->PostDelayedTask(FROM_HERE, + BindOnce( + [](OnceClosure closure) { + ADD_FAILURE(); + std::move(closure).Run(); + }, + run_loop.QuitClosure()), + TestTimeouts::tiny_timeout()); + + // Run the loop. It should not result in ADD_FAILURE() getting called. + run_loop.Run(); +} + TEST_P(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) { RunTest_PostDelayedTask_SharedTimer_SubPump(); } @@ -1910,7 +1935,7 @@ class DestructionObserverProbe : bool* destruction_observer_called_; }; -class MLDestructionObserver : public MessageLoop::DestructionObserver { +class MLDestructionObserver : public MessageLoopCurrent::DestructionObserver { public: MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called) : task_destroyed_(task_destroyed), @@ -2030,7 +2055,7 @@ LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message, case 2: // Since we're about to enter a modal loop, tell the message loop that we // intend to nest tasks. - MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); bool did_run = false; ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&EndTest, &did_run, hwnd)); diff --git a/chromium/base/message_loop/message_pump_android.cc b/chromium/base/message_loop/message_pump_android.cc index 1a11e55325b..8c5bb5727ab 100644 --- a/chromium/base/message_loop/message_pump_android.cc +++ b/chromium/base/message_loop/message_pump_android.cc @@ -10,7 +10,6 @@ #include "base/android/scoped_java_ref.h" #include "base/lazy_instance.h" #include "base/logging.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "jni/SystemMessageHandler_jni.h" diff --git a/chromium/base/message_loop/message_pump_for_ui.h b/chromium/base/message_loop/message_pump_for_ui.h index 2d3e17513b4..6ee02b094ca 100644 --- a/chromium/base/message_loop/message_pump_for_ui.h +++ b/chromium/base/message_loop/message_pump_for_ui.h @@ -15,7 +15,7 @@ #elif defined(OS_ANDROID) #include "base/message_loop/message_pump_android.h" #elif defined(OS_MACOSX) -// No MessagePumpForUI, see below. +#include "base/message_loop/message_pump.h" #elif defined(OS_NACL) || defined(OS_AIX) // No MessagePumpForUI, see below. #elif defined(USE_GLIB) @@ -35,8 +35,10 @@ using MessagePumpForUI = MessagePumpForUI; // Android defines it as-is. using MessagePumpForUI = MessagePumpForUI; #elif defined(OS_MACOSX) -// MessagePumpForUI doesn't exists on Mac, MessagePumpMac::Create defines which -// Mac specific pump is used. +// MessagePumpForUI isn't bound to a specific impl on Mac. While each impl can +// be represented by a plain MessagePump: MessagePumpMac::Create() must be used +// to instantiate the right impl. +using MessagePumpForUI = MessagePump; #elif defined(OS_NACL) || defined(OS_AIX) // Currently NaCl and AIX don't have a MessagePumpForUI. // TODO(abarth): Figure out if we need this. diff --git a/chromium/base/message_loop/message_pump_fuchsia.cc b/chromium/base/message_loop/message_pump_fuchsia.cc index 6504d177333..b9af6433dd7 100644 --- a/chromium/base/message_loop/message_pump_fuchsia.cc +++ b/chromium/base/message_loop/message_pump_fuchsia.cc @@ -4,23 +4,40 @@ #include "base/message_loop/message_pump_fuchsia.h" +#include <fdio/io.h> +#include <fdio/private.h> #include <zircon/status.h> #include <zircon/syscalls.h> #include "base/auto_reset.h" +#include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" namespace base { MessagePumpFuchsia::ZxHandleWatchController::ZxHandleWatchController( const Location& from_here) - : created_from_location_(from_here) {} + : async_wait_t({}), created_from_location_(from_here) {} MessagePumpFuchsia::ZxHandleWatchController::~ZxHandleWatchController() { if (!StopWatchingZxHandle()) NOTREACHED(); } +bool MessagePumpFuchsia::ZxHandleWatchController::WaitBegin() { + DCHECK(!handler); + async_wait_t::handler = &HandleSignal; + + zx_status_t status = async_begin_wait(&weak_pump_->async_dispatcher_, this); + if (status != ZX_OK) { + ZX_DLOG(ERROR, status) << "async_begin_wait() failed"; + async_wait_t::handler = nullptr; + return false; + } + + return true; +} + bool MessagePumpFuchsia::ZxHandleWatchController::StopWatchingZxHandle() { if (was_stopped_) { DCHECK(!*was_stopped_); @@ -33,23 +50,64 @@ bool MessagePumpFuchsia::ZxHandleWatchController::StopWatchingZxHandle() { was_stopped_ = nullptr; } - if (!has_begun_) - return true; - - has_begun_ = false; - // If the pump is gone then there is nothing to cancel. if (!weak_pump_) return true; - int result = zx_port_cancel(weak_pump_->port_.get(), handle_, wait_key()); - DLOG_IF(ERROR, result != ZX_OK) - << "zx_port_cancel(handle=" << handle_ - << ") failed: " << zx_status_get_string(result); + // |handler| is set when waiting for a signal. + if (!handler) + return true; + async_wait_t::handler = nullptr; + + zx_status_t result = async_cancel_wait(&weak_pump_->async_dispatcher_, this); + ZX_DLOG_IF(ERROR, result != ZX_OK, result) << "async_cancel_wait failed"; return result == ZX_OK; } +// static +void MessagePumpFuchsia::ZxHandleWatchController::HandleSignal( + async_t* async, + async_wait_t* wait, + zx_status_t status, + const zx_packet_signal_t* signal) { + if (status != ZX_OK) { + ZX_LOG(WARNING, status) << "async wait failed"; + return; + } + + ZxHandleWatchController* controller = + static_cast<ZxHandleWatchController*>(wait); + DCHECK_EQ(controller->handler, &HandleSignal); + controller->handler = nullptr; + + // |signal| can include other spurious things, in particular, that an fd + // is writable, when we only asked to know when it was readable. In that + // case, we don't want to call both the CanWrite and CanRead callback, + // when the caller asked for only, for example, readable callbacks. So, + // mask with the events that we actually wanted to know about. + zx_signals_t signals = signal->trigger & signal->observed; + DCHECK_NE(0u, signals); + + // In the case of a persistent Watch, the Watch may be stopped and + // potentially deleted by the caller within the callback, in which case + // |controller| should not be accessed again, and we mustn't continue the + // watch. We check for this with a bool on the stack, which the Watch + // receives a pointer to. + bool was_stopped = false; + controller->was_stopped_ = &was_stopped; + + controller->watcher_->OnZxHandleSignalled(wait->object, signals); + + if (was_stopped) + return; + + controller->was_stopped_ = nullptr; + + if (controller->persistent_) + controller->WaitBegin(); +} + void MessagePumpFuchsia::FdWatchController::OnZxHandleSignalled( zx_handle_t handle, zx_signals_t signals) { @@ -79,6 +137,19 @@ MessagePumpFuchsia::FdWatchController::~FdWatchController() { NOTREACHED(); } +bool MessagePumpFuchsia::FdWatchController::WaitBegin() { + // Refresh the |handle_| and |desired_signals_| from the mxio for the fd. + // Some types of fdio map read/write events to different signals depending on + // their current state, so we must do this every time we begin to wait. + __fdio_wait_begin(io_, desired_events_, &object, &trigger); + if (async_wait_t::object == ZX_HANDLE_INVALID) { + DLOG(ERROR) << "fdio_wait_begin failed"; + return false; + } + + return MessagePumpFuchsia::ZxHandleWatchController::WaitBegin(); +} + bool MessagePumpFuchsia::FdWatchController::StopWatchingFileDescriptor() { bool success = StopWatchingZxHandle(); if (io_) { @@ -88,11 +159,9 @@ bool MessagePumpFuchsia::FdWatchController::StopWatchingFileDescriptor() { return success; } -MessagePumpFuchsia::MessagePumpFuchsia() : weak_factory_(this) { - CHECK_EQ(ZX_OK, zx_port_create(0, port_.receive())); -} +MessagePumpFuchsia::MessagePumpFuchsia() : weak_factory_(this) {} -MessagePumpFuchsia::~MessagePumpFuchsia() {} +MessagePumpFuchsia::~MessagePumpFuchsia() = default; bool MessagePumpFuchsia::WatchFileDescriptor(int fd, bool persistent, @@ -138,19 +207,6 @@ bool MessagePumpFuchsia::WatchFileDescriptor(int fd, controller); } -bool MessagePumpFuchsia::FdWatchController::WaitBegin() { - // Refresh the |handle_| and |desired_signals_| from the mxio for the fd. - // Some types of mxio map read/write events to different signals depending on - // their current state, so we must do this every time we begin to wait. - __fdio_wait_begin(io_, desired_events_, &handle_, &desired_signals_); - if (handle_ == ZX_HANDLE_INVALID) { - DLOG(ERROR) << "fdio_wait_begin failed"; - return false; - } - - return MessagePumpFuchsia::ZxHandleWatchController::WaitBegin(); -} - bool MessagePumpFuchsia::WatchZxHandle(zx_handle_t handle, bool persistent, zx_signals_t signals, @@ -160,15 +216,15 @@ bool MessagePumpFuchsia::WatchZxHandle(zx_handle_t handle, DCHECK(controller); DCHECK(delegate); DCHECK(handle == ZX_HANDLE_INVALID || - controller->handle_ == ZX_HANDLE_INVALID || - handle == controller->handle_); + controller->async_wait_t::object == ZX_HANDLE_INVALID || + handle == controller->async_wait_t::object); if (!controller->StopWatchingZxHandle()) NOTREACHED(); - controller->handle_ = handle; + controller->async_wait_t::object = handle; controller->persistent_ = persistent; - controller->desired_signals_ = signals; + controller->async_wait_t::trigger = signals; controller->watcher_ = delegate; controller->weak_pump_ = weak_factory_.GetWeakPtr(); @@ -176,85 +232,22 @@ bool MessagePumpFuchsia::WatchZxHandle(zx_handle_t handle, return controller->WaitBegin(); } -bool MessagePumpFuchsia::ZxHandleWatchController::WaitBegin() { - DCHECK(!has_begun_); - - zx_status_t status = - zx_object_wait_async(handle_, weak_pump_->port_.get(), wait_key(), - desired_signals_, ZX_WAIT_ASYNC_ONCE); - if (status != ZX_OK) { - DLOG(ERROR) << "zx_object_wait_async failed: " - << zx_status_get_string(status) - << " (port=" << weak_pump_->port_.get() << ")"; - return false; - } - - has_begun_ = true; - - return true; -} - -uint32_t MessagePumpFuchsia::ZxHandleWatchController::WaitEnd( - zx_signals_t signals) { - DCHECK(has_begun_); - - has_begun_ = false; - - // |signals| can include other spurious things, in particular, that an fd - // is writable, when we only asked to know when it was readable. In that - // case, we don't want to call both the CanWrite and CanRead callback, - // when the caller asked for only, for example, readable callbacks. So, - // mask with the events that we actually wanted to know about. - signals &= desired_signals_; - return signals; -} - bool MessagePumpFuchsia::HandleEvents(zx_time_t deadline) { - zx_port_packet_t packet; - const zx_status_t wait_status = - zx_port_wait(port_.get(), deadline, &packet, 0); - - if (wait_status == ZX_ERR_TIMED_OUT) - return false; - - if (wait_status != ZX_OK) { - NOTREACHED() << "unexpected wait status: " - << zx_status_get_string(wait_status); - return false; - } + zx_status_t status = async_dispatcher_.DispatchOrWaitUntil(deadline); + switch (status) { + // Return true if some tasks or events were dispatched or if the dispatcher + // was stopped by ScheduleWork(). + case ZX_OK: + case ZX_ERR_CANCELED: + return true; + + case ZX_ERR_TIMED_OUT: + return false; - if (packet.type == ZX_PKT_TYPE_SIGNAL_ONE) { - // A watched fd caused the wakeup via zx_object_wait_async(). - DCHECK_EQ(ZX_OK, packet.status); - ZxHandleWatchController* controller = - reinterpret_cast<ZxHandleWatchController*>( - static_cast<uintptr_t>(packet.key)); - - DCHECK_NE(0u, packet.signal.trigger & packet.signal.observed); - - zx_signals_t signals = controller->WaitEnd(packet.signal.observed); - - // In the case of a persistent Watch, the Watch may be stopped and - // potentially deleted by the caller within the callback, in which case - // |controller| should not be accessed again, and we mustn't continue the - // watch. We check for this with a bool on the stack, which the Watch - // receives a pointer to. - bool controller_was_stopped = false; - controller->was_stopped_ = &controller_was_stopped; - - controller->watcher_->OnZxHandleSignalled(controller->handle_, signals); - - if (!controller_was_stopped) { - controller->was_stopped_ = nullptr; - if (controller->persistent_) - controller->WaitBegin(); - } - } else { - // Wakeup caused by ScheduleWork(). - DCHECK_EQ(ZX_PKT_TYPE_USER, packet.type); + default: + ZX_DLOG(DCHECK, status) << "unexpected wait status"; + return false; } - - return true; } void MessagePumpFuchsia::Run(Delegate* delegate) { @@ -295,13 +288,9 @@ void MessagePumpFuchsia::Quit() { } void MessagePumpFuchsia::ScheduleWork() { - // Since this can be called on any thread, we need to ensure that our Run loop - // wakes up. - zx_port_packet_t packet = {}; - packet.type = ZX_PKT_TYPE_USER; - zx_status_t status = zx_port_queue(port_.get(), &packet, 0); - DLOG_IF(ERROR, status != ZX_OK) - << "zx_port_queue failed: " << status << " (port=" << port_.get() << ")"; + // Stop AsyncDispatcher to let MessagePumpFuchsia::Run() handle message loop + // tasks. + async_dispatcher_.Stop(); } void MessagePumpFuchsia::ScheduleDelayedWork( diff --git a/chromium/base/message_loop/message_pump_fuchsia.h b/chromium/base/message_loop/message_pump_fuchsia.h index dbcd7d4dc38..514e23f79bf 100644 --- a/chromium/base/message_loop/message_pump_fuchsia.h +++ b/chromium/base/message_loop/message_pump_fuchsia.h @@ -5,17 +5,17 @@ #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_FUCHSIA_H_ #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_FUCHSIA_H_ +#include <lib/async/wait.h> + #include "base/base_export.h" -#include "base/fuchsia/scoped_zx_handle.h" +#include "base/fuchsia/async_dispatcher.h" #include "base/location.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_pump.h" #include "base/message_loop/watchable_io_message_pump_posix.h" -#include <fdio/io.h> -#include <fdio/private.h> -#include <zircon/syscalls/port.h> +typedef struct fdio fdio_t; namespace base { @@ -33,7 +33,7 @@ class BASE_EXPORT MessagePumpFuchsia : public MessagePump, }; // Manages an active watch on an zx_handle_t. - class ZxHandleWatchController { + class ZxHandleWatchController : public async_wait_t { public: explicit ZxHandleWatchController(const Location& from_here); // Deleting the Controller implicitly calls StopWatchingZxHandle. @@ -46,6 +46,17 @@ class BASE_EXPORT MessagePumpFuchsia : public MessagePump, const Location& created_from_location() { return created_from_location_; } protected: + friend class MessagePumpFuchsia; + + virtual bool WaitBegin(); + + static void HandleSignal(async_t* async, + async_wait_t* wait, + zx_status_t status, + const zx_packet_signal_t* signal); + + const Location created_from_location_; + // This bool is used by the pump when invoking the ZxHandleWatcher callback, // and by the FdHandleWatchController when invoking read & write callbacks, // to cope with the possibility of the caller deleting the *Watcher within @@ -54,28 +65,8 @@ class BASE_EXPORT MessagePumpFuchsia : public MessagePump, // to check the value on the stack to short-cut any post-callback work. bool* was_stopped_ = nullptr; - protected: - friend class MessagePumpFuchsia; - - // Start watching the handle. - virtual bool WaitBegin(); - - // Called by MessagePumpFuchsia when the handle is signalled. Accepts the - // set of signals that fired, and returns the intersection with those the - // caller is interested in. - zx_signals_t WaitEnd(zx_signals_t observed); - - // Returns the key to use to uniquely identify this object's wait operation. - uint64_t wait_key() const { - return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this)); - } - - const Location created_from_location_; - // Set directly from the inputs to WatchFileDescriptor. ZxHandleWatcher* watcher_ = nullptr; - zx_handle_t handle_ = ZX_HANDLE_INVALID; - zx_signals_t desired_signals_ = 0; // Used to safely access resources owned by the associated message pump. WeakPtr<MessagePumpFuchsia> weak_pump_; @@ -84,10 +75,6 @@ class BASE_EXPORT MessagePumpFuchsia : public MessagePump, // after triggering. bool persistent_ = false; - // Used to determine whether an asynchronous wait operation is active on - // this controller. - bool has_begun_ = false; - DISALLOW_COPY_AND_ASSIGN(ZxHandleWatchController); }; @@ -148,14 +135,14 @@ class BASE_EXPORT MessagePumpFuchsia : public MessagePump, void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override; private: - // Handles IO events from the |port_|. Returns true if any events were - // received. + // Handles IO events by running |async_dispatcher_|. Returns true if any + // events were received or if ScheduleWork() was called. bool HandleEvents(zx_time_t deadline); // This flag is set to false when Run should return. bool keep_running_ = true; - ScopedZxHandle port_; + AsyncDispatcher async_dispatcher_; // The time at which we should call DoDelayedWork. TimeTicks delayed_work_time_; diff --git a/chromium/base/message_loop/message_pump_glib_unittest.cc b/chromium/base/message_loop/message_pump_glib_unittest.cc index 451c6f5caa2..70be2a4f74c 100644 --- a/chromium/base/message_loop/message_pump_glib_unittest.cc +++ b/chromium/base/message_loop/message_pump_glib_unittest.cc @@ -16,6 +16,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread.h" @@ -190,7 +191,7 @@ TEST_F(MessagePumpGLibTest, TestQuit) { injector()->Reset(); // Quit from an event - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); + injector()->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); RunLoop().Run(); EXPECT_EQ(1, injector()->processed_events()); } @@ -210,7 +211,7 @@ TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); injector()->AddEventAsTask(0, std::move(posted_task)); injector()->AddEventAsTask(0, DoNothing()); - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); + injector()->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); RunLoop().Run(); EXPECT_EQ(4, injector()->processed_events()); @@ -221,7 +222,7 @@ TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); injector()->AddEventAsTask(0, std::move(posted_task)); injector()->AddEventAsTask(10, DoNothing()); - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); + injector()->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); RunLoop().Run(); EXPECT_EQ(4, injector()->processed_events()); } @@ -238,7 +239,7 @@ TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { // quit. loop()->task_runner()->PostTask( FROM_HERE, BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0, - MessageLoop::QuitWhenIdleClosure())); + RunLoop::QuitCurrentWhenIdleClosureDeprecated())); RunLoop().Run(); ASSERT_EQ(10, task_count); EXPECT_EQ(1, injector()->processed_events()); @@ -258,7 +259,7 @@ TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { loop()->task_runner()->PostDelayedTask( FROM_HERE, BindOnce(&EventInjector::AddEvent, Unretained(injector()), 10, - MessageLoop::QuitWhenIdleClosure()), + RunLoop::QuitCurrentWhenIdleClosureDeprecated()), TimeDelta::FromMilliseconds(150)); RunLoop().Run(); ASSERT_EQ(10, task_count); @@ -281,7 +282,7 @@ TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) { injector()->AddEventAsTask(10, std::move(posted_task)); // And then quit (relies on the condition tested by TestEventTaskInterleave). - injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure()); + injector()->AddEvent(10, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); RunLoop().Run(); EXPECT_EQ(12, injector()->processed_events()); @@ -373,7 +374,7 @@ void AddEventsAndDrainGLib(EventInjector* injector) { injector->AddDummyEvent(0); injector->AddDummyEvent(0); // Then add an event that will quit the main loop. - injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); + injector->AddEvent(0, RunLoop::QuitCurrentWhenIdleClosureDeprecated()); // Post a couple of dummy tasks ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing()); @@ -433,7 +434,7 @@ class GLibLoopRunner : public RefCounted<GLibLoopRunner> { void TestGLibLoopInternal(EventInjector* injector) { // Allow tasks to be processed from 'native' event loops. - MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner(); int task_count = 0; @@ -466,7 +467,7 @@ void TestGLibLoopInternal(EventInjector* injector) { void TestGtkLoopInternal(EventInjector* injector) { // Allow tasks to be processed from 'native' event loops. - MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoopCurrent::Get()->SetNestableTasksAllowed(true); scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner(); int task_count = 0; diff --git a/chromium/base/message_loop/message_pump_io_ios_unittest.cc b/chromium/base/message_loop/message_pump_io_ios_unittest.cc index dc78309590f..4d15d44db32 100644 --- a/chromium/base/message_loop/message_pump_io_ios_unittest.cc +++ b/chromium/base/message_loop/message_pump_io_ios_unittest.cc @@ -7,7 +7,6 @@ #include <unistd.h> #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/posix/eintr_wrapper.h" #include "base/test/gtest_util.h" #include "base/threading/thread.h" @@ -17,15 +16,10 @@ namespace base { class MessagePumpIOSForIOTest : public testing::Test { protected: - MessagePumpIOSForIOTest() - : ui_loop_(MessageLoop::TYPE_UI), - io_thread_("MessagePumpIOSForIOTestIOThread") {} - ~MessagePumpIOSForIOTest() override {} + MessagePumpIOSForIOTest() = default; + ~MessagePumpIOSForIOTest() override = default; void SetUp() override { - Thread::Options options(MessageLoop::TYPE_IO, 0); - ASSERT_TRUE(io_thread_.StartWithOptions(options)); - ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type()); int ret = pipe(pipefds_); ASSERT_EQ(0, ret); ret = pipe(alternate_pipefds_); @@ -39,11 +33,6 @@ class MessagePumpIOSForIOTest : public testing::Test { PLOG(ERROR) << "close"; } - MessageLoop* ui_loop() { return &ui_loop_; } - MessageLoopForIO* io_loop() const { - return static_cast<MessageLoopForIO*>(io_thread_.message_loop()); - } - void HandleFdIOEvent(MessagePumpForIO::FdWatchController* watcher) { MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_.get(), kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack, @@ -54,9 +43,6 @@ class MessagePumpIOSForIOTest : public testing::Test { int alternate_pipefds_[2]; private: - MessageLoop ui_loop_; - Thread io_thread_; - DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest); }; @@ -73,16 +59,6 @@ class StupidWatcher : public MessagePumpIOSForIO::FdWatcher { void OnFileCanWriteWithoutBlocking(int fd) override {} }; -// Test to make sure that we catch calling WatchFileDescriptor off of the wrong -// thread. -TEST_F(MessagePumpIOSForIOTest, TestWatchingFromBadThread) { - MessagePumpIOSForIO::FdWatchController watcher(FROM_HERE); - StupidWatcher delegate; - - ASSERT_DCHECK_DEATH(io_loop()->WatchFileDescriptor( - STDOUT_FILENO, false, MessagePumpForIO::WATCH_READ, &watcher, &delegate)); -} - class BaseWatcher : public MessagePumpIOSForIO::FdWatcher { public: BaseWatcher(MessagePumpIOSForIO::FdWatchController* controller) diff --git a/chromium/base/message_loop/message_pump_libevent_unittest.cc b/chromium/base/message_loop/message_pump_libevent_unittest.cc index 0444e35ace2..55eb0b4d728 100644 --- a/chromium/base/message_loop/message_pump_libevent_unittest.cc +++ b/chromium/base/message_loop/message_pump_libevent_unittest.cc @@ -55,8 +55,8 @@ class MessagePumpLibeventTest : public testing::Test { ASSERT_TRUE(io_thread_.WaitUntilThreadStarted()); } - MessageLoopForIO* io_loop() const { - return static_cast<MessageLoopForIO*>(io_thread_.message_loop()); + scoped_refptr<SingleThreadTaskRunner> io_runner() const { + return io_thread_.task_runner(); } void OnLibeventNotification( @@ -85,20 +85,6 @@ class StupidWatcher : public MessagePumpLibevent::FdWatcher { void OnFileCanWriteWithoutBlocking(int fd) override {} }; -// Test to make sure that we catch calling WatchFileDescriptor off of the -// wrong thread. -TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) { - MessagePumpLibevent::FdWatchController watcher(FROM_HERE); - StupidWatcher delegate; - - // Ensure that |io_thread_| has started, otherwise we're racing against - // creation of the thread's MessagePump. - WaitUntilIoThreadStarted(); - - ASSERT_DCHECK_DEATH(io_loop()->WatchFileDescriptor( - STDOUT_FILENO, false, MessagePumpForIO::WATCH_READ, &watcher, &delegate)); -} - TEST_F(MessagePumpLibeventTest, QuitOutsideOfRun) { std::unique_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); ASSERT_DCHECK_DEATH(pump->Quit()); @@ -255,10 +241,10 @@ TEST_F(MessagePumpLibeventTest, QuitWatcher) { const char buf = 0; WaitableEventWatcher::EventCallback write_fd_task = BindOnce(&WriteFDWrapper, pipefds_[1], &buf, 1); - io_loop()->task_runner()->PostTask( + io_runner()->PostTask( FROM_HERE, BindOnce(IgnoreResult(&WaitableEventWatcher::StartWatching), Unretained(watcher.get()), &event, - std::move(write_fd_task), io_loop()->task_runner())); + std::move(write_fd_task), io_runner())); // Queue |event| to signal on |loop|. loop.task_runner()->PostTask( @@ -268,9 +254,8 @@ TEST_F(MessagePumpLibeventTest, QuitWatcher) { run_loop.Run(); // StartWatching can move |watcher| to IO thread. Release on IO thread. - io_loop()->task_runner()->PostTask( - FROM_HERE, - BindOnce(&WaitableEventWatcher::StopWatching, Owned(watcher.release()))); + io_runner()->PostTask(FROM_HERE, BindOnce(&WaitableEventWatcher::StopWatching, + Owned(watcher.release()))); } } // namespace diff --git a/chromium/base/message_loop/message_pump_mac.mm b/chromium/base/message_loop/message_pump_mac.mm index eed9247079e..fb252017999 100644 --- a/chromium/base/message_loop/message_pump_mac.mm +++ b/chromium/base/message_loop/message_pump_mac.mm @@ -25,41 +25,12 @@ namespace base { -// kMessageLoopExclusiveRunLoopMode must be defined before kAllModes to generate -// a sane static initialization order. const CFStringRef kMessageLoopExclusiveRunLoopMode = CFSTR("kMessageLoopExclusiveRunLoopMode"); namespace { -// kCFRunLoopCommonModes is const but not constexpr; hence kAllModes is -// initialized at run-time. This initialization being trivial, constant, and -// without side-effects: this is fine. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wglobal-constructors" - -// AppKit RunLoop modes observed to potentially run tasks posted to Chrome's -// main thread task runner. Some are internal to AppKit but must be observed to -// keep Chrome's UI responsive. Others that may be interesting, but are not -// watched: -// - com.apple.hitoolbox.windows.transitionmode -// - com.apple.hitoolbox.windows.flushmode -const CFStringRef kAllModes[] = { - kCFRunLoopCommonModes, - - // Mode that only sees Chrome work sources. - kMessageLoopExclusiveRunLoopMode, - - // Process work when NSMenus are fading out. - CFSTR("com.apple.hitoolbox.windows.windowfadingmode"), - - // Process work when AppKit is highlighting an item on the main menubar. - CFSTR("NSUnhighlightMenuRunLoopMode"), -}; - -#pragma clang diagnostic pop // -Wglobal-constructors - -// Mask that determines which modes in |kAllModes| to use. +// Mask that determines which modes to use. enum { kCommonModeMask = 0x1, kAllModesMask = 0xf }; // Modes to use for MessagePumpNSApplication that are considered "safe". @@ -85,9 +56,7 @@ MessagePumpNSApplication* g_app_pump; typedef struct __CFRuntimeBase { uintptr_t _cfisa; uint8_t _cfinfo[4]; -#if __LP64__ uint32_t _rc; -#endif } CFRuntimeBase; #if defined(__BIG_ENDIAN__) @@ -167,7 +136,33 @@ class MessagePumpCFRunLoopBase::ScopedModeEnabler { CFRunLoopRemoveTimer(loop, owner_->delayed_work_timer_, mode()); } - const CFStringRef& mode() const { return kAllModes[mode_index_]; } + // This function knows about the AppKit RunLoop modes observed to potentially + // run tasks posted to Chrome's main thread task runner. Some are internal to + // AppKit but must be observed to keep Chrome's UI responsive. Others that may + // be interesting, but are not watched: + // - com.apple.hitoolbox.windows.transitionmode + // - com.apple.hitoolbox.windows.flushmode + const CFStringRef& mode() const { + static const CFStringRef modes[] = { + // The standard Core Foundation "common modes" constant. Must always be + // first in this list to match the value of kCommonModeMask. + kCFRunLoopCommonModes, + + // Mode that only sees Chrome work sources. + kMessageLoopExclusiveRunLoopMode, + + // Process work when NSMenus are fading out. + CFSTR("com.apple.hitoolbox.windows.windowfadingmode"), + + // Process work when AppKit is highlighting an item on the main menubar. + CFSTR("NSUnhighlightMenuRunLoopMode"), + }; + static_assert(arraysize(modes) == kNumModes, "mode size mismatch"); + static_assert((1 << kNumModes) - 1 == kAllModesMask, + "kAllModesMask not large enough"); + + return modes[mode_index_]; + } private: MessagePumpCFRunLoopBase* const owner_; // Weak. Owns this. @@ -331,9 +326,7 @@ AutoreleasePoolType* MessagePumpCFRunLoopBase::CreateAutoreleasePool() { } void MessagePumpCFRunLoopBase::SetModeMask(int mode_mask) { - static_assert(arraysize(enabled_modes_) == arraysize(kAllModes), - "mode size mismatch"); - for (size_t i = 0; i < arraysize(kAllModes); ++i) { + for (size_t i = 0; i < kNumModes; ++i) { bool enable = mode_mask & (0x1 << i); if (enable == !enabled_modes_[i]) { enabled_modes_[i] = @@ -344,7 +337,7 @@ void MessagePumpCFRunLoopBase::SetModeMask(int mode_mask) { int MessagePumpCFRunLoopBase::GetModeMask() const { int mask = 0; - for (size_t i = 0; i < arraysize(enabled_modes_); ++i) + for (size_t i = 0; i < kNumModes; ++i) mask |= enabled_modes_[i] ? (0x1 << i) : 0; return mask; } diff --git a/chromium/base/message_loop/message_pump_mac_unittest.mm b/chromium/base/message_loop/message_pump_mac_unittest.mm index 480b311fa38..6b63aa14f5d 100644 --- a/chromium/base/message_loop/message_pump_mac_unittest.mm +++ b/chromium/base/message_loop/message_pump_mac_unittest.mm @@ -8,6 +8,7 @@ #import "base/mac/scoped_nsobject.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/threading/thread_task_runner_handle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -131,7 +132,7 @@ namespace { // the counter incremented after emptying that run loop mode. void IncrementInModeAndExpect(CFRunLoopMode mode, int result) { // Since this task is "ours" rather than a system task, allow nesting. - MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); + MessageLoopCurrent::ScopedNestableTaskAllower allow; int counter = 0; auto increment = BindRepeating([](int* i) { ++*i; }, &counter); ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, increment); diff --git a/chromium/base/message_loop/message_pump_perftest.cc b/chromium/base/message_loop/message_pump_perftest.cc index cadd58e64f3..76f18cb467e 100644 --- a/chromium/base/message_loop/message_pump_perftest.cc +++ b/chromium/base/message_loop/message_pump_perftest.cc @@ -9,6 +9,7 @@ #include "base/bind_helpers.h" #include "base/format_macros.h" #include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" #include "base/synchronization/condition_variable.h" diff --git a/chromium/base/message_loop/message_pump_win.cc b/chromium/base/message_loop/message_pump_win.cc index ca257370fb5..68bb4c08465 100644 --- a/chromium/base/message_loop/message_pump_win.cc +++ b/chromium/base/message_loop/message_pump_win.cc @@ -11,7 +11,6 @@ #include "base/debug/alias.h" #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" @@ -128,6 +127,10 @@ void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { RescheduleTimer(); } +void MessagePumpForUI::EnableWmQuit() { + enable_wm_quit_ = true; +} + //----------------------------------------------------------------------------- // MessagePumpForUI private: @@ -351,9 +354,17 @@ bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper", "message", msg.message); if (WM_QUIT == msg.message) { + if (enable_wm_quit_) { + // Repost the QUIT message so that it will be retrieved by the primary + // GetMessage() loop. + state_->should_quit = true; + PostQuitMessage(static_cast<int>(msg.wParam)); + return false; + } + // WM_QUIT is the standard way to exit a GetMessage() loop. Our MessageLoop // has its own quit mechanism, so WM_QUIT is unexpected and should be - // ignored. + // ignored when |enable_wm_quit_| is set to false. UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", RECEIVED_WM_QUIT_ERROR, MESSAGE_LOOP_PROBLEM_MAX); return true; diff --git a/chromium/base/message_loop/message_pump_win.h b/chromium/base/message_loop/message_pump_win.h index f8a8557014b..c1f96bd1e24 100644 --- a/chromium/base/message_loop/message_pump_win.h +++ b/chromium/base/message_loop/message_pump_win.h @@ -124,6 +124,9 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin { void ScheduleWork() override; void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override; + // Make the MessagePumpForUI respond to WM_QUIT messages. + void EnableWmQuit(); + private: bool MessageCallback( UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result); @@ -137,6 +140,10 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin { bool ProcessPumpReplacementMessage(); base::win::MessageWindow message_window_; + + // Whether MessagePumpForUI responds to WM_QUIT messages or not. + // TODO(thestig): Remove when the Cloud Print Service goes away. + bool enable_wm_quit_ = false; }; //----------------------------------------------------------------------------- |