1 // Copyright 2012 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_RUN_LOOP_H_ 6 #define BASE_RUN_LOOP_H_ 7 8 #include <stack> 9 #include <utility> 10 #include <vector> 11 12 #include "base/base_export.h" 13 #include "base/containers/stack.h" 14 #include "base/dcheck_is_on.h" 15 #include "base/functional/callback.h" 16 #include "base/gtest_prod_util.h" 17 #include "base/location.h" 18 #include "base/memory/raw_ptr.h" 19 #include "base/memory/weak_ptr.h" 20 #include "base/observer_list.h" 21 #include "base/sequence_checker.h" 22 #include "base/threading/thread_checker.h" 23 #include "base/time/time.h" 24 #include "build/build_config.h" 25 26 namespace base { 27 28 namespace test { 29 class ScopedRunLoopTimeout; 30 class ScopedDisableRunLoopTimeout; 31 } // namespace test 32 33 #if BUILDFLAG(IS_ANDROID) 34 class MessagePumpAndroid; 35 #endif 36 37 #if BUILDFLAG(IS_IOS) 38 class MessagePumpUIApplication; 39 #endif 40 41 class SingleThreadTaskRunner; 42 43 // Helper class to run the RunLoop::Delegate associated with the current thread. 44 // A RunLoop::Delegate must have been bound to this thread (ref. 45 // RunLoop::RegisterDelegateForCurrentThread()) prior to using any of RunLoop's 46 // member and static methods unless explicitly indicated otherwise (e.g. 47 // IsRunning/IsNestedOnCurrentThread()). RunLoop::Run can only be called once 48 // per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run 49 // a nested RunLoop but please avoid nested loops in production code! 50 class BASE_EXPORT RunLoop { 51 public: 52 // The type of RunLoop: a kDefault RunLoop at the top-level (non-nested) will 53 // process system and application tasks assigned to its Delegate. When nested 54 // however a kDefault RunLoop will only process system tasks while a 55 // kNestableTasksAllowed RunLoop will continue to process application tasks 56 // even if nested. 57 // 58 // This is relevant in the case of recursive RunLoops. Some unwanted run loops 59 // may occur when using common controls or printer functions. By default, 60 // recursive task processing is disabled. 61 // 62 // In general, nestable RunLoops are to be avoided. They are dangerous and 63 // difficult to get right, so please use with extreme caution. 64 // 65 // A specific example where this makes a difference is: 66 // - The thread is running a RunLoop. 67 // - It receives a task #1 and executes it. 68 // - The task #1 implicitly starts a RunLoop, like a MessageBox in the unit 69 // test. This can also be StartDoc or GetSaveFileName. 70 // - The thread receives a task #2 before or while in this second RunLoop. 71 // - With a kNestableTasksAllowed RunLoop, the task #2 will run right away. 72 // Otherwise, it will get executed right after task #1 completes in the main 73 // RunLoop. 74 enum class Type { 75 kDefault, 76 kNestableTasksAllowed, 77 }; 78 79 explicit RunLoop(Type type = Type::kDefault); 80 RunLoop(const RunLoop&) = delete; 81 RunLoop& operator=(const RunLoop&) = delete; 82 ~RunLoop(); 83 84 // Run the current RunLoop::Delegate. This blocks until Quit is called 85 // (directly or by running the RunLoop::QuitClosure). 86 void Run(const Location& location = Location::Current()); 87 88 // Run the current RunLoop::Delegate until it doesn't find any tasks or 89 // messages in its queue (it goes idle). 90 // WARNING #1: This may run long (flakily timeout) and even never return! Do 91 // not use this when repeating tasks such as animated web pages 92 // are present. 93 // WARNING #2: This may return too early! For example, if used to run until an 94 // incoming event has occurred but that event depends on a task in 95 // a different queue -- e.g. another TaskRunner or a system event. 96 // Per the warnings above, this tends to lead to flaky tests; prefer 97 // QuitClosure()+Run() when at all possible. 98 void RunUntilIdle(); 99 running()100 bool running() const { 101 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 102 return running_; 103 } 104 105 // Quit() transitions this RunLoop to a state where no more tasks will be 106 // allowed to run at the run-loop-level of this RunLoop. If invoked from the 107 // owning thread, the effect is immediate; otherwise it is thread-safe but 108 // asynchronous. When the transition takes effect, the underlying message loop 109 // quits this run-loop-level if it is topmost (otherwise the desire to quit 110 // this level is saved until run-levels nested above it are quit). 111 // 112 // QuitWhenIdle() results in this RunLoop returning true from 113 // ShouldQuitWhenIdle() at this run-level (the delegate decides when "idle" is 114 // reached). This is also thread-safe. 115 // 116 // There can be other nested RunLoops servicing the same task queue. As 117 // mentioned above, quitting one RunLoop has no bearing on the others. Hence, 118 // you may never assume that a call to Quit() will terminate the underlying 119 // message loop. If a nested RunLoop continues running, the target may NEVER 120 // terminate. 121 void Quit(); 122 void QuitWhenIdle(); 123 124 // Returns a RepeatingClosure that safely calls Quit() or QuitWhenIdle() (has 125 // no effect if the RunLoop instance is gone). 126 // 127 // The closures must be obtained from the thread owning the RunLoop but may 128 // then be invoked from any thread. 129 // 130 // Returned closures may be safely: 131 // * Passed to other threads. 132 // * Run() from other threads, though this will quit the RunLoop 133 // asynchronously. 134 // * Run() after the RunLoop has stopped or been destroyed, in which case 135 // they are a no-op). 136 // * Run() before RunLoop::Run(), in which case RunLoop::Run() returns 137 // immediately." 138 // 139 // Example: 140 // RunLoop run_loop; 141 // DoFooAsyncAndNotify(run_loop.QuitClosure()); 142 // run_loop.Run(); 143 // 144 // Note that Quit() itself is thread-safe and may be invoked directly if you 145 // have access to the RunLoop reference from another thread (e.g. from a 146 // capturing lambda or test observer). 147 [[nodiscard]] RepeatingClosure QuitClosure(); 148 [[nodiscard]] RepeatingClosure QuitWhenIdleClosure(); 149 150 // Returns true if Quit() or QuitWhenIdle() was called. 151 bool AnyQuitCalled(); 152 153 // Returns true if there is an active RunLoop on this thread. 154 // Safe to call before RegisterDelegateForCurrentThread(). 155 static bool IsRunningOnCurrentThread(); 156 157 // Returns true if there is an active RunLoop on this thread and it's nested 158 // within another active RunLoop. 159 // Safe to call before RegisterDelegateForCurrentThread(). 160 static bool IsNestedOnCurrentThread(); 161 162 // A NestingObserver is notified when a nested RunLoop begins and ends. 163 class BASE_EXPORT NestingObserver { 164 public: 165 // Notified before a nested loop starts running work on the current thread. 166 virtual void OnBeginNestedRunLoop() = 0; 167 // Notified after a nested loop is done running work on the current thread. OnExitNestedRunLoop()168 virtual void OnExitNestedRunLoop() {} 169 170 protected: 171 virtual ~NestingObserver() = default; 172 }; 173 174 static void AddNestingObserverOnCurrentThread(NestingObserver* observer); 175 static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer); 176 177 // A RunLoop::Delegate is a generic interface that allows RunLoop to be 178 // separate from the underlying implementation of the message loop for this 179 // thread. It holds private state used by RunLoops on its associated thread. 180 // One and only one RunLoop::Delegate must be registered on a given thread 181 // via RunLoop::RegisterDelegateForCurrentThread() before RunLoop instances 182 // and RunLoop static methods can be used on it. 183 class BASE_EXPORT Delegate { 184 public: 185 Delegate(); 186 Delegate(const Delegate&) = delete; 187 Delegate& operator=(const Delegate&) = delete; 188 virtual ~Delegate(); 189 190 // Used by RunLoop to inform its Delegate to Run/Quit. Implementations are 191 // expected to keep on running synchronously from the Run() call until the 192 // eventual matching Quit() call or a delay of |timeout| expires. Upon 193 // receiving a Quit() call or timing out it should return from the Run() 194 // call as soon as possible without executing remaining tasks/messages. 195 // Run() calls can nest in which case each Quit() call should result in the 196 // topmost active Run() call returning. The only other trigger for Run() 197 // to return is the |should_quit_when_idle_callback_| which the Delegate 198 // should probe before sleeping when it becomes idle. 199 // |application_tasks_allowed| is true if this is the first Run() call on 200 // the stack or it was made from a nested RunLoop of 201 // Type::kNestableTasksAllowed (otherwise this Run() level should only 202 // process system tasks). 203 virtual void Run(bool application_tasks_allowed, TimeDelta timeout) = 0; 204 virtual void Quit() = 0; 205 206 // Invoked right before a RunLoop enters a nested Run() call on this 207 // Delegate iff this RunLoop is of type kNestableTasksAllowed. The Delegate 208 // should ensure that the upcoming Run() call will result in processing 209 // application tasks queued ahead of it without further probing. e.g. 210 // message pumps on some platforms, like Mac, need an explicit request to 211 // process application tasks when nested, otherwise they'll only wait for 212 // system messages. 213 virtual void EnsureWorkScheduled() = 0; 214 215 protected: 216 // Returns the result of this Delegate's |should_quit_when_idle_callback_|. 217 // "protected" so it can be invoked only by the Delegate itself. The 218 // Delegate is expected to quit Run() if this returns true. 219 bool ShouldQuitWhenIdle(); 220 221 private: 222 // While the state is owned by the Delegate subclass, only RunLoop can use 223 // it. 224 friend class RunLoop; 225 226 friend class ScopedDisallowRunningRunLoop; 227 228 // A vector-based stack is more memory efficient than the default 229 // deque-based stack as the active RunLoop stack isn't expected to ever 230 // have more than a few entries. 231 using RunLoopStack = 232 stack<raw_ptr<RunLoop, VectorExperimental>, 233 std::vector<raw_ptr<RunLoop, VectorExperimental>>>; 234 235 RunLoopStack active_run_loops_; 236 ObserverList<RunLoop::NestingObserver>::Unchecked nesting_observers_; 237 238 #if DCHECK_IS_ON() 239 bool allow_running_for_testing_ = true; 240 #endif 241 242 // True once this Delegate is bound to a thread via 243 // RegisterDelegateForCurrentThread(). 244 bool bound_ = false; 245 246 // Thread-affine per its use of TLS. 247 THREAD_CHECKER(bound_thread_checker_); 248 }; 249 250 // Registers |delegate| on the current thread. Must be called once and only 251 // once per thread before using RunLoop methods on it. |delegate| is from then 252 // on forever bound to that thread (including its destruction). 253 static void RegisterDelegateForCurrentThread(Delegate* new_delegate); 254 255 // Support for //base/test/scoped_run_loop_timeout.h. 256 // This must be public for access by the implementation code in run_loop.cc. 257 struct BASE_EXPORT RunLoopTimeout { 258 RunLoopTimeout(); 259 ~RunLoopTimeout(); 260 TimeDelta timeout; 261 RepeatingCallback<void(const Location&)> on_timeout; 262 }; 263 264 private: 265 FRIEND_TEST_ALL_PREFIXES(SingleThreadTaskExecutorTypedTest, 266 RunLoopQuitOrderAfter); 267 268 #if BUILDFLAG(IS_ANDROID) 269 // Android doesn't support the blocking RunLoop::Run, so it calls 270 // BeforeRun and AfterRun directly. 271 friend class MessagePumpAndroid; 272 #endif 273 274 #if BUILDFLAG(IS_IOS) 275 // iOS doesn't support the blocking RunLoop::Run, so it calls 276 // BeforeRun directly. 277 friend class MessagePumpUIApplication; 278 #endif 279 280 // Support for //base/test/scoped_run_loop_timeout.h. 281 friend class test::ScopedRunLoopTimeout; 282 friend class test::ScopedDisableRunLoopTimeout; 283 284 static void SetTimeoutForCurrentThread(const RunLoopTimeout* timeout); 285 static const RunLoopTimeout* GetTimeoutForCurrentThread(); 286 287 // Return false to abort the Run. 288 bool BeforeRun(); 289 void AfterRun(); 290 291 // A cached reference of RunLoop::Delegate for the thread driven by this 292 // RunLoop for quick access without using TLS (also allows access to state 293 // from another sequence during Run(), ref. |sequence_checker_| below). 294 const raw_ptr<Delegate, DanglingUntriaged> delegate_; 295 296 const Type type_; 297 298 #if DCHECK_IS_ON() 299 bool run_allowed_ = true; 300 #endif 301 302 bool quit_called_ = false; 303 bool running_ = false; 304 305 // Used to record that QuitWhenIdle() was called on this RunLoop. 306 bool quit_when_idle_called_ = false; 307 // Whether the Delegate should quit Run() once it becomes idle (it's 308 // responsible for probing this state via ShouldQuitWhenIdle()). This state is 309 // stored here rather than pushed to Delegate to support nested RunLoops. 310 bool quit_when_idle_ = false; 311 312 // RunLoop is not thread-safe. Its state/methods, unless marked as such, may 313 // not be accessed from any other sequence than the thread it was constructed 314 // on. Exception: RunLoop can be safely accessed from one other sequence (or 315 // single parallel task) during Run() -- e.g. to Quit() without having to 316 // plumb SingleThreadTaskRunner::GetCurrentDefault() throughout a test to 317 // repost QuitClosure to origin thread. 318 SEQUENCE_CHECKER(sequence_checker_); 319 320 const scoped_refptr<SingleThreadTaskRunner> origin_task_runner_; 321 322 // WeakPtrFactory for QuitClosure safety. 323 WeakPtrFactory<RunLoop> weak_factory_{this}; 324 }; 325 326 // RunLoop::Run() will DCHECK if called while there's a 327 // ScopedDisallowRunningRunLoop in scope on its thread. This is useful to add 328 // safety to some test constructs which allow multiple task runners to share the 329 // main thread in unit tests. While the main thread can be shared by multiple 330 // runners to deterministically fake multi threading, there can still only be a 331 // single RunLoop::Delegate per thread and RunLoop::Run() should only be invoked 332 // from it (or it would result in incorrectly driving TaskRunner A while in 333 // TaskRunner B's context). 334 class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowRunningRunLoop { 335 public: 336 ScopedDisallowRunningRunLoop(); 337 ScopedDisallowRunningRunLoop(const ScopedDisallowRunningRunLoop&) = delete; 338 ScopedDisallowRunningRunLoop& operator=(const ScopedDisallowRunningRunLoop&) = 339 delete; 340 ~ScopedDisallowRunningRunLoop(); 341 342 private: 343 #if DCHECK_IS_ON() 344 raw_ptr<RunLoop::Delegate> current_delegate_; 345 const bool previous_run_allowance_; 346 #endif // DCHECK_IS_ON() 347 }; 348 349 } // namespace base 350 351 #endif // BASE_RUN_LOOP_H_ 352