[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 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_ |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 7 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 8 | #include <vector> |
| 9 | |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 10 | #include "base/base_export.h" |
| 11 | #include "base/callback.h" |
Brett Wilson | 1f07f20e | 2017-10-02 18:55:28 | [diff] [blame^] | 12 | #include "base/containers/stack.h" |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 13 | #include "base/macros.h" |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 14 | #include "base/memory/ref_counted.h" |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 15 | #include "base/memory/weak_ptr.h" |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 16 | #include "base/observer_list.h" |
gab | 980a5271 | 2017-05-18 16:20:16 | [diff] [blame] | 17 | #include "base/sequence_checker.h" |
ahest | 72c1b44 | 2016-12-09 20:40:38 | [diff] [blame] | 18 | #include "base/threading/thread_checker.h" |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 19 | #include "build/build_config.h" |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 20 | |
| 21 | namespace base { |
| 22 | #if defined(OS_ANDROID) |
| 23 | class MessagePumpForUI; |
| 24 | #endif |
| 25 | |
[email protected] | feb727e | 2012-07-13 11:02:57 | [diff] [blame] | 26 | #if defined(OS_IOS) |
| 27 | class MessagePumpUIApplication; |
| 28 | #endif |
| 29 | |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 30 | class SingleThreadTaskRunner; |
| 31 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 32 | // Helper class to run the RunLoop::Delegate associated with the current thread. |
| 33 | // A RunLoop::Delegate must have been bound to this thread (ref. |
| 34 | // RunLoop::RegisterDelegateForCurrentThread()) prior to using any of RunLoop's |
| 35 | // member and static methods unless explicitly indicated otherwise (e.g. |
| 36 | // IsRunning/IsNestedOnCurrentThread()). RunLoop::Run can only be called once |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 37 | // per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 38 | // a nested RunLoop but please do not use nested loops in production code! |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 39 | class BASE_EXPORT RunLoop { |
| 40 | public: |
Gabriel Charette | 3ff403e | 2017-08-07 04:22:48 | [diff] [blame] | 41 | // The type of RunLoop: a kDefault RunLoop at the top-level (non-nested) will |
| 42 | // process system and application tasks assigned to its Delegate. When nested |
| 43 | // however a kDefault RunLoop will only process system tasks while a |
| 44 | // kNestableTasksAllowed RunLoop will continue to process application tasks |
| 45 | // even if nested. |
| 46 | // |
| 47 | // This is relevant in the case of recursive RunLoops. Some unwanted run loops |
| 48 | // may occur when using common controls or printer functions. By default, |
| 49 | // recursive task processing is disabled. |
| 50 | // |
| 51 | // In general, nestable RunLoops are to be avoided. They are dangerous and |
| 52 | // difficult to get right, so please use with extreme caution. To further |
| 53 | // protect this: kNestableTasksAllowed RunLoops are only allowed on threads |
| 54 | // where IsNestingAllowedOnCurrentThread(). |
| 55 | // |
| 56 | // A specific example where this makes a difference is: |
| 57 | // - The thread is running a RunLoop. |
| 58 | // - It receives a task #1 and executes it. |
| 59 | // - The task #1 implicitly starts a RunLoop, like a MessageBox in the unit |
| 60 | // test. This can also be StartDoc or GetSaveFileName. |
| 61 | // - The thread receives a task #2 before or while in this second RunLoop. |
| 62 | // - With a kNestableTasksAllowed RunLoop, the task #2 will run right away. |
| 63 | // Otherwise, it will get executed right after task #1 completes in the main |
| 64 | // RunLoop. |
| 65 | enum class Type { |
| 66 | kDefault, |
| 67 | kNestableTasksAllowed, |
| 68 | }; |
| 69 | |
| 70 | RunLoop(Type type = Type::kDefault); |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 71 | ~RunLoop(); |
| 72 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 73 | // Run the current RunLoop::Delegate. This blocks until Quit is called. Before |
blundell | 69c2549 | 2016-02-04 08:10:45 | [diff] [blame] | 74 | // calling Run, be sure to grab the QuitClosure in order to stop the |
Gabriel Charette | d9839bc | 2017-07-29 14:17:47 | [diff] [blame] | 75 | // RunLoop::Delegate asynchronously. |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 76 | void Run(); |
| 77 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 78 | // Run the current RunLoop::Delegate until it doesn't find any tasks or |
| 79 | // messages in its queue (it goes idle). WARNING: This may never return! Only |
| 80 | // use this when repeating tasks such as animated web pages have been shut |
| 81 | // down. |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 82 | void RunUntilIdle(); |
| 83 | |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 84 | bool running() const { |
gab | 980a5271 | 2017-05-18 16:20:16 | [diff] [blame] | 85 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 86 | return running_; |
| 87 | } |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 88 | |
fdoray | a4f28ec | 2016-06-10 00:08:58 | [diff] [blame] | 89 | // Quit() quits an earlier call to Run() immediately. QuitWhenIdle() quits an |
| 90 | // earlier call to Run() when there aren't any tasks or messages in the queue. |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 91 | // |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 92 | // These methods are thread-safe but note that Quit() is best-effort when |
| 93 | // called from another thread (will quit soon but tasks that were already |
| 94 | // queued on this RunLoop will get to run first). |
| 95 | // |
Gabriel Charette | d9839bc | 2017-07-29 14:17:47 | [diff] [blame] | 96 | // There can be other nested RunLoops servicing the same task queue. Quitting |
| 97 | // one RunLoop has no bearing on the others. Quit() and QuitWhenIdle() can be |
| 98 | // called before, during or after Run(). If called before Run(), Run() will |
| 99 | // return immediately when called. Calling Quit() or QuitWhenIdle() after the |
| 100 | // RunLoop has already finished running has no effect. |
fdoray | a4f28ec | 2016-06-10 00:08:58 | [diff] [blame] | 101 | // |
| 102 | // WARNING: You must NEVER assume that a call to Quit() or QuitWhenIdle() will |
Gabriel Charette | 3ff403e | 2017-08-07 04:22:48 | [diff] [blame] | 103 | // terminate the targetted message loop. If a nested RunLoop continues |
fdoray | a4f28ec | 2016-06-10 00:08:58 | [diff] [blame] | 104 | // running, the target may NEVER terminate. It is very easy to livelock (run |
| 105 | // forever) in such a case. |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 106 | void Quit(); |
fdoray | a4f28ec | 2016-06-10 00:08:58 | [diff] [blame] | 107 | void QuitWhenIdle(); |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 108 | |
fdoray | a365860 | 2016-06-10 18:23:15 | [diff] [blame] | 109 | // Convenience methods to get a closure that safely calls Quit() or |
| 110 | // QuitWhenIdle() (has no effect if the RunLoop instance is gone). |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 111 | // |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 112 | // The resulting Closure is thread-safe (note however that invoking the |
| 113 | // QuitClosure() from another thread than this RunLoop's will result in an |
| 114 | // asynchronous rather than immediate Quit()). |
| 115 | // |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 116 | // Example: |
| 117 | // RunLoop run_loop; |
| 118 | // PostTask(run_loop.QuitClosure()); |
| 119 | // run_loop.Run(); |
| 120 | base::Closure QuitClosure(); |
fdoray | a365860 | 2016-06-10 18:23:15 | [diff] [blame] | 121 | base::Closure QuitWhenIdleClosure(); |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 122 | |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 123 | // Returns true if there is an active RunLoop on this thread. |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 124 | // Safe to call before RegisterDelegateForCurrentThread(). |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 125 | static bool IsRunningOnCurrentThread(); |
| 126 | |
| 127 | // Returns true if there is an active RunLoop on this thread and it's nested |
| 128 | // within another active RunLoop. |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 129 | // Safe to call before RegisterDelegateForCurrentThread(). |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 130 | static bool IsNestedOnCurrentThread(); |
| 131 | |
Gabriel Charette | 3ff403e | 2017-08-07 04:22:48 | [diff] [blame] | 132 | // A NestingObserver is notified when a nested RunLoop begins. The observers |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 133 | // are notified before the current thread's RunLoop::Delegate::Run() is |
| 134 | // invoked and nested work begins. |
| 135 | class BASE_EXPORT NestingObserver { |
| 136 | public: |
| 137 | virtual void OnBeginNestedRunLoop() = 0; |
| 138 | |
| 139 | protected: |
| 140 | virtual ~NestingObserver() = default; |
| 141 | }; |
| 142 | |
| 143 | static void AddNestingObserverOnCurrentThread(NestingObserver* observer); |
| 144 | static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer); |
| 145 | |
| 146 | // Returns true if nesting is allowed on this thread. |
| 147 | static bool IsNestingAllowedOnCurrentThread(); |
| 148 | |
| 149 | // Disallow nesting. After this is called, running a nested RunLoop or calling |
| 150 | // Add/RemoveNestingObserverOnCurrentThread() on this thread will crash. |
| 151 | static void DisallowNestingOnCurrentThread(); |
| 152 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 153 | // A RunLoop::Delegate is a generic interface that allows RunLoop to be |
| 154 | // separate from the uderlying implementation of the message loop for this |
| 155 | // thread. It holds private state used by RunLoops on its associated thread. |
| 156 | // One and only one RunLoop::Delegate must be registered on a given thread |
| 157 | // via RunLoop::RegisterDelegateForCurrentThread() before RunLoop instances |
| 158 | // and RunLoop static methods can be used on it. |
| 159 | class BASE_EXPORT Delegate { |
| 160 | protected: |
| 161 | Delegate(); |
| 162 | ~Delegate(); |
| 163 | |
| 164 | // The client interface provided back to the caller who registers this |
| 165 | // Delegate via RegisterDelegateForCurrentThread. |
Gabriel Charette | e2b632b | 2017-08-02 03:52:16 | [diff] [blame] | 166 | class BASE_EXPORT Client { |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 167 | public: |
Gabriel Charette | e2b632b | 2017-08-02 03:52:16 | [diff] [blame] | 168 | // Returns true if the Delegate should return from the topmost Run() when |
| 169 | // it becomes idle. The Delegate is responsible for probing this when it |
| 170 | // becomes idle. |
| 171 | bool ShouldQuitWhenIdle() const; |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 172 | |
| 173 | // Returns true if this |outer_| is currently in nested runs. This is a |
| 174 | // shortcut for RunLoop::IsNestedOnCurrentThread() for the owner of this |
| 175 | // interface. |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 176 | bool IsNested() const; |
| 177 | |
Gabriel Charette | 3ff403e | 2017-08-07 04:22:48 | [diff] [blame] | 178 | // Returns true if the Delegate is allowed to process application tasks. |
| 179 | // This typically returns true except in nested RunLoops outside the scope |
| 180 | // of a ScopedNestableTaskAllowed as, by default, nested RunLoops are only |
| 181 | // meant to process system events. |
| 182 | bool ProcessingTasksAllowed() const; |
| 183 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 184 | private: |
| 185 | // Only a Delegate can instantiate a Delegate::Client. |
| 186 | friend class Delegate; |
| 187 | Client(Delegate* outer); |
| 188 | |
| 189 | Delegate* outer_; |
| 190 | }; |
| 191 | |
| 192 | private: |
| 193 | // While the state is owned by the Delegate subclass, only RunLoop can use |
| 194 | // it. |
| 195 | friend class RunLoop; |
| 196 | |
| 197 | // Used by RunLoop to inform its Delegate to Run/Quit. Implementations are |
| 198 | // expected to keep on running synchronously from the Run() call until the |
| 199 | // eventual matching Quit() call. Upon receiving a Quit() call it should |
| 200 | // return from the Run() call as soon as possible without executing |
| 201 | // remaining tasks/messages. Run() calls can nest in which case each Quit() |
Gabriel Charette | 3ff403e | 2017-08-07 04:22:48 | [diff] [blame] | 202 | // call should result in the topmost active Run() call returning. The only |
| 203 | // other trigger for Run() to return is Client::ShouldQuitWhenIdle() which |
| 204 | // the Delegate should probe before sleeping when it becomes idle. Run() |
| 205 | // implementations should also check Client::ProcessingTasksAllowed() before |
| 206 | // processing assigned application tasks (they should only process system |
| 207 | // tasks otherwise). |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 208 | virtual void Run() = 0; |
| 209 | virtual void Quit() = 0; |
| 210 | |
Gabriel Charette | 3ff403e | 2017-08-07 04:22:48 | [diff] [blame] | 211 | // Invoked right before a RunLoop enters a nested Run() call on this |
| 212 | // Delegate iff this RunLoop is of type kNestableTasksAllowed. The Delegate |
| 213 | // should ensure that the upcoming Run() call will result in processing |
| 214 | // application tasks queued ahead of it without further probing. e.g. |
| 215 | // message pumps on some platforms, like Mac, need an explicit request to |
| 216 | // process application tasks when nested, otherwise they'll only wait for |
| 217 | // system messages. |
| 218 | virtual void EnsureWorkScheduled() = 0; |
| 219 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 220 | // A vector-based stack is more memory efficient than the default |
| 221 | // deque-based stack as the active RunLoop stack isn't expected to ever |
| 222 | // have more than a few entries. |
Brett Wilson | 1f07f20e | 2017-10-02 18:55:28 | [diff] [blame^] | 223 | using RunLoopStack = base::stack<RunLoop*, std::vector<RunLoop*>>; |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 224 | |
| 225 | bool allow_nesting_ = true; |
| 226 | RunLoopStack active_run_loops_; |
| 227 | ObserverList<RunLoop::NestingObserver> nesting_observers_; |
| 228 | |
Gabriel Charette | a4497505 | 2017-08-21 23:14:04 | [diff] [blame] | 229 | #if DCHECK_IS_ON() |
| 230 | bool allow_running_for_testing_ = true; |
| 231 | #endif |
| 232 | |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 233 | // True once this Delegate is bound to a thread via |
| 234 | // RegisterDelegateForCurrentThread(). |
| 235 | bool bound_ = false; |
| 236 | |
gab | 980a5271 | 2017-05-18 16:20:16 | [diff] [blame] | 237 | // Thread-affine per its use of TLS. |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 238 | THREAD_CHECKER(bound_thread_checker_); |
| 239 | |
| 240 | Client client_interface_ = Client(this); |
| 241 | |
| 242 | DISALLOW_COPY_AND_ASSIGN(Delegate); |
| 243 | }; |
| 244 | |
| 245 | // Registers |delegate| on the current thread. Must be called once and only |
| 246 | // once per thread before using RunLoop methods on it. |delegate| is from then |
| 247 | // on forever bound to that thread (including its destruction). The returned |
| 248 | // Delegate::Client is valid as long as |delegate| is kept alive. |
| 249 | static Delegate::Client* RegisterDelegateForCurrentThread(Delegate* delegate); |
| 250 | |
Gabriel Charette | 0592c3a | 2017-07-26 12:02:04 | [diff] [blame] | 251 | // Quits the active RunLoop (when idle) -- there must be one. These were |
| 252 | // introduced as prefered temporary replacements to the long deprecated |
| 253 | // MessageLoop::Quit(WhenIdle) methods. Callers should properly plumb a |
| 254 | // reference to the appropriate RunLoop instance (or its QuitClosure) instead |
| 255 | // of using these in order to link Run()/Quit() to a single RunLoop instance |
| 256 | // and increase readability. |
| 257 | static void QuitCurrentDeprecated(); |
| 258 | static void QuitCurrentWhenIdleDeprecated(); |
| 259 | |
Gabriel Charette | a4497505 | 2017-08-21 23:14:04 | [diff] [blame] | 260 | // Run() will DCHECK if called while there's a ScopedDisallowRunningForTesting |
| 261 | // in scope on its thread. This is useful to add safety to some test |
| 262 | // constructs which allow multiple task runners to share the main thread in |
| 263 | // unit tests. While the main thread can be shared by multiple runners to |
| 264 | // deterministically fake multi threading, there can still only be a single |
| 265 | // RunLoop::Delegate per thread and RunLoop::Run() should only be invoked from |
| 266 | // it (or it would result in incorrectly driving TaskRunner A while in |
| 267 | // TaskRunner B's context). |
| 268 | class BASE_EXPORT ScopedDisallowRunningForTesting { |
| 269 | public: |
| 270 | ScopedDisallowRunningForTesting(); |
| 271 | ~ScopedDisallowRunningForTesting(); |
| 272 | |
| 273 | private: |
| 274 | #if DCHECK_IS_ON() |
| 275 | Delegate* current_delegate_; |
| 276 | const bool previous_run_allowance_; |
| 277 | #endif // DCHECK_IS_ON() |
| 278 | |
| 279 | DISALLOW_COPY_AND_ASSIGN(ScopedDisallowRunningForTesting); |
| 280 | }; |
| 281 | |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 282 | private: |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 283 | #if defined(OS_ANDROID) |
Gabriel Charette | e2b632b | 2017-08-02 03:52:16 | [diff] [blame] | 284 | // Android doesn't support the blocking RunLoop::Run, so it calls |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 285 | // BeforeRun and AfterRun directly. |
| 286 | friend class base::MessagePumpForUI; |
| 287 | #endif |
| 288 | |
[email protected] | feb727e | 2012-07-13 11:02:57 | [diff] [blame] | 289 | #if defined(OS_IOS) |
Gabriel Charette | e2b632b | 2017-08-02 03:52:16 | [diff] [blame] | 290 | // iOS doesn't support the blocking RunLoop::Run, so it calls |
[email protected] | feb727e | 2012-07-13 11:02:57 | [diff] [blame] | 291 | // BeforeRun directly. |
| 292 | friend class base::MessagePumpUIApplication; |
| 293 | #endif |
| 294 | |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 295 | // Return false to abort the Run. |
| 296 | bool BeforeRun(); |
| 297 | void AfterRun(); |
| 298 | |
gab | 980a5271 | 2017-05-18 16:20:16 | [diff] [blame] | 299 | // A copy of RunLoop::Delegate for the thread driven by tis RunLoop for quick |
| 300 | // access without using TLS (also allows access to state from another sequence |
| 301 | // during Run(), ref. |sequence_checker_| below). |
gab | 27355196 | 2017-05-18 06:01:10 | [diff] [blame] | 302 | Delegate* delegate_; |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 303 | |
Gabriel Charette | 3ff403e | 2017-08-07 04:22:48 | [diff] [blame] | 304 | const Type type_; |
| 305 | |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 306 | #if DCHECK_IS_ON() |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 307 | bool run_called_ = false; |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 308 | #endif |
| 309 | |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 310 | bool quit_called_ = false; |
| 311 | bool running_ = false; |
Gabriel Charette | e2b632b | 2017-08-02 03:52:16 | [diff] [blame] | 312 | // Used to record that QuitWhenIdle() was called on this RunLoop, meaning that |
| 313 | // the Delegate should quit Run() once it becomes idle (it's responsible for |
| 314 | // probing this state via Client::ShouldQuitWhenIdle()). This state is stored |
| 315 | // here rather than pushed to Delegate via, e.g., Delegate::QuitWhenIdle() to |
| 316 | // support nested RunLoops. |
gab | 7af9dc0 | 2017-05-05 13:38:54 | [diff] [blame] | 317 | bool quit_when_idle_received_ = false; |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 318 | |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 319 | // RunLoop is not thread-safe. Its state/methods, unless marked as such, may |
| 320 | // not be accessed from any other sequence than the thread it was constructed |
| 321 | // on. Exception: RunLoop can be safely accessed from one other sequence (or |
| 322 | // single parallel task) during Run() -- e.g. to Quit() without having to |
| 323 | // plumb ThreatTaskRunnerHandle::Get() throughout a test to repost QuitClosure |
| 324 | // to origin thread. |
gab | 980a5271 | 2017-05-18 16:20:16 | [diff] [blame] | 325 | SEQUENCE_CHECKER(sequence_checker_); |
ahest | 72c1b44 | 2016-12-09 20:40:38 | [diff] [blame] | 326 | |
gab | cf5e4ce | 2017-05-19 22:56:57 | [diff] [blame] | 327 | const scoped_refptr<SingleThreadTaskRunner> origin_task_runner_; |
| 328 | |
[email protected] | dcf1063 | 2013-10-08 19:23:33 | [diff] [blame] | 329 | // WeakPtrFactory for QuitClosure safety. |
| 330 | base::WeakPtrFactory<RunLoop> weak_factory_; |
| 331 | |
[email protected] | 8e937c1e | 2012-06-28 22:57:30 | [diff] [blame] | 332 | DISALLOW_COPY_AND_ASSIGN(RunLoop); |
| 333 | }; |
| 334 | |
| 335 | } // namespace base |
| 336 | |
| 337 | #endif // BASE_RUN_LOOP_H_ |