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 |