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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/message_loop/message_loop.cc ('k') | base/run_loop.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
« 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