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

Side by Side Diff: base/run_loop.h

Issue 2880453003: Introduce RunLoop::Delegate splitting RunLoop/MessageLoop some more. (Closed)
Patch Set: 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
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::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
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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698