1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TASK_CURRENT_THREAD_H_
#define BASE_TASK_CURRENT_THREAD_H_
#include <ostream>
#include "base/base_export.h"
#include "base/check.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/message_loop/ios_cronet_buildflags.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/task/sequence_manager/task_time_observer.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_observer.h"
#include "build/build_config.h"
namespace web {
class WebTaskEnvironment;
}
namespace base {
namespace sequence_manager {
namespace internal {
class SequenceManagerImpl;
}
} // namespace sequence_manager
// CurrentThread is a proxy to a subset of Task related APIs bound to the
// current thread
//
// Current(UI|IO)Thread is available statically through
// Current(UI|IO)Thread::Get() on threads that have registered as CurrentThread
// on this physical thread (e.g. by using SingleThreadTaskExecutor). APIs
// intended for all consumers on the thread should be on Current(UI|IO)Thread,
// while internal APIs might be on multiple internal classes (e.g.
// SequenceManager).
//
// Why: Historically MessageLoop would take care of everything related to event
// processing on a given thread. Nowadays that functionality is split among
// different classes. At that time 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
// once all static callers have been migrated.
class BASE_EXPORT CurrentThread {
public:
// CurrentThread is effectively just a disguised pointer and is fine to
// copy/move around.
CurrentThread(const CurrentThread& other) = default;
CurrentThread(CurrentThread&& other) = default;
CurrentThread& operator=(const CurrentThread& other) = default;
bool operator==(const CurrentThread& other) const;
// Returns a proxy object to interact with the Task related APIs for the
// current thread. It must only be used on the thread it was obtained.
static CurrentThread Get();
// Return an empty CurrentThread. No methods should be called on this
// object.
static CurrentThread GetNull();
// Returns true if the current thread is registered to expose CurrentThread
// API. 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 CurrentThread to be used like a pointer to support the many
// callsites that used MessageLoop::current() that way when it was a
// MessageLoop*.
CurrentThread* operator->() { return this; }
explicit operator bool() const { return !!current_; }
// A DestructionObserver is notified when the current task execution
// environment is being destroyed. These observers are notified prior to
// CurrentThread::IsSet() being changed to return false. This gives interested
// parties the chance to do final cleanup.
//
// NOTE: Any tasks posted to the current thread 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:
// TODO(https://crbug.com/891670): Rename to
// WillDestroyCurrentTaskExecutionEnvironment
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 SequenceManager::SetTaskRunner().
// DEPRECATED(https://crbug.com/825327): only owners of the SequenceManager
// instance should replace its TaskRunner.
void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
// Forwards to SequenceManager::(Add|Remove)TaskObserver.
// DEPRECATED(https://crbug.com/825327): only owners of the SequenceManager
// 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);
// Registers a OnceClosure to be called on this thread the next time it goes
// idle. This is meant for internal usage; callers should use BEST_EFFORT
// tasks instead of this for generic work that needs to wait until quiescence
// to run. There can only be one OnNextIdleCallback at a time. Can be called
// with a null callback to clear any potentially pending callbacks.
void RegisterOnNextIdleCallback(OnceClosure on_next_idle_callback);
// Enables nested task processing in scope of an upcoming native message loop.
// Some unwanted message loops may occur when using common controls or printer
// functions. Hence, nested task processing is disabled by default to avoid
// unplanned reentrancy. This re-enables it in cases where the stack is
// reentrancy safe and processing nestable tasks is explicitly safe.
//
// For instance,
// - The current thread is running a message loop.
// - It receives a task #1 and executes it.
// - The task #1 implicitly starts a nested 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".
//
// Use RunLoop::Type::kNestableTasksAllowed when nesting is triggered by the
// application RunLoop rather than by native code.
class BASE_EXPORT ScopedAllowApplicationTasksInNativeNestedLoop {
public:
ScopedAllowApplicationTasksInNativeNestedLoop();
~ScopedAllowApplicationTasksInNativeNestedLoop();
private:
const raw_ptr<sequence_manager::internal::SequenceManagerImpl>
sequence_manager_;
const bool previous_state_;
};
// Returns true if nestable tasks are allowed on the current thread at this
// time (i.e. if a native nested loop would start from the callee's point in
// the stack, would it be allowed to run application tasks).
bool ApplicationTasksAllowedInNativeNestedLoop() const;
// Returns true if this instance is bound to the current thread.
bool IsBoundToCurrentThread() const;
// Returns true if the current thread 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();
// Enables ThreadControllerWithMessagePumpImpl's TimeKeeper metrics.
// `thread_name` will be used as a suffix.
void EnableMessagePumpTimeKeeperMetrics(const char* thread_name);
protected:
explicit CurrentThread(
sequence_manager::internal::SequenceManagerImpl* sequence_manager)
: current_(sequence_manager) {}
static sequence_manager::internal::SequenceManagerImpl*
GetCurrentSequenceManagerImpl();
friend class MessagePumpLibeventTest;
friend class ScheduleWorkTest;
friend class Thread;
friend class sequence_manager::internal::SequenceManagerImpl;
friend class MessageLoopTaskRunnerTest;
friend class web::WebTaskEnvironment;
raw_ptr<sequence_manager::internal::SequenceManagerImpl> current_;
};
#if !BUILDFLAG(IS_NACL)
// UI extension of CurrentThread.
class BASE_EXPORT CurrentUIThread : public CurrentThread {
public:
// Returns an interface for the CurrentUIThread of the current thread.
// Asserts that IsSet().
static CurrentUIThread Get();
// Returns true if the current thread is running a CurrentUIThread.
static bool IsSet();
CurrentUIThread* operator->() { return this; }
#if BUILDFLAG(IS_OZONE) && !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_WIN)
static_assert(
std::is_base_of_v<WatchableIOMessagePumpPosix, MessagePumpForUI>,
"CurrentThreadForUI::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 BUILDFLAG(IS_IOS)
// Forwards to SequenceManager::Attach().
// TODO(https://crbug.com/825327): Plumb the actual SequenceManager* to
// callers and remove ability to access this method from
// CurrentUIThread.
void Attach();
#endif
#if BUILDFLAG(IS_ANDROID)
// Forwards to MessagePumpForUI::Abort().
// TODO(https://crbug.com/825327): Plumb the actual MessagePumpForUI* to
// callers and remove ability to access this method from
// CurrentUIThread.
void Abort();
#endif
#if BUILDFLAG(IS_WIN)
void AddMessagePumpObserver(MessagePumpForUI::Observer* observer);
void RemoveMessagePumpObserver(MessagePumpForUI::Observer* observer);
#endif
private:
explicit CurrentUIThread(
sequence_manager::internal::SequenceManagerImpl* current)
: CurrentThread(current) {}
MessagePumpForUI* GetMessagePumpForUI() const;
};
#endif // !BUILDFLAG(IS_NACL)
// ForIO extension of CurrentThread.
class BASE_EXPORT CurrentIOThread : public CurrentThread {
public:
// Returns an interface for the CurrentIOThread of the current thread.
// Asserts that IsSet().
static CurrentIOThread Get();
// Returns true if the current thread is running a CurrentIOThread.
static bool IsSet();
CurrentIOThread* operator->() { return this; }
#if !BUILDFLAG(IS_NACL)
#if BUILDFLAG(IS_WIN)
// Please see MessagePumpWin for definitions of these methods.
HRESULT RegisterIOHandler(HANDLE file, MessagePumpForIO::IOHandler* handler);
bool RegisterJobObject(HANDLE job, MessagePumpForIO::IOHandler* handler);
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_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 // BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_IOS) && !BUILDFLAG(CRONET_BUILD))
bool WatchMachReceivePort(
mach_port_t port,
MessagePumpForIO::MachPortWatchController* controller,
MessagePumpForIO::MachPortWatcher* delegate);
#endif
#if BUILDFLAG(IS_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 // BUILDFLAG(IS_FUCHSIA)
#endif // !BUILDFLAG(IS_NACL)
private:
explicit CurrentIOThread(
sequence_manager::internal::SequenceManagerImpl* current)
: CurrentThread(current) {}
MessagePumpForIO* GetMessagePumpForIO() const;
};
} // namespace base
#endif // BASE_TASK_CURRENT_THREAD_H_
|