Index: base/threading/thread.cc |
diff --git a/base/threading/thread.cc b/base/threading/thread.cc |
index ea5b1747e3836a8092517b19e8197d1cf3debb62..fd61b028d20e8f5e3dae6ade001d50615f4ae75a 100644 |
--- a/base/threading/thread.cc |
+++ b/base/threading/thread.cc |
@@ -8,6 +8,7 @@ |
#include "base/lazy_instance.h" |
#include "base/profiler/scoped_tracker.h" |
#include "base/synchronization/waitable_event.h" |
+#include "base/synchronization/waitable_event_watcher.h" |
#include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
#include "base/threading/thread_id_name_manager.h" |
#include "base/threading/thread_local.h" |
@@ -36,20 +37,6 @@ void ThreadQuitHelper() { |
Thread::SetThreadWasQuitProperly(true); |
} |
-// Used to pass data to ThreadMain. This structure is allocated on the stack |
-// from within StartWithOptions. |
-struct Thread::StartupData { |
- // We get away with a const reference here because of how we are allocated. |
- const Thread::Options& options; |
- |
- // Used to synchronize thread startup. |
- WaitableEvent event; |
- |
- explicit StartupData(const Options& opt) |
- : options(opt), |
- event(false, false) {} |
-}; |
- |
Thread::Options::Options() |
: message_loop_type(MessageLoop::TYPE_DEFAULT), |
timer_slack(TIMER_SLACK_NONE), |
@@ -74,9 +61,8 @@ Thread::Thread(const std::string& name) |
started_(false), |
stopping_(false), |
running_(false), |
- startup_data_(NULL), |
thread_(0), |
- message_loop_(NULL), |
+ message_loop_(nullptr), |
thread_id_(kInvalidThreadId), |
name_(name) { |
} |
@@ -108,32 +94,44 @@ bool Thread::StartWithOptions(const Options& options) { |
SetThreadWasQuitProperly(false); |
- StartupData startup_data(options); |
- startup_data_ = &startup_data; |
+ scoped_ptr<MessageLoop::LazyInitOptions> message_loop_options( |
DaleCurtis
2015/03/18 22:04:28
No need for a scoped_ptr allocation? Seems simple
kinuko
2015/03/19 03:08:16
Not really, but I want to keep around this object
|
+ new MessageLoop::LazyInitOptions); |
+ message_loop_options->message_loop_type = options.message_loop_type; |
+ message_loop_options->message_pump_factory = options.message_pump_factory; |
+ message_loop_options->timer_slack = options.timer_slack; |
+ message_loop_ = MessageLoop::CreateForLazyInit(message_loop_options.Pass()); |
+ |
+ start_event_.reset(new WaitableEvent(false, false)); |
if (!PlatformThread::Create(options.stack_size, this, &thread_)) { |
DLOG(ERROR) << "failed to create thread"; |
- startup_data_ = NULL; |
+ delete message_loop_; |
+ message_loop_ = NULL; |
return false; |
} |
- // TODO(eroman): Remove once crbug.com/465458 is solved. |
- tracked_objects::ScopedTracker tracking_profile_wait( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "465458 base::Thread::StartWithOptions (Wait)")); |
- |
- // Wait for the thread to start and initialize message_loop_ |
- base::ThreadRestrictions::ScopedAllowWait allow_wait; |
- startup_data.event.Wait(); |
- |
- // set it to NULL so we don't keep a pointer to some object on the stack. |
- startup_data_ = NULL; |
started_ = true; |
DCHECK(message_loop_); |
return true; |
} |
+bool Thread::StartAndWait() { |
+ bool result = Start(); |
+ if (!result) |
+ return result; |
+ WaitUntilThreadStarted(); |
+ return result; |
+} |
+ |
+bool Thread::WaitUntilThreadStarted() { |
+ if (!started_) |
+ return false; |
+ base::ThreadRestrictions::ScopedAllowWait allow_wait; |
+ start_event_->Wait(); |
+ return true; |
+} |
+ |
void Thread::Stop() { |
if (!started_) |
return; |
@@ -171,7 +169,9 @@ void Thread::StopSoon() { |
} |
bool Thread::IsRunning() const { |
- return running_; |
+ if (stopping_) |
+ return IsInRunLoop(); |
+ return started_; |
} |
void Thread::SetPriority(ThreadPriority priority) { |
@@ -199,24 +199,16 @@ bool Thread::GetThreadWasQuitProperly() { |
void Thread::ThreadMain() { |
{ |
- // The message loop for this thread. |
- // Allocated on the heap to centralize any leak reports at this line. |
- scoped_ptr<MessageLoop> message_loop; |
- if (!startup_data_->options.message_pump_factory.is_null()) { |
- message_loop.reset( |
- new MessageLoop(startup_data_->options.message_pump_factory.Run())); |
- } else { |
- message_loop.reset( |
- new MessageLoop(startup_data_->options.message_loop_type)); |
- } |
- |
// Complete the initialization of our Thread object. |
thread_id_ = PlatformThread::CurrentId(); |
PlatformThread::SetName(name_.c_str()); |
ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. |
- message_loop->set_thread_name(name_); |
- message_loop->SetTimerSlack(startup_data_->options.timer_slack); |
- message_loop_ = message_loop.get(); |
+ |
+ // Lazily initialize the message_loop so that it can run on this thread. |
+ DCHECK(message_loop_); |
+ scoped_ptr<MessageLoop> message_loop(message_loop_); |
+ message_loop_->set_thread_name(name_); |
+ message_loop_->LazyInit(); |
#if defined(OS_WIN) |
scoped_ptr<win::ScopedCOMInitializer> com_initializer; |
@@ -228,16 +220,21 @@ void Thread::ThreadMain() { |
#endif |
// Let the thread do extra initialization. |
- // Let's do this before signaling we are started. |
Init(); |
- running_ = true; |
- startup_data_->event.Signal(); |
- // startup_data_ can't be touched anymore since the starting thread is now |
- // unlocked. |
+ { |
DaleCurtis
2015/03/18 22:04:28
You can combine running_ and start_event_ into a r
kinuko
2015/03/19 03:08:16
Sounds like a good idea, done.
kinuko
2015/03/20 08:44:22
Hmm, replacing running_ with event_->IsSignaled()
|
+ base::AutoLock lock(running_lock_); |
+ running_ = true; |
+ } |
+ |
+ start_event_->Signal(); |
Run(message_loop_); |
- running_ = false; |
+ |
+ { |
+ base::AutoLock lock(running_lock_); |
+ running_ = false; |
+ } |
// Let the thread do extra cleanup. |
CleanUp(); |
@@ -254,4 +251,9 @@ void Thread::ThreadMain() { |
} |
} |
+bool Thread::IsInRunLoop() const { |
+ base::AutoLock lock(running_lock_); |
+ return running_; |
+} |
+ |
} // namespace base |