Reland (3rd try): Lazily initialize MessageLoop for faster thread startup
Original review: https://codereview.chromium.org/1011683002/
2nd try: https://codereview.chromium.org/1129953004/
2nd try reverted due to race reports on Linux:
https://crbug.com/489263 Data races on valid_thread_id_ after r330329
This fixes:
- Race in MessageLoopProxyImpl by introducing lock
- Race in BrowserMainLoop/BrowserThreadImpl, where BrowserThread::CurrentlyOn()
called on one of BrowserThreads tries to touch other thread's message_loop()
via global thread table.
Reg: the latter race, the code flow that causes this race is like following:
// On the main thread, we create all known browser threads:
for (...) {
{
AutoLock lock(g_lock);
g_threads[id] = new BrowserProcessSubThread();
}
// [A] This initializes the thread's message_loop, which causes a race
// against [B] in the new code because new threads can start running
// immediately.
thread->StartWithOptions();
}
// On the new thread's main function, it calls CurrentlyOn() which does:
{
// [B] This touches other thread's Thread::message_loop.
AutoLock lock(g_lock);
return g_threads[other_thread_id] &&
g_threads[other_thread_id]->message_loop() == MessageLoop::current();
}
This was safe before because both message_loop initialization and the first
call to CurrentlyOn() on the new thread was done synchronously in
StartWithOptions() while the main thread was blocked. In the new code
new threads can start accessing message_loop() asynchronously while
the main thread's for loop is running.
PS1 is the original patch (2nd try) that got reverted.
BUG=465458, 489263
Review URL: https://codereview.chromium.org/1131513007
Cr-Commit-Position: refs/heads/master@{#331235}
CrOS-Libchrome-Original-Commit: 7f68f8735355c1c73557c3cfb294b441901fc31d
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index fd7596a..f2f89d0 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -114,7 +114,8 @@
explicit MessageLoop(Type type = TYPE_DEFAULT);
// Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must
// be non-NULL.
- explicit MessageLoop(scoped_ptr<base::MessagePump> pump);
+ explicit MessageLoop(scoped_ptr<MessagePump> pump);
+
~MessageLoop() override;
// Returns the MessageLoop object for the current thread, or null if none.
@@ -394,10 +395,6 @@
// Returns true if the message loop is "idle". Provided for testing.
bool IsIdleForTesting();
- // Wakes up the message pump. Can be called on any thread. The caller is
- // responsible for synchronizing ScheduleWork() calls.
- void ScheduleWork();
-
// Returns the TaskAnnotator which is used to add debug information to posted
// tasks.
debug::TaskAnnotator* task_annotator() { return &task_annotator_; }
@@ -411,9 +408,33 @@
private:
friend class RunLoop;
+ friend class internal::IncomingTaskQueue;
+ friend class ScheduleWorkTest;
+ friend class Thread;
- // Configures various members for the two constructors.
- void Init();
+ using MessagePumpFactoryCallback = Callback<scoped_ptr<MessagePump>()>;
+
+ // Creates a MessageLoop without binding to a thread.
+ // If |type| is TYPE_CUSTOM non-null |pump_factory| must be also given
+ // to create a message pump for this message loop. Otherwise a default
+ // message pump for the |type| is created.
+ //
+ // It is valid to call this to create a new message loop on one thread,
+ // and then pass it to the thread where the message loop actually runs.
+ // The message loop's BindToCurrentThread() method must be called on the
+ // thread the message loop runs on, before calling Run().
+ // Before BindToCurrentThread() is called only Post*Task() functions can
+ // be called on the message loop.
+ scoped_ptr<MessageLoop> CreateUnbound(
+ Type type,
+ MessagePumpFactoryCallback pump_factory);
+
+ // Common private constructor. Other constructors delegate the initialization
+ // to this constructor.
+ MessageLoop(Type type, MessagePumpFactoryCallback pump_factory);
+
+ // Configure various members and bind this message loop to the current thread.
+ void BindToCurrentThread();
// Invokes the actual run loop using the message pump.
void RunHandler();
@@ -437,6 +458,10 @@
// empty.
void ReloadWorkQueue();
+ // Wakes up the message pump. Can be called on any thread. The caller is
+ // responsible for synchronizing ScheduleWork() calls.
+ void ScheduleWork();
+
// Start recording histogram info about events and action IF it was enabled
// and IF the statistics recorder can accept a registration of our histogram.
void StartHistogrammer();
@@ -490,6 +515,10 @@
bool os_modal_loop_;
#endif
+ // pump_factory_.Run() is called to create a message pump for this loop
+ // if type_ is TYPE_CUSTOM and pump_ is null.
+ MessagePumpFactoryCallback pump_factory_;
+
std::string thread_name_;
// A profiling histogram showing the counts of various messages and events.
HistogramBase* message_histogram_;