blob: a3b48b58d367501100d8ee4d5b9391f15597d367 [file] [log] [blame]
// 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 <ostream>
#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 web {
class WebTaskEnvironment;
}
namespace base {
class MessageLoopImpl;
namespace sequence_manager {
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<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::SetTaskRunner().
// DEPRECATED(https://crbug.com/825327): only owners of the MessageLoop
// instance should replace its TaskRunner.
void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
// 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:
sequence_manager::internal::SequenceManagerImpl* const sequence_manager_;
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:
explicit MessageLoopCurrent(
sequence_manager::internal::SequenceManagerImpl* sequence_manager)
: current_(sequence_manager) {}
static sequence_manager::internal::SequenceManagerImpl*
GetCurrentSequenceManagerImpl();
friend class MessageLoopImpl;
friend class MessagePumpLibeventTest;
friend class ScheduleWorkTest;
friend class Thread;
friend class sequence_manager::internal::SequenceManagerImpl;
friend class MessageLoopTaskRunnerTest;
friend class web::WebTaskEnvironment;
sequence_manager::internal::SequenceManagerImpl* 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)
static_assert(
std::is_base_of<WatchableIOMessagePumpPosix, MessagePumpForUI>::value,
"MessageLoopCurrentForUI::WatchFileDescriptor is supported only"
"by MessagePumpLibevent and MessagePumpGlib implementations.");
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::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(
sequence_manager::internal::SequenceManagerImpl* 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_MACOSX) && !defined(OS_IOS)
bool WatchMachReceivePort(
mach_port_t port,
MessagePumpForIO::MachPortWatchController* controller,
MessagePumpForIO::MachPortWatcher* delegate);
#endif
#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(
sequence_manager::internal::SequenceManagerImpl* current)
: MessageLoopCurrent(current) {}
MessagePumpForIO* GetMessagePumpForIO() const;
};
} // namespace base
#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_CURRENT_H_