Index: base/run_loop.h |
diff --git a/base/run_loop.h b/base/run_loop.h |
index 12976fce5a38acd0adf36d64868f2db2d64d2fb4..c6471273fd2378f6366ef544ef64cbfe4f777c13 100644 |
--- a/base/run_loop.h |
+++ b/base/run_loop.h |
@@ -5,11 +5,14 @@ |
#ifndef BASE_RUN_LOOP_H_ |
#define BASE_RUN_LOOP_H_ |
+#include <stack> |
+#include <vector> |
+ |
#include "base/base_export.h" |
#include "base/callback.h" |
#include "base/macros.h" |
#include "base/memory/weak_ptr.h" |
-#include "base/message_loop/message_loop.h" |
+#include "base/observer_list.h" |
#include "base/threading/thread_checker.h" |
#include "build/build_config.h" |
@@ -22,25 +25,29 @@ class MessagePumpForUI; |
class MessagePumpUIApplication; |
#endif |
-// Helper class to Run a nested MessageLoop. Please do not use nested |
-// MessageLoops in production code! If you must, use this class instead of |
-// calling MessageLoop::Run/Quit directly. RunLoop::Run can only be called once |
+// Helper class to run the RunLoop::Delegate associated with the current thread. |
+// A RunLoop::Delegate must have been bound to this thread (ref. |
+// RunLoop::RegisterDelegateForCurrentThread()) prior to using any of RunLoop's |
+// member and static methods unless explicitly indicated otherwise (e.g. |
+// IsRunning/IsNestedOnCurrentThread()). RunLoop::Run can only be called once |
// per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run |
-// a nested MessageLoop. |
+// a nested RunLoop but please do not use nested loops in production code! |
class BASE_EXPORT RunLoop { |
public: |
RunLoop(); |
~RunLoop(); |
- // Run the current MessageLoop. This blocks until Quit is called. Before |
+ // Run the current RunLoop::Delegate. This blocks until Quit is called. Before |
// calling Run, be sure to grab the QuitClosure in order to stop the |
- // MessageLoop asynchronously. MessageLoop::QuitWhenIdle and QuitNow will also |
- // trigger a return from Run, but those are deprecated. |
+ // RunLoop::Delegate asynchronously. MessageLoop::QuitWhenIdle and QuitNow |
+ // will also trigger a return from Run (if RunLoop::Delegate happens to be a |
+ // MessageLoop...), but those are deprecated. |
void Run(); |
- // Run the current MessageLoop until it doesn't find any tasks or messages in |
- // the queue (it goes idle). WARNING: This may never return! Only use this |
- // when repeating tasks such as animated web pages have been shut down. |
+ // Run the current RunLoop::Delegate until it doesn't find any tasks or |
+ // messages in its queue (it goes idle). WARNING: This may never return! Only |
+ // use this when repeating tasks such as animated web pages have been shut |
+ // down. |
void RunUntilIdle(); |
bool running() const { |
@@ -76,16 +83,13 @@ class BASE_EXPORT RunLoop { |
base::Closure QuitClosure(); |
base::Closure QuitWhenIdleClosure(); |
- // Cleans pre-existing TLS state. |
- // TODO(gab): Remove this in favor of managing TLS through RunLoop::Delegate |
- // as part of the RunLoop<=>MessageLoop split in http://crbug.com/703346. |
- static void ResetTLSState(); |
- |
// Returns true if there is an active RunLoop on this thread. |
+ // Safe to call before RegisterDelegateForCurrentThread(). |
static bool IsRunningOnCurrentThread(); |
// Returns true if there is an active RunLoop on this thread and it's nested |
// within another active RunLoop. |
+ // Safe to call before RegisterDelegateForCurrentThread(). |
static bool IsNestedOnCurrentThread(); |
// A NestingObserver is notified when a nested run loop begins. The observers |
@@ -109,7 +113,84 @@ class BASE_EXPORT RunLoop { |
// Add/RemoveNestingObserverOnCurrentThread() on this thread will crash. |
static void DisallowNestingOnCurrentThread(); |
+ // A RunLoop::Delegate is a generic interface that allows RunLoop to be |
+ // separate from the uderlying implementation of the message loop for this |
+ // thread. It holds private state used by RunLoops on its associated thread. |
+ // One and only one RunLoop::Delegate must be registered on a given thread |
+ // via RunLoop::RegisterDelegateForCurrentThread() before RunLoop instances |
+ // and RunLoop static methods can be used on it. |
+ class BASE_EXPORT Delegate { |
+ protected: |
+ Delegate(); |
+ ~Delegate(); |
+ |
+ // The client interface provided back to the caller who registers this |
+ // Delegate via RegisterDelegateForCurrentThread. |
+ class Client { |
+ public: |
+ // Returns the RunLoop with the topmost active Run() call on the stack. |
+ // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop |
+ // further. http://crbug.com/703346 |
+ RunLoop* GetTopMostRunLoop() const; |
+ |
+ // Returns true if this |outer_| is currently in nested runs. This is a |
+ // shortcut for RunLoop::IsNestedOnCurrentThread() for the owner of this |
+ // interface. |
+ // TODO(gab): consider getting rid of this and the Client class altogether |
+ // when it's the only method left on Client. http://crbug.com/703346. |
+ bool IsNested() const; |
+ |
+ private: |
+ // Only a Delegate can instantiate a Delegate::Client. |
+ friend class Delegate; |
+ Client(Delegate* outer); |
+ |
+ Delegate* outer_; |
+ }; |
+ |
+ private: |
+ // While the state is owned by the Delegate subclass, only RunLoop can use |
+ // it. |
+ friend class RunLoop; |
+ |
+ // Used by RunLoop to inform its Delegate to Run/Quit. Implementations are |
+ // expected to keep on running synchronously from the Run() call until the |
+ // eventual matching Quit() call. Upon receiving a Quit() call it should |
+ // return from the Run() call as soon as possible without executing |
+ // remaining tasks/messages. Run() calls can nest in which case each Quit() |
+ // call should result in the topmost active Run() call returning. |
+ virtual void Run() = 0; |
+ virtual void Quit() = 0; |
+ |
+ // A vector-based stack is more memory efficient than the default |
+ // deque-based stack as the active RunLoop stack isn't expected to ever |
+ // have more than a few entries. |
+ using RunLoopStack = std::stack<RunLoop*, std::vector<RunLoop*>>; |
+ |
+ bool allow_nesting_ = true; |
+ RunLoopStack active_run_loops_; |
+ ObserverList<RunLoop::NestingObserver> nesting_observers_; |
+ |
+ // True once this Delegate is bound to a thread via |
+ // RegisterDelegateForCurrentThread(). |
+ bool bound_ = false; |
+ |
+ THREAD_CHECKER(bound_thread_checker_); |
+ |
+ Client client_interface_ = Client(this); |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Delegate); |
+ }; |
+ |
+ // Registers |delegate| on the current thread. Must be called once and only |
+ // once per thread before using RunLoop methods on it. |delegate| is from then |
+ // on forever bound to that thread (including its destruction). The returned |
+ // Delegate::Client is valid as long as |delegate| is kept alive. |
+ static Delegate::Client* RegisterDelegateForCurrentThread(Delegate* delegate); |
+ |
private: |
+ // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop |
+ // further. http://crbug.com/703346 |
friend class MessageLoop; |
#if defined(OS_ANDROID) |
// Android doesn't support the blocking MessageLoop::Run, so it calls |
@@ -127,7 +208,9 @@ class BASE_EXPORT RunLoop { |
bool BeforeRun(); |
void AfterRun(); |
- MessageLoop* loop_; |
+ // A copy of RunLoop::Delegate for this thread for quick access without using |
+ // TLS. |
+ Delegate* delegate_; |
bool run_called_ = false; |
bool quit_called_ = false; |