1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TASK_CURRENT_THREAD_H_ 6 #define BASE_TASK_CURRENT_THREAD_H_ 7 8 #include <ostream> 9 #include <type_traits> 10 11 #include "base/base_export.h" 12 #include "base/callback_list.h" 13 #include "base/check.h" 14 #include "base/functional/callback_forward.h" 15 #include "base/memory/raw_ptr.h" 16 #include "base/memory/scoped_refptr.h" 17 #include "base/message_loop/ios_cronet_buildflags.h" 18 #include "base/message_loop/message_pump_for_io.h" 19 #include "base/message_loop/message_pump_for_ui.h" 20 #include "base/pending_task.h" 21 #include "base/task/sequence_manager/task_time_observer.h" 22 #include "base/task/single_thread_task_runner.h" 23 #include "base/task/task_observer.h" 24 #include "build/build_config.h" 25 26 namespace autofill { 27 class NextIdleBarrier; 28 } 29 30 namespace content { 31 class BrowserMainLoop; 32 } 33 34 namespace web { 35 class WebTaskEnvironment; 36 } 37 38 namespace base { 39 40 namespace test { 41 bool RunUntil(FunctionRef<bool(void)>); 42 void TestPredicateOrRegisterOnNextIdleCallback(base::FunctionRef<bool(void)>, 43 CallbackListSubscription*, 44 OnceClosure); 45 } // namespace test 46 47 namespace sequence_manager { 48 namespace internal { 49 class SequenceManagerImpl; 50 } 51 } // namespace sequence_manager 52 53 class IOWatcher; 54 55 // CurrentThread is a proxy to a subset of Task related APIs bound to the 56 // current thread 57 // 58 // Current(UI|IO)Thread is available statically through 59 // Current(UI|IO)Thread::Get() on threads that have registered as CurrentThread 60 // on this physical thread (e.g. by using SingleThreadTaskExecutor). APIs 61 // intended for all consumers on the thread should be on Current(UI|IO)Thread, 62 // while internal APIs might be on multiple internal classes (e.g. 63 // SequenceManager). 64 // 65 // Why: Historically MessageLoop would take care of everything related to event 66 // processing on a given thread. Nowadays that functionality is split among 67 // different classes. At that time MessageLoop::current() gave access to the 68 // full MessageLoop API, preventing both addition of powerful owner-only APIs as 69 // well as making it harder to remove callers of deprecated APIs (that need to 70 // stick around for a few owner-only use cases and re-accrue callers after 71 // cleanup per remaining publicly available). 72 // 73 // As such, many methods below are flagged as deprecated and should be removed 74 // once all static callers have been migrated. 75 class BASE_EXPORT CurrentThread { 76 public: 77 // CurrentThread is effectively just a disguised pointer and is fine to 78 // copy/move around. 79 CurrentThread(const CurrentThread& other) = default; 80 CurrentThread(CurrentThread&& other) = default; 81 CurrentThread& operator=(const CurrentThread& other) = default; 82 83 friend bool operator==(const CurrentThread&, const CurrentThread&) = default; 84 85 // Returns a proxy object to interact with the Task related APIs for the 86 // current thread. It must only be used on the thread it was obtained. 87 static CurrentThread Get(); 88 89 // Return an empty CurrentThread. No methods should be called on this 90 // object. 91 static CurrentThread GetNull(); 92 93 // Returns true if the current thread is registered to expose CurrentThread 94 // API. Prefer this to verifying the boolean value of Get() (so that Get() can 95 // ultimately DCHECK it's only invoked when IsSet()). 96 static bool IsSet(); 97 98 // Allow CurrentThread to be used like a pointer to support the many 99 // callsites that used MessageLoop::current() that way when it was a 100 // MessageLoop*. 101 CurrentThread* operator->() { return this; } 102 explicit operator bool() const { return !!current_; } 103 104 // A DestructionObserver is notified when the current task execution 105 // environment is being destroyed. These observers are notified prior to 106 // CurrentThread::IsSet() being changed to return false. This gives interested 107 // parties the chance to do final cleanup. 108 // 109 // NOTE: Any tasks posted to the current thread during this notification will 110 // not be run. Instead, they will be deleted. 111 // 112 // Deprecation note: Prefer SequenceLocalStorageSlot<std::unique_ptr<Foo>> to 113 // DestructionObserver to bind an object's lifetime to the current 114 // thread/sequence. 115 class BASE_EXPORT DestructionObserver { 116 public: 117 // TODO(crbug.com/40596446): Rename to 118 // WillDestroyCurrentTaskExecutionEnvironment 119 virtual void WillDestroyCurrentMessageLoop() = 0; 120 121 protected: 122 virtual ~DestructionObserver() = default; 123 }; 124 125 // Add a DestructionObserver, which will start receiving notifications 126 // immediately. 127 void AddDestructionObserver(DestructionObserver* destruction_observer); 128 129 // Remove a DestructionObserver. It is safe to call this method while a 130 // DestructionObserver is receiving a notification callback. 131 void RemoveDestructionObserver(DestructionObserver* destruction_observer); 132 133 // Forwards to SequenceManager::SetTaskRunner(). 134 // DEPRECATED(https://crbug.com/825327): only owners of the SequenceManager 135 // instance should replace its TaskRunner. 136 void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner); 137 138 // Forwards to SequenceManager::(Add|Remove)TaskObserver. 139 // DEPRECATED(https://crbug.com/825327): only owners of the SequenceManager 140 // instance should add task observers on it. 141 void AddTaskObserver(TaskObserver* task_observer); 142 void RemoveTaskObserver(TaskObserver* task_observer); 143 144 // When this functionality is enabled, the queue time will be recorded for 145 // posted tasks. 146 void SetAddQueueTimeToTasks(bool enable); 147 148 // Registers a `OnceClosure` to be called on this thread the next time it goes 149 // idle. This is meant for internal usage; callers should use BEST_EFFORT 150 // tasks instead of this for generic work that needs to wait until quiescence 151 // to run. 152 class RegisterOnNextIdleCallbackPasskey { 153 private: 154 RegisterOnNextIdleCallbackPasskey() = default; 155 156 friend autofill::NextIdleBarrier; 157 friend content::BrowserMainLoop; 158 friend bool test::RunUntil(FunctionRef<bool(void)>); 159 friend void test::TestPredicateOrRegisterOnNextIdleCallback( 160 base::FunctionRef<bool(void)>, 161 CallbackListSubscription*, 162 OnceClosure); 163 }; 164 [[nodiscard]] CallbackListSubscription RegisterOnNextIdleCallback( 165 RegisterOnNextIdleCallbackPasskey, 166 OnceClosure on_next_idle_callback); 167 168 // Enables nested task processing in scope of an upcoming native message loop. 169 // Some unwanted message loops may occur when using common controls or printer 170 // functions. Hence, nested task processing is disabled by default to avoid 171 // unplanned reentrancy. This re-enables it in cases where the stack is 172 // reentrancy safe and processing nestable tasks is explicitly safe. 173 // 174 // For instance, 175 // - The current thread is running a message loop. 176 // - It receives a task #1 and executes it. 177 // - The task #1 implicitly starts a nested message loop, like a MessageBox in 178 // the unit test. This can also be StartDoc or GetSaveFileName. 179 // - The thread receives a task #2 before or while in this second message 180 // loop. 181 // - With NestableTasksAllowed set to true, the task #2 will run right away. 182 // Otherwise, it will get executed right after task #1 completes at "thread 183 // message loop level". 184 // 185 // Use RunLoop::Type::kNestableTasksAllowed when nesting is triggered by the 186 // application RunLoop rather than by native code. 187 class BASE_EXPORT ScopedAllowApplicationTasksInNativeNestedLoop { 188 public: 189 ScopedAllowApplicationTasksInNativeNestedLoop(); 190 ~ScopedAllowApplicationTasksInNativeNestedLoop(); 191 192 private: 193 const raw_ptr<sequence_manager::internal::SequenceManagerImpl> 194 sequence_manager_; 195 const bool previous_state_; 196 }; 197 198 // Returns true if nestable tasks are allowed on the current thread at this 199 // time (i.e. if a native nested loop would start from the callee's point in 200 // the stack, would it be allowed to run application tasks). 201 bool ApplicationTasksAllowedInNativeNestedLoop() const; 202 203 // Returns true if this instance is bound to the current thread. 204 bool IsBoundToCurrentThread() const; 205 206 // Returns true if the current thread is idle (ignoring delayed tasks). This 207 // is the same condition which triggers DoWork() to return false: i.e. out of 208 // tasks which can be processed at the current run-level -- there might be 209 // deferred non-nestable tasks remaining if currently in a nested run level. 210 bool IsIdleForTesting(); 211 212 // Enables ThreadControllerWithMessagePumpImpl's TimeKeeper metrics. 213 // `thread_name` will be used as a suffix. 214 // Setting `wall_time_based_metrics_enabled_for_testing` adds wall-time 215 // based metrics for this thread. This is only for test environments as it 216 // disables subsampling. 217 void EnableMessagePumpTimeKeeperMetrics( 218 const char* thread_name, 219 bool wall_time_based_metrics_enabled_for_testing = false); 220 221 // Returns the IOWatcher instance exposed by this thread, if any. 222 IOWatcher* GetIOWatcher(); 223 224 protected: CurrentThread(sequence_manager::internal::SequenceManagerImpl * sequence_manager)225 explicit CurrentThread( 226 sequence_manager::internal::SequenceManagerImpl* sequence_manager) 227 : current_(sequence_manager) {} 228 229 static sequence_manager::internal::SequenceManagerImpl* 230 GetCurrentSequenceManagerImpl(); 231 232 friend class ScheduleWorkTest; 233 friend class Thread; 234 friend class sequence_manager::internal::SequenceManagerImpl; 235 friend class MessageLoopTaskRunnerTest; 236 friend class web::WebTaskEnvironment; 237 238 raw_ptr<sequence_manager::internal::SequenceManagerImpl> current_; 239 }; 240 241 #if !BUILDFLAG(IS_NACL) 242 243 // UI extension of CurrentThread. 244 class BASE_EXPORT CurrentUIThread : public CurrentThread { 245 public: 246 // Returns an interface for the CurrentUIThread of the current thread. 247 // Asserts that IsSet(). 248 static CurrentUIThread Get(); 249 250 // Returns true if the current thread is running a CurrentUIThread. 251 static bool IsSet(); 252 253 CurrentUIThread* operator->() { return this; } 254 255 #if BUILDFLAG(IS_OZONE) && !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_WIN) 256 static_assert( 257 std::is_base_of_v<WatchableIOMessagePumpPosix, MessagePumpForUI>, 258 "CurrentThreadForUI::WatchFileDescriptor is supported only" 259 "by MessagePumpEpoll and MessagePumpGlib implementations."); 260 bool WatchFileDescriptor(int fd, 261 bool persistent, 262 MessagePumpForUI::Mode mode, 263 MessagePumpForUI::FdWatchController* controller, 264 MessagePumpForUI::FdWatcher* delegate); 265 #endif 266 267 #if BUILDFLAG(IS_IOS) 268 // Forwards to SequenceManager::Attach(). 269 // TODO(crbug.com/40568517): Plumb the actual SequenceManager* to 270 // callers and remove ability to access this method from 271 // CurrentUIThread. 272 void Attach(); 273 #endif 274 275 #if BUILDFLAG(IS_ANDROID) 276 // Forwards to MessagePumpAndroid::Abort(). 277 // TODO(crbug.com/40568517): Plumb the actual MessagePumpForUI* to 278 // callers and remove ability to access this method from 279 // CurrentUIThread. 280 void Abort(); 281 #endif 282 283 #if BUILDFLAG(IS_WIN) 284 void AddMessagePumpObserver(MessagePumpForUI::Observer* observer); 285 void RemoveMessagePumpObserver(MessagePumpForUI::Observer* observer); 286 #endif 287 288 private: CurrentUIThread(sequence_manager::internal::SequenceManagerImpl * current)289 explicit CurrentUIThread( 290 sequence_manager::internal::SequenceManagerImpl* current) 291 : CurrentThread(current) {} 292 293 MessagePumpForUI* GetMessagePumpForUI() const; 294 }; 295 296 #endif // !BUILDFLAG(IS_NACL) 297 298 // ForIO extension of CurrentThread. 299 class BASE_EXPORT CurrentIOThread : public CurrentThread { 300 public: 301 // Returns an interface for the CurrentIOThread of the current thread. 302 // Asserts that IsSet(). 303 static CurrentIOThread Get(); 304 305 // Returns true if the current thread is running a CurrentIOThread. 306 static bool IsSet(); 307 308 CurrentIOThread* operator->() { return this; } 309 310 #if !BUILDFLAG(IS_NACL) 311 312 #if BUILDFLAG(IS_WIN) 313 // Please see MessagePumpWin for definitions of these methods. 314 [[nodiscard]] bool RegisterIOHandler(HANDLE file, 315 MessagePumpForIO::IOHandler* handler); 316 bool RegisterJobObject(HANDLE job, MessagePumpForIO::IOHandler* handler); 317 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) 318 // Please see WatchableIOMessagePumpPosix for definition. 319 // Prefer base::FileDescriptorWatcher for non-critical IO. 320 bool WatchFileDescriptor(int fd, 321 bool persistent, 322 MessagePumpForIO::Mode mode, 323 MessagePumpForIO::FdWatchController* controller, 324 MessagePumpForIO::FdWatcher* delegate); 325 #endif // BUILDFLAG(IS_WIN) 326 327 #if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_IOS) && !BUILDFLAG(CRONET_BUILD)) 328 bool WatchMachReceivePort( 329 mach_port_t port, 330 MessagePumpForIO::MachPortWatchController* controller, 331 MessagePumpForIO::MachPortWatcher* delegate); 332 #endif 333 334 #if BUILDFLAG(IS_FUCHSIA) 335 // Additional watch API for native platform resources. 336 bool WatchZxHandle(zx_handle_t handle, 337 bool persistent, 338 zx_signals_t signals, 339 MessagePumpForIO::ZxHandleWatchController* controller, 340 MessagePumpForIO::ZxHandleWatcher* delegate); 341 #endif // BUILDFLAG(IS_FUCHSIA) 342 343 #endif // !BUILDFLAG(IS_NACL) 344 345 private: CurrentIOThread(sequence_manager::internal::SequenceManagerImpl * current)346 explicit CurrentIOThread( 347 sequence_manager::internal::SequenceManagerImpl* current) 348 : CurrentThread(current) {} 349 350 MessagePumpForIO* GetMessagePumpForIO() const; 351 }; 352 353 } // namespace base 354 355 #endif // BASE_TASK_CURRENT_THREAD_H_ 356