// 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 #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 "base/task/task_observer.h" #include "build/build_config.h" namespace QtWebEngineCore { class MessagePumpForUIQt; class WebContentsAdapter; } namespace web { class TestWebThreadBundle; } namespace base { class MessageLoopBase; class MessageLoopImpl; namespace sequence_manager { class LazyThreadControllerForTest; namespace internal { class SequenceManagerImpl; } } // namespace sequence_manager // 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/move around. MessageLoopCurrent(const MessageLoopCurrent& other) = default; MessageLoopCurrent(MessageLoopCurrent&& other) = default; MessageLoopCurrent& operator=(const MessageLoopCurrent& other) = default; bool operator==(const MessageLoopCurrent& other) const; // 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(); // Return an empty MessageLoopCurrent. No methods should be called on this // object. static MessageLoopCurrent GetNull(); // 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_; } // 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> 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); // Returns the name for the thread associated with this object. std::string GetThreadName() const; // Forwards to MessageLoop::task_runner(). // DEPRECATED(https://crbug.com/616447): Use ThreadTaskRunnerHandle::Get() // instead of MessageLoopCurrent::Get()->task_runner(). scoped_refptr 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 task_runner); // This alias is deprecated. Use base::TaskObserver instead. // TODO(yutak): Replace all the use sites with base::TaskObserver. using TaskObserver = base::TaskObserver; // 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); // When this functionality is enabled, the queue time will be recorded for // posted tasks. void SetAddQueueTimeToTasks(bool enable); // 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: MessageLoopBase* const loop_; const bool old_state_; }; // Returns true if this is the active MessageLoop for the current thread. bool IsBoundToCurrentThread() const; // 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(); protected: // 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(MessageLoopBase* 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(MessageLoopBase* current); explicit MessageLoopCurrent(MessageLoopBase* current) : current_(current) {} friend class MessageLoopImpl; friend class MessagePumpLibeventTest; friend class ScheduleWorkTest; friend class Thread; friend class sequence_manager::LazyThreadControllerForTest; friend class sequence_manager::internal::SequenceManagerImpl; friend class MessageLoopTaskRunnerTest; friend class web::TestWebThreadBundle; friend class QtWebEngineCore::MessagePumpForUIQt; friend class QtWebEngineCore::WebContentsAdapter; // Return the pointer to MessageLoop for internal needs. // All other callers should call MessageLoopCurrent::Get(). // TODO(altimin): Remove this. MessageLoopBase* ToMessageLoopBaseDeprecated() const { return current_; } MessageLoopBase* 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::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) || defined(OS_ANDROID) // 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::Abort(). // TODO(https://crbug.com/825327): Plumb the actual MessageLoopForUI* to // callers and remove ability to access this method from // MessageLoopCurrentForUI. void Abort(); #endif #if defined(OS_WIN) void AddMessagePumpObserver(MessagePumpForUI::Observer* observer); void RemoveMessagePumpObserver(MessagePumpForUI::Observer* observer); #endif private: explicit MessageLoopCurrentForUI(MessageLoopBase* current) : MessageLoopCurrent(current) {} MessagePumpForUI* GetMessagePumpForUI() const; }; #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. HRESULT 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: explicit MessageLoopCurrentForIO(MessageLoopBase* current) : MessageLoopCurrent(current) {} MessagePumpForIO* GetMessagePumpForIO() const; }; } // namespace base #endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_CURRENT_H_