Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: base/run_loop.h

Issue 2880453003: Introduce RunLoop::Delegate splitting RunLoop/MessageLoop some more. (Closed)
Patch Set: oops, re-invert IsRunning logic Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/message_loop/message_loop.cc ('k') | base/run_loop.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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::RegisterDelegateForCurrentThread()) prior to using any of RunLoop's
31 // member and static methods unless explicitly indicated otherwise (e.g.
32 // IsRunning/IsNestedOnCurrentThread()). RunLoop::Run can only be called once
28 // per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run 33 // per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run
29 // a nested MessageLoop. 34 // a nested RunLoop but please do not use nested loops in production code!
30 class BASE_EXPORT RunLoop { 35 class BASE_EXPORT RunLoop {
31 public: 36 public:
32 RunLoop(); 37 RunLoop();
33 ~RunLoop(); 38 ~RunLoop();
34 39
35 // Run the current MessageLoop. This blocks until Quit is called. Before 40 // 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 41 // calling Run, be sure to grab the QuitClosure in order to stop the
37 // MessageLoop asynchronously. MessageLoop::QuitWhenIdle and QuitNow will also 42 // RunLoop::Delegate asynchronously. MessageLoop::QuitWhenIdle and QuitNow
38 // trigger a return from Run, but those are deprecated. 43 // will also trigger a return from Run (if RunLoop::Delegate happens to be a
44 // MessageLoop...), but those are deprecated.
39 void Run(); 45 void Run();
40 46
41 // Run the current MessageLoop until it doesn't find any tasks or messages in 47 // 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 48 // 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. 49 // use this when repeating tasks such as animated web pages have been shut
50 // down.
44 void RunUntilIdle(); 51 void RunUntilIdle();
45 52
46 bool running() const { 53 bool running() const {
47 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. 54 // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
48 // DCHECK(thread_checker_.CalledOnValidThread()); 55 // DCHECK(thread_checker_.CalledOnValidThread());
49 return running_; 56 return running_;
50 } 57 }
51 58
52 // Quit() quits an earlier call to Run() immediately. QuitWhenIdle() quits an 59 // 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. 60 // earlier call to Run() when there aren't any tasks or messages in the queue.
(...skipping 15 matching lines...) Expand all
69 // Convenience methods to get a closure that safely calls Quit() or 76 // Convenience methods to get a closure that safely calls Quit() or
70 // QuitWhenIdle() (has no effect if the RunLoop instance is gone). 77 // QuitWhenIdle() (has no effect if the RunLoop instance is gone).
71 // 78 //
72 // Example: 79 // Example:
73 // RunLoop run_loop; 80 // RunLoop run_loop;
74 // PostTask(run_loop.QuitClosure()); 81 // PostTask(run_loop.QuitClosure());
75 // run_loop.Run(); 82 // run_loop.Run();
76 base::Closure QuitClosure(); 83 base::Closure QuitClosure();
77 base::Closure QuitWhenIdleClosure(); 84 base::Closure QuitWhenIdleClosure();
78 85
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. 86 // Returns true if there is an active RunLoop on this thread.
87 // Safe to call before RegisterDelegateForCurrentThread().
85 static bool IsRunningOnCurrentThread(); 88 static bool IsRunningOnCurrentThread();
86 89
87 // Returns true if there is an active RunLoop on this thread and it's nested 90 // Returns true if there is an active RunLoop on this thread and it's nested
88 // within another active RunLoop. 91 // within another active RunLoop.
92 // Safe to call before RegisterDelegateForCurrentThread().
89 static bool IsNestedOnCurrentThread(); 93 static bool IsNestedOnCurrentThread();
90 94
91 // A NestingObserver is notified when a nested run loop begins. The observers 95 // A NestingObserver is notified when a nested run loop begins. The observers
92 // are notified before the current thread's RunLoop::Delegate::Run() is 96 // are notified before the current thread's RunLoop::Delegate::Run() is
93 // invoked and nested work begins. 97 // invoked and nested work begins.
94 class BASE_EXPORT NestingObserver { 98 class BASE_EXPORT NestingObserver {
95 public: 99 public:
96 virtual void OnBeginNestedRunLoop() = 0; 100 virtual void OnBeginNestedRunLoop() = 0;
97 101
98 protected: 102 protected:
99 virtual ~NestingObserver() = default; 103 virtual ~NestingObserver() = default;
100 }; 104 };
101 105
102 static void AddNestingObserverOnCurrentThread(NestingObserver* observer); 106 static void AddNestingObserverOnCurrentThread(NestingObserver* observer);
103 static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer); 107 static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer);
104 108
105 // Returns true if nesting is allowed on this thread. 109 // Returns true if nesting is allowed on this thread.
106 static bool IsNestingAllowedOnCurrentThread(); 110 static bool IsNestingAllowedOnCurrentThread();
107 111
108 // Disallow nesting. After this is called, running a nested RunLoop or calling 112 // Disallow nesting. After this is called, running a nested RunLoop or calling
109 // Add/RemoveNestingObserverOnCurrentThread() on this thread will crash. 113 // Add/RemoveNestingObserverOnCurrentThread() on this thread will crash.
110 static void DisallowNestingOnCurrentThread(); 114 static void DisallowNestingOnCurrentThread();
111 115
116 // A RunLoop::Delegate is a generic interface that allows RunLoop to be
117 // separate from the uderlying implementation of the message loop for this
118 // thread. It holds private state used by RunLoops on its associated thread.
119 // One and only one RunLoop::Delegate must be registered on a given thread
120 // via RunLoop::RegisterDelegateForCurrentThread() before RunLoop instances
121 // and RunLoop static methods can be used on it.
122 class BASE_EXPORT Delegate {
123 protected:
124 Delegate();
125 ~Delegate();
126
127 // The client interface provided back to the caller who registers this
128 // Delegate via RegisterDelegateForCurrentThread.
129 class Client {
130 public:
131 // Returns the RunLoop with the topmost active Run() call on the stack.
132 // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop
133 // further. http://crbug.com/703346
134 RunLoop* GetTopMostRunLoop() const;
135
136 // Returns true if this |outer_| is currently in nested runs. This is a
137 // shortcut for RunLoop::IsNestedOnCurrentThread() for the owner of this
138 // interface.
139 // TODO(gab): consider getting rid of this and the Client class altogether
140 // when it's the only method left on Client. http://crbug.com/703346.
141 bool IsNested() const;
142
143 private:
144 // Only a Delegate can instantiate a Delegate::Client.
145 friend class Delegate;
146 Client(Delegate* outer);
147
148 Delegate* outer_;
149 };
150
151 private:
152 // While the state is owned by the Delegate subclass, only RunLoop can use
153 // it.
154 friend class RunLoop;
155
156 // Used by RunLoop to inform its Delegate to Run/Quit. Implementations are
157 // expected to keep on running synchronously from the Run() call until the
158 // eventual matching Quit() call. Upon receiving a Quit() call it should
159 // return from the Run() call as soon as possible without executing
160 // remaining tasks/messages. Run() calls can nest in which case each Quit()
161 // call should result in the topmost active Run() call returning.
162 virtual void Run() = 0;
163 virtual void Quit() = 0;
164
165 // A vector-based stack is more memory efficient than the default
166 // deque-based stack as the active RunLoop stack isn't expected to ever
167 // have more than a few entries.
168 using RunLoopStack = std::stack<RunLoop*, std::vector<RunLoop*>>;
169
170 bool allow_nesting_ = true;
171 RunLoopStack active_run_loops_;
172 ObserverList<RunLoop::NestingObserver> nesting_observers_;
173
174 // True once this Delegate is bound to a thread via
175 // RegisterDelegateForCurrentThread().
176 bool bound_ = false;
177
178 THREAD_CHECKER(bound_thread_checker_);
179
180 Client client_interface_ = Client(this);
181
182 DISALLOW_COPY_AND_ASSIGN(Delegate);
183 };
184
185 // Registers |delegate| on the current thread. Must be called once and only
186 // once per thread before using RunLoop methods on it. |delegate| is from then
187 // on forever bound to that thread (including its destruction). The returned
188 // Delegate::Client is valid as long as |delegate| is kept alive.
189 static Delegate::Client* RegisterDelegateForCurrentThread(Delegate* delegate);
190
112 private: 191 private:
192 // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop
193 // further. http://crbug.com/703346
113 friend class MessageLoop; 194 friend class MessageLoop;
114 #if defined(OS_ANDROID) 195 #if defined(OS_ANDROID)
115 // Android doesn't support the blocking MessageLoop::Run, so it calls 196 // Android doesn't support the blocking MessageLoop::Run, so it calls
116 // BeforeRun and AfterRun directly. 197 // BeforeRun and AfterRun directly.
117 friend class base::MessagePumpForUI; 198 friend class base::MessagePumpForUI;
118 #endif 199 #endif
119 200
120 #if defined(OS_IOS) 201 #if defined(OS_IOS)
121 // iOS doesn't support the blocking MessageLoop::Run, so it calls 202 // iOS doesn't support the blocking MessageLoop::Run, so it calls
122 // BeforeRun directly. 203 // BeforeRun directly.
123 friend class base::MessagePumpUIApplication; 204 friend class base::MessagePumpUIApplication;
124 #endif 205 #endif
125 206
126 // Return false to abort the Run. 207 // Return false to abort the Run.
127 bool BeforeRun(); 208 bool BeforeRun();
128 void AfterRun(); 209 void AfterRun();
129 210
130 MessageLoop* loop_; 211 // A copy of RunLoop::Delegate for this thread for quick access without using
212 // TLS.
213 Delegate* delegate_;
131 214
132 bool run_called_ = false; 215 bool run_called_ = false;
133 bool quit_called_ = false; 216 bool quit_called_ = false;
134 bool running_ = false; 217 bool running_ = false;
135 218
136 // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning 219 // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
137 // that we should quit Run once it becomes idle. 220 // that we should quit Run once it becomes idle.
138 bool quit_when_idle_received_ = false; 221 bool quit_when_idle_received_ = false;
139 222
140 // RunLoop's non-static methods are affine to the thread it's running on per 223 // RunLoop's non-static methods are affine to the thread it's running on per
141 // this class' underlying use of thread-local-storage. 224 // this class' underlying use of thread-local-storage.
142 base::ThreadChecker thread_checker_; 225 base::ThreadChecker thread_checker_;
143 226
144 // WeakPtrFactory for QuitClosure safety. 227 // WeakPtrFactory for QuitClosure safety.
145 base::WeakPtrFactory<RunLoop> weak_factory_; 228 base::WeakPtrFactory<RunLoop> weak_factory_;
146 229
147 DISALLOW_COPY_AND_ASSIGN(RunLoop); 230 DISALLOW_COPY_AND_ASSIGN(RunLoop);
148 }; 231 };
149 232
150 } // namespace base 233 } // namespace base
151 234
152 #endif // BASE_RUN_LOOP_H_ 235 #endif // BASE_RUN_LOOP_H_
OLDNEW
« no previous file with comments | « base/message_loop/message_loop.cc ('k') | base/run_loop.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698