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