Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef BASE_RUN_LOOP_H_ | 5 #ifndef BASE_RUN_LOOP_H_ |
| 6 #define BASE_RUN_LOOP_H_ | 6 #define BASE_RUN_LOOP_H_ |
| 7 | 7 |
| 8 #include <stack> | |
| 9 #include <vector> | |
| 10 | |
| 8 #include "base/base_export.h" | 11 #include "base/base_export.h" |
| 9 #include "base/callback.h" | 12 #include "base/callback.h" |
| 10 #include "base/macros.h" | 13 #include "base/macros.h" |
| 11 #include "base/memory/weak_ptr.h" | 14 #include "base/memory/weak_ptr.h" |
| 12 #include "base/message_loop/message_loop.h" | 15 #include "base/observer_list.h" |
| 13 #include "base/threading/thread_checker.h" | 16 #include "base/threading/thread_checker.h" |
| 14 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 15 | 18 |
| 16 namespace base { | 19 namespace base { |
| 17 #if defined(OS_ANDROID) | 20 #if defined(OS_ANDROID) |
| 18 class MessagePumpForUI; | 21 class MessagePumpForUI; |
| 19 #endif | 22 #endif |
| 20 | 23 |
| 21 #if defined(OS_IOS) | 24 #if defined(OS_IOS) |
| 22 class MessagePumpUIApplication; | 25 class MessagePumpUIApplication; |
| 23 #endif | 26 #endif |
| 24 | 27 |
| 25 // Helper class to Run a nested MessageLoop. Please do not use nested | 28 // Helper class to run the RunLoop::Delegate associated with the current thread. |
| 26 // MessageLoops in production code! If you must, use this class instead of | 29 // A RunLoop::Delegate must have been bound to this thread (ref. |
| 27 // calling MessageLoop::Run/Quit directly. RunLoop::Run can only be called once | 30 // RunLoop::Delegate::BindToCurrentThread()) prior to using any of RunLoop's |
| 28 // per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run | 31 // member and static methods. RunLoop::Run can only be called once per RunLoop |
| 29 // a nested MessageLoop. | 32 // lifetime. Create a RunLoop on the stack and call Run/Quit to run a nested |
| 33 // RunLoop but please do not use nested loops in production code! | |
| 30 class BASE_EXPORT RunLoop { | 34 class BASE_EXPORT RunLoop { |
| 31 public: | 35 public: |
| 32 RunLoop(); | 36 RunLoop(); |
| 33 ~RunLoop(); | 37 ~RunLoop(); |
| 34 | 38 |
| 35 // Run the current MessageLoop. This blocks until Quit is called. Before | 39 // Run the current RunLoop::Delegate. This blocks until Quit is called. Before |
| 36 // calling Run, be sure to grab the QuitClosure in order to stop the | 40 // calling Run, be sure to grab the QuitClosure in order to stop the |
| 37 // MessageLoop asynchronously. MessageLoop::QuitWhenIdle and QuitNow will also | 41 // RunLoop::Delegate asynchronously. MessageLoop::QuitWhenIdle and QuitNow |
| 38 // trigger a return from Run, but those are deprecated. | 42 // will also trigger a return from Run (if RunLoop::Delegate happens to be a |
| 43 // MessageLoop...), but those are deprecated. | |
| 39 void Run(); | 44 void Run(); |
| 40 | 45 |
| 41 // Run the current MessageLoop until it doesn't find any tasks or messages in | 46 // Run the current RunLoop::Delegate until it doesn't find any tasks or |
| 42 // the queue (it goes idle). WARNING: This may never return! Only use this | 47 // messages in its queue (it goes idle). WARNING: This may never return! Only |
| 43 // when repeating tasks such as animated web pages have been shut down. | 48 // use this when repeating tasks such as animated web pages have been shut |
| 49 // down. | |
| 44 void RunUntilIdle(); | 50 void RunUntilIdle(); |
| 45 | 51 |
| 46 bool running() const { | 52 bool running() const { |
| 47 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. | 53 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
| 48 // DCHECK(thread_checker_.CalledOnValidThread()); | 54 // DCHECK(thread_checker_.CalledOnValidThread()); |
| 49 return running_; | 55 return running_; |
| 50 } | 56 } |
| 51 | 57 |
| 52 // Quit() quits an earlier call to Run() immediately. QuitWhenIdle() quits an | 58 // Quit() quits an earlier call to Run() immediately. QuitWhenIdle() quits an |
| 53 // earlier call to Run() when there aren't any tasks or messages in the queue. | 59 // earlier call to Run() when there aren't any tasks or messages in the queue. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 69 // Convenience methods to get a closure that safely calls Quit() or | 75 // Convenience methods to get a closure that safely calls Quit() or |
| 70 // QuitWhenIdle() (has no effect if the RunLoop instance is gone). | 76 // QuitWhenIdle() (has no effect if the RunLoop instance is gone). |
| 71 // | 77 // |
| 72 // Example: | 78 // Example: |
| 73 // RunLoop run_loop; | 79 // RunLoop run_loop; |
| 74 // PostTask(run_loop.QuitClosure()); | 80 // PostTask(run_loop.QuitClosure()); |
| 75 // run_loop.Run(); | 81 // run_loop.Run(); |
| 76 base::Closure QuitClosure(); | 82 base::Closure QuitClosure(); |
| 77 base::Closure QuitWhenIdleClosure(); | 83 base::Closure QuitWhenIdleClosure(); |
| 78 | 84 |
| 79 // Cleans pre-existing TLS state. | |
| 80 // TODO(gab): Remove this in favor of managing TLS through RunLoop::Delegate | |
| 81 // as part of the RunLoop<=>MessageLoop split in http://crbug.com/703346. | |
| 82 static void ResetTLSState(); | |
| 83 | |
| 84 // Returns true if there is an active RunLoop on this thread. | 85 // Returns true if there is an active RunLoop on this thread. |
| 85 static bool IsRunningOnCurrentThread(); | 86 static bool IsRunningOnCurrentThread(); |
| 86 | 87 |
| 87 // Returns true if there is an active RunLoop on this thread and it's nested | 88 // Returns true if there is an active RunLoop on this thread and it's nested |
| 88 // within another active RunLoop. | 89 // within another active RunLoop. |
| 89 static bool IsNestedOnCurrentThread(); | 90 static bool IsNestedOnCurrentThread(); |
| 90 | 91 |
| 91 // A NestingObserver is notified when a nested run loop begins. The observers | 92 // A NestingObserver is notified when a nested run loop begins. The observers |
| 92 // are notified before the current thread's RunLoop::Delegate::Run() is | 93 // are notified before the current thread's RunLoop::Delegate::Run() is |
| 93 // invoked and nested work begins. | 94 // invoked and nested work begins. |
| 94 class BASE_EXPORT NestingObserver { | 95 class BASE_EXPORT NestingObserver { |
| 95 public: | 96 public: |
| 96 virtual void OnBeginNestedRunLoop() = 0; | 97 virtual void OnBeginNestedRunLoop() = 0; |
| 97 | 98 |
| 98 protected: | 99 protected: |
| 99 virtual ~NestingObserver() = default; | 100 virtual ~NestingObserver() = default; |
| 100 }; | 101 }; |
| 101 | 102 |
| 102 static void AddNestingObserverOnCurrentThread(NestingObserver* observer); | 103 static void AddNestingObserverOnCurrentThread(NestingObserver* observer); |
| 103 static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer); | 104 static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer); |
| 104 | 105 |
| 105 // Returns true if nesting is allowed on this thread. | 106 // Returns true if nesting is allowed on this thread. |
| 106 static bool IsNestingAllowedOnCurrentThread(); | 107 static bool IsNestingAllowedOnCurrentThread(); |
| 107 | 108 |
| 108 // Disallow nesting. After this is called, running a nested RunLoop or calling | 109 // Disallow nesting. After this is called, running a nested RunLoop or calling |
| 109 // Add/RemoveNestingObserverOnCurrentThread() on this thread will crash. | 110 // Add/RemoveNestingObserverOnCurrentThread() on this thread will crash. |
| 110 static void DisallowNestingOnCurrentThread(); | 111 static void DisallowNestingOnCurrentThread(); |
| 111 | 112 |
| 113 // A RunLoop::Delegate is a generic interface that allows RunLoop to be | |
| 114 // separate from the uderlying implementation of the message loop for this | |
| 115 // thread, it has two functions: | |
| 116 // 1) it implements a private API used by RunLoop to ask the Delegate to | |
| 117 // run/quit. | |
| 118 // 2) it holds thread-local state used by every RunLoop on its associated | |
| 119 // thread. The advantage of having that state stored on the Delegate | |
| 120 // itself instead of in a TLS slot in run_loop.cc is that it guarantees | |
| 121 // it's cleaned up when the RunLoop::Delegate is destroyed (required in | |
| 122 // unittests). | |
| 123 class BASE_EXPORT Delegate { | |
|
danakj
2017/05/15 16:23:13
While its less # of classes to do this, this Deleg
gab
2017/05/15 17:28:35
Hmmm, I don't see how this would work, what is Mes
| |
| 124 protected: | |
| 125 Delegate(); | |
| 126 ~Delegate(); | |
| 127 | |
| 128 // Returns the RunLoop with the topmost active Run() call on the stack. | |
| 129 // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop | |
| 130 // further. http://crbug.com/703346 | |
| 131 RunLoop* GetTopMostRunLoop() const; | |
| 132 | |
| 133 // Returns true if this Delegate is currently in nested runs. | |
| 134 // Code that needs to query RunLoop::IsNestedOnCurrentThread() frequently | |
| 135 // may want to consider storing RunLoop::Delegate::current() in a variable | |
| 136 // and accessing the value through this method instead. | |
| 137 bool IsNested() const; | |
| 138 | |
| 139 // Binds this Delegate to the current thread. After this point, RunLoops may | |
| 140 // be instantiated on this thread and they will be associated to this | |
| 141 // Delegate. It will bound unbound in its destructor (which must occur on | |
| 142 // the same thread this call was made). | |
| 143 virtual void BindToCurrentThread(); | |
| 144 | |
| 145 private: | |
| 146 friend class RunLoop; | |
|
danakj
2017/05/15 16:23:13
This isn't needed since the class is nested right?
gab
2017/05/15 17:28:35
In Java you're right I think but in C++ it's requi
| |
| 147 | |
| 148 // Used by RunLoop to inform its Delegate to Run/Quit. Implementations are | |
| 149 // expected to keep on running synchronously from the Run() call until the | |
| 150 // eventual matching Quit() call. Upon receiving a Quit() call it should | |
| 151 // return from the Run() call as soon as possible without executing | |
| 152 // remaining tasks/messages. Run() calls can nest in which case each Quit() | |
| 153 // call should result in the topmost active Run() call returning. | |
| 154 virtual void Run() = 0; | |
| 155 virtual void Quit() = 0; | |
| 156 | |
| 157 // A vector-based stack is more memory efficient than the default deque- | |
| 158 // based stack as the active RunLoop stack isn't expected to ever have more | |
| 159 // than a few entries. | |
| 160 using RunLoopStack = std::stack<RunLoop*, std::vector<RunLoop*>>; | |
| 161 | |
| 162 bool allow_nesting_ = true; | |
| 163 RunLoopStack active_run_loops_; | |
| 164 ObserverList<RunLoop::NestingObserver> nesting_observers_; | |
| 165 | |
| 166 bool bound_ = false; | |
| 167 | |
| 168 THREAD_CHECKER(bound_thread_checker_); | |
| 169 | |
| 170 DISALLOW_COPY_AND_ASSIGN(Delegate); | |
| 171 }; | |
| 172 | |
| 112 private: | 173 private: |
| 174 // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop | |
| 175 // further. http://crbug.com/703346 | |
| 113 friend class MessageLoop; | 176 friend class MessageLoop; |
| 114 #if defined(OS_ANDROID) | 177 #if defined(OS_ANDROID) |
| 115 // Android doesn't support the blocking MessageLoop::Run, so it calls | 178 // Android doesn't support the blocking MessageLoop::Run, so it calls |
| 116 // BeforeRun and AfterRun directly. | 179 // BeforeRun and AfterRun directly. |
| 117 friend class base::MessagePumpForUI; | 180 friend class base::MessagePumpForUI; |
| 118 #endif | 181 #endif |
| 119 | 182 |
| 120 #if defined(OS_IOS) | 183 #if defined(OS_IOS) |
| 121 // iOS doesn't support the blocking MessageLoop::Run, so it calls | 184 // iOS doesn't support the blocking MessageLoop::Run, so it calls |
| 122 // BeforeRun directly. | 185 // BeforeRun directly. |
| 123 friend class base::MessagePumpUIApplication; | 186 friend class base::MessagePumpUIApplication; |
| 124 #endif | 187 #endif |
| 125 | 188 |
| 126 // Return false to abort the Run. | 189 // Return false to abort the Run. |
| 127 bool BeforeRun(); | 190 bool BeforeRun(); |
| 128 void AfterRun(); | 191 void AfterRun(); |
| 129 | 192 |
| 130 MessageLoop* loop_; | 193 // A copy of RunLoop::Delegate for this thread for quick access without using |
| 194 // TLS. | |
| 195 Delegate* delegate_; | |
| 131 | 196 |
| 132 bool run_called_ = false; | 197 bool run_called_ = false; |
| 133 bool quit_called_ = false; | 198 bool quit_called_ = false; |
| 134 bool running_ = false; | 199 bool running_ = false; |
| 135 | 200 |
| 136 // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning | 201 // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning |
| 137 // that we should quit Run once it becomes idle. | 202 // that we should quit Run once it becomes idle. |
| 138 bool quit_when_idle_received_ = false; | 203 bool quit_when_idle_received_ = false; |
| 139 | 204 |
| 140 // RunLoop's non-static methods are affine to the thread it's running on per | 205 // RunLoop's non-static methods are affine to the thread it's running on per |
| 141 // this class' underlying use of thread-local-storage. | 206 // this class' underlying use of thread-local-storage. |
| 142 base::ThreadChecker thread_checker_; | 207 base::ThreadChecker thread_checker_; |
| 143 | 208 |
| 144 // WeakPtrFactory for QuitClosure safety. | 209 // WeakPtrFactory for QuitClosure safety. |
| 145 base::WeakPtrFactory<RunLoop> weak_factory_; | 210 base::WeakPtrFactory<RunLoop> weak_factory_; |
| 146 | 211 |
| 147 DISALLOW_COPY_AND_ASSIGN(RunLoop); | 212 DISALLOW_COPY_AND_ASSIGN(RunLoop); |
| 148 }; | 213 }; |
| 149 | 214 |
| 150 } // namespace base | 215 } // namespace base |
| 151 | 216 |
| 152 #endif // BASE_RUN_LOOP_H_ | 217 #endif // BASE_RUN_LOOP_H_ |
| OLD | NEW |