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

Side by Side Diff: base/run_loop.h

Issue 2892993002: Make RunLoop::Quit() thread-safe. (Closed)
Patch Set: add tests that call Quit(WhenIdle) directly, without the Quit(WhenIdle)Closure 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 | « no previous file | 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> 8 #include <stack>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/base_export.h" 11 #include "base/base_export.h"
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
14 #include "base/memory/weak_ptr.h" 15 #include "base/memory/weak_ptr.h"
15 #include "base/observer_list.h" 16 #include "base/observer_list.h"
16 #include "base/sequence_checker.h" 17 #include "base/sequence_checker.h"
17 #include "base/threading/thread_checker.h" 18 #include "base/threading/thread_checker.h"
18 #include "build/build_config.h" 19 #include "build/build_config.h"
19 20
20 namespace base { 21 namespace base {
21 #if defined(OS_ANDROID) 22 #if defined(OS_ANDROID)
22 class MessagePumpForUI; 23 class MessagePumpForUI;
23 #endif 24 #endif
24 25
25 #if defined(OS_IOS) 26 #if defined(OS_IOS)
26 class MessagePumpUIApplication; 27 class MessagePumpUIApplication;
27 #endif 28 #endif
28 29
30 class SingleThreadTaskRunner;
31
29 // Helper class to run the RunLoop::Delegate associated with the current thread. 32 // Helper class to run the RunLoop::Delegate associated with the current thread.
30 // A RunLoop::Delegate must have been bound to this thread (ref. 33 // A RunLoop::Delegate must have been bound to this thread (ref.
31 // RunLoop::RegisterDelegateForCurrentThread()) prior to using any of RunLoop's 34 // RunLoop::RegisterDelegateForCurrentThread()) prior to using any of RunLoop's
32 // member and static methods unless explicitly indicated otherwise (e.g. 35 // member and static methods unless explicitly indicated otherwise (e.g.
33 // IsRunning/IsNestedOnCurrentThread()). RunLoop::Run can only be called once 36 // IsRunning/IsNestedOnCurrentThread()). RunLoop::Run can only be called once
34 // per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run 37 // per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run
35 // a nested RunLoop but please do not use nested loops in production code! 38 // a nested RunLoop but please do not use nested loops in production code!
36 class BASE_EXPORT RunLoop { 39 class BASE_EXPORT RunLoop {
37 public: 40 public:
38 RunLoop(); 41 RunLoop();
(...skipping 13 matching lines...) Expand all
52 void RunUntilIdle(); 55 void RunUntilIdle();
53 56
54 bool running() const { 57 bool running() const {
55 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 58 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
56 return running_; 59 return running_;
57 } 60 }
58 61
59 // Quit() quits an earlier call to Run() immediately. QuitWhenIdle() quits an 62 // Quit() quits an earlier call to Run() immediately. QuitWhenIdle() quits an
60 // earlier call to Run() when there aren't any tasks or messages in the queue. 63 // earlier call to Run() when there aren't any tasks or messages in the queue.
61 // 64 //
65 // These methods are thread-safe but note that Quit() is best-effort when
66 // called from another thread (will quit soon but tasks that were already
67 // queued on this RunLoop will get to run first).
68 //
62 // There can be other nested RunLoops servicing the same task queue 69 // There can be other nested RunLoops servicing the same task queue
63 // (MessageLoop); Quitting one RunLoop has no bearing on the others. Quit() 70 // (MessageLoop); Quitting one RunLoop has no bearing on the others. Quit()
64 // and QuitWhenIdle() can be called before, during or after Run(). If called 71 // and QuitWhenIdle() can be called before, during or after Run(). If called
65 // before Run(), Run() will return immediately when called. Calling Quit() or 72 // before Run(), Run() will return immediately when called. Calling Quit() or
66 // QuitWhenIdle() after the RunLoop has already finished running has no 73 // QuitWhenIdle() after the RunLoop has already finished running has no
67 // effect. 74 // effect.
68 // 75 //
69 // WARNING: You must NEVER assume that a call to Quit() or QuitWhenIdle() will 76 // WARNING: You must NEVER assume that a call to Quit() or QuitWhenIdle() will
70 // terminate the targetted message loop. If a nested run loop continues 77 // terminate the targetted message loop. If a nested run loop continues
71 // running, the target may NEVER terminate. It is very easy to livelock (run 78 // running, the target may NEVER terminate. It is very easy to livelock (run
72 // forever) in such a case. 79 // forever) in such a case.
73 void Quit(); 80 void Quit();
74 void QuitWhenIdle(); 81 void QuitWhenIdle();
75 82
76 // Convenience methods to get a closure that safely calls Quit() or 83 // Convenience methods to get a closure that safely calls Quit() or
77 // QuitWhenIdle() (has no effect if the RunLoop instance is gone). 84 // QuitWhenIdle() (has no effect if the RunLoop instance is gone).
78 // 85 //
86 // The resulting Closure is thread-safe (note however that invoking the
87 // QuitClosure() from another thread than this RunLoop's will result in an
88 // asynchronous rather than immediate Quit()).
89 //
79 // Example: 90 // Example:
80 // RunLoop run_loop; 91 // RunLoop run_loop;
81 // PostTask(run_loop.QuitClosure()); 92 // PostTask(run_loop.QuitClosure());
82 // run_loop.Run(); 93 // run_loop.Run();
83 base::Closure QuitClosure(); 94 base::Closure QuitClosure();
84 base::Closure QuitWhenIdleClosure(); 95 base::Closure QuitWhenIdleClosure();
85 96
86 // Returns true if there is an active RunLoop on this thread. 97 // Returns true if there is an active RunLoop on this thread.
87 // Safe to call before RegisterDelegateForCurrentThread(). 98 // Safe to call before RegisterDelegateForCurrentThread().
88 static bool IsRunningOnCurrentThread(); 99 static bool IsRunningOnCurrentThread();
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 218
208 // Return false to abort the Run. 219 // Return false to abort the Run.
209 bool BeforeRun(); 220 bool BeforeRun();
210 void AfterRun(); 221 void AfterRun();
211 222
212 // A copy of RunLoop::Delegate for the thread driven by tis RunLoop for quick 223 // A copy of RunLoop::Delegate for the thread driven by tis RunLoop for quick
213 // access without using TLS (also allows access to state from another sequence 224 // access without using TLS (also allows access to state from another sequence
214 // during Run(), ref. |sequence_checker_| below). 225 // during Run(), ref. |sequence_checker_| below).
215 Delegate* delegate_; 226 Delegate* delegate_;
216 227
228 #if DCHECK_IS_ON()
217 bool run_called_ = false; 229 bool run_called_ = false;
230 #endif
231
218 bool quit_called_ = false; 232 bool quit_called_ = false;
219 bool running_ = false; 233 bool running_ = false;
220
221 // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning 234 // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
222 // that we should quit Run once it becomes idle. 235 // that we should quit Run once it becomes idle.
223 bool quit_when_idle_received_ = false; 236 bool quit_when_idle_received_ = false;
224 237
225 // RunLoop is not thread-safe. Its state may not be accessed from any other 238 // RunLoop is not thread-safe. Its state/methods, unless marked as such, may
226 // sequence than the thread it was constructed on. Exception: RunLoop can be 239 // not be accessed from any other sequence than the thread it was constructed
227 // safely accessed from one other sequence (or single parallel task) during 240 // on. Exception: RunLoop can be safely accessed from one other sequence (or
228 // Run(). 241 // single parallel task) during Run() -- e.g. to Quit() without having to
242 // plumb ThreatTaskRunnerHandle::Get() throughout a test to repost QuitClosure
243 // to origin thread.
229 SEQUENCE_CHECKER(sequence_checker_); 244 SEQUENCE_CHECKER(sequence_checker_);
230 245
246 const scoped_refptr<SingleThreadTaskRunner> origin_task_runner_;
247
231 // WeakPtrFactory for QuitClosure safety. 248 // WeakPtrFactory for QuitClosure safety.
232 base::WeakPtrFactory<RunLoop> weak_factory_; 249 base::WeakPtrFactory<RunLoop> weak_factory_;
233 250
234 DISALLOW_COPY_AND_ASSIGN(RunLoop); 251 DISALLOW_COPY_AND_ASSIGN(RunLoop);
235 }; 252 };
236 253
237 } // namespace base 254 } // namespace base
238 255
239 #endif // BASE_RUN_LOOP_H_ 256 #endif // BASE_RUN_LOOP_H_
OLDNEW
« no previous file with comments | « no previous file | base/run_loop.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698