diff options
| author | glider <glider@chromium.org> | 2015-05-18 06:24:19 -0700 | 
|---|---|---|
| committer | Commit bot <commit-bot@chromium.org> | 2015-05-18 13:24:21 +0000 | 
| commit | 787e3347eb49a59db5e6fe0374f50464f36d48e3 (patch) | |
| tree | 65004507e5713d6f9c8e275b8829b61c86715da0 | |
| parent | cfdf46013b37da38c878632b87fa24f1b7997f3d (diff) | |
| download | chromium_src-787e3347eb49a59db5e6fe0374f50464f36d48e3.zip chromium_src-787e3347eb49a59db5e6fe0374f50464f36d48e3.tar.gz chromium_src-787e3347eb49a59db5e6fe0374f50464f36d48e3.tar.bz2 | |
Revert of Reland: Lazily initialize MessageLoop for faster thread startup (patchset #5 id:160001 of https://codereview.chromium.org/1129953004/)
Reason for revert:
Massive data race reports, see https://crbug.com/489263
Original issue's description:
> Reland: Lazily initialize MessageLoop for faster thread startup
>
> Original review: https://codereview.chromium.org/1011683002/
>
> Reverted because it's suspected for following flakiness issues:
> http://crbug.com/485157 - Windows race
> http://crbug.com/485091 - Android ThreadWatcher
> http://crbug.com/485178 - interactive_ui_tests Menu* tests
>
> PS1 is the original patch set that gets reverted.
>
> BUG=465458, 485157, 485091, 485178
> TBR=jam
>
> Committed: https://crrev.com/8b6133a69f16702a32a3c3104630c4d9ac393b7a
> Cr-Commit-Position: refs/heads/master@{#330329}
TBR=thakis@chromium.org,toyoshim@chromium.org,jam@chromium.org,kinuko@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=465458, 485157, 485091, 485178
Review URL: https://codereview.chromium.org/1140363002
Cr-Commit-Position: refs/heads/master@{#330351}
24 files changed, 180 insertions, 283 deletions
| diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc index 5e9a461..c1ce939 100644 --- a/base/message_loop/incoming_task_queue.cc +++ b/base/message_loop/incoming_task_queue.cc @@ -44,8 +44,7 @@ IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)        message_loop_(message_loop),        next_sequence_num_(0),        message_loop_scheduled_(false), -      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())), -      is_ready_for_scheduling_(false) { +      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())) {  }  bool IncomingTaskQueue::AddToIncomingQueue( @@ -110,15 +109,6 @@ void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {    message_loop_ = NULL;  } -void IncomingTaskQueue::StartScheduling() { -  AutoLock lock(incoming_queue_lock_); -  DCHECK(!is_ready_for_scheduling_); -  DCHECK(!message_loop_scheduled_); -  is_ready_for_scheduling_ = true; -  if (!incoming_queue_.empty()) -    ScheduleWork(); -} -  IncomingTaskQueue::~IncomingTaskQueue() {    // Verify that WillDestroyCurrentMessageLoop() has been called.    DCHECK(!message_loop_); @@ -158,25 +148,19 @@ bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {    incoming_queue_.push(*pending_task);    pending_task->task.Reset(); -  if (is_ready_for_scheduling_ && -      (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) { -    ScheduleWork(); +  if (always_schedule_work_ || (!message_loop_scheduled_ && was_empty)) { +    // Wake up the message loop. +    message_loop_->ScheduleWork(); +    // After we've scheduled the message loop, we do not need to do so again +    // until we know it has processed all of the work in our queue and is +    // waiting for more work again. The message loop will always attempt to +    // reload from the incoming queue before waiting again so we clear this flag +    // in ReloadWorkQueue(). +    message_loop_scheduled_ = true;    }    return true;  } -void IncomingTaskQueue::ScheduleWork() { -  DCHECK(is_ready_for_scheduling_); -  // Wake up the message loop. -  message_loop_->ScheduleWork(); -  // After we've scheduled the message loop, we do not need to do so again -  // until we know it has processed all of the work in our queue and is -  // waiting for more work again. The message loop will always attempt to -  // reload from the incoming queue before waiting again so we clear this flag -  // in ReloadWorkQueue(). -  message_loop_scheduled_ = true; -} -  }  // namespace internal  }  // namespace base diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h index 7dd1e82..72e1f30 100644 --- a/base/message_loop/incoming_task_queue.h +++ b/base/message_loop/incoming_task_queue.h @@ -53,10 +53,6 @@ class BASE_EXPORT IncomingTaskQueue    // Disconnects |this| from the parent message loop.    void WillDestroyCurrentMessageLoop(); -  // This should be called when the message loop becomes ready for -  // scheduling work. -  void StartScheduling(); -   private:    friend class RefCountedThreadSafe<IncomingTaskQueue>;    virtual ~IncomingTaskQueue(); @@ -70,9 +66,6 @@ class BASE_EXPORT IncomingTaskQueue    // does not retain |pending_task->task| beyond this function call.    bool PostPendingTask(PendingTask* pending_task); -  // Wakes up the message loop and schedules work. -  void ScheduleWork(); -    // Number of tasks that require high resolution timing. This value is kept    // so that ReloadWorkQueue() completes in constant time.    int high_res_task_count_; @@ -99,9 +92,6 @@ class BASE_EXPORT IncomingTaskQueue    // if the incoming queue was not empty.    const bool always_schedule_work_; -  // False until StartScheduling() is called. -  bool is_ready_for_scheduling_; -    DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);  }; diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc index 4222c77..eb0f968 100644 --- a/base/message_loop/message_loop.cc +++ b/base/message_loop/message_loop.cc @@ -100,10 +100,6 @@ MessagePumpForIO* ToPumpIO(MessagePump* pump) {  }  #endif  // !defined(OS_NACL_SFI) -scoped_ptr<MessagePump> ReturnPump(scoped_ptr<MessagePump> pump) { -  return pump; -} -  }  // namespace  //------------------------------------------------------------------------------ @@ -120,19 +116,41 @@ MessageLoop::DestructionObserver::~DestructionObserver() {  //------------------------------------------------------------------------------  MessageLoop::MessageLoop(Type type) -    : MessageLoop(type, MessagePumpFactoryCallback()) { -  BindToCurrentThread(); +    : type_(type), +#if defined(OS_WIN) +      pending_high_res_tasks_(0), +      in_high_res_mode_(false), +#endif +      nestable_tasks_allowed_(true), +#if defined(OS_WIN) +      os_modal_loop_(false), +#endif  // OS_WIN +      message_histogram_(NULL), +      run_loop_(NULL) { +  Init(); + +  pump_ = CreateMessagePumpForType(type).Pass();  }  MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump) -    : MessageLoop(TYPE_CUSTOM, Bind(&ReturnPump, Passed(&pump))) { -  BindToCurrentThread(); +    : pump_(pump.Pass()), +      type_(TYPE_CUSTOM), +#if defined(OS_WIN) +      pending_high_res_tasks_(0), +      in_high_res_mode_(false), +#endif +      nestable_tasks_allowed_(true), +#if defined(OS_WIN) +      os_modal_loop_(false), +#endif  // OS_WIN +      message_histogram_(NULL), +      run_loop_(NULL) { +  DCHECK(pump_.get()); +  Init();  }  MessageLoop::~MessageLoop() { -  // current() could be NULL if this message loop is destructed before it is -  // bound to a thread. -  DCHECK(current() == this || !current()); +  DCHECK_EQ(this, current());    // iOS just attaches to the loop, it doesn't Run it.    // TODO(stuartmorgan): Consider wiring up a Detach(). @@ -281,13 +299,11 @@ void MessageLoop::PostNonNestableDelayedTask(  }  void MessageLoop::Run() { -  DCHECK(pump_);    RunLoop run_loop;    run_loop.Run();  }  void MessageLoop::RunUntilIdle() { -  DCHECK(pump_);    RunLoop run_loop;    run_loop.RunUntilIdle();  } @@ -367,43 +383,13 @@ bool MessageLoop::IsIdleForTesting() {  //------------------------------------------------------------------------------ -scoped_ptr<MessageLoop> MessageLoop::CreateUnbound( -    Type type, MessagePumpFactoryCallback pump_factory) { -  return make_scoped_ptr(new MessageLoop(type, pump_factory)); -} - -MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) -    : type_(type), -#if defined(OS_WIN) -      pending_high_res_tasks_(0), -      in_high_res_mode_(false), -#endif -      nestable_tasks_allowed_(true), -#if defined(OS_WIN) -      os_modal_loop_(false), -#endif  // OS_WIN -      pump_factory_(pump_factory), -      message_histogram_(NULL), -      run_loop_(NULL), -      incoming_task_queue_(new internal::IncomingTaskQueue(this)), -      message_loop_proxy_( -          new internal::MessageLoopProxyImpl(incoming_task_queue_)) { -  // If type is TYPE_CUSTOM non-null pump_factory must be given. -  DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null()); -} - -void MessageLoop::BindToCurrentThread() { -  DCHECK(!pump_); -  if (!pump_factory_.is_null()) -    pump_ = pump_factory_.Run(); -  else -    pump_ = CreateMessagePumpForType(type_); - +void MessageLoop::Init() {    DCHECK(!current()) << "should only have one message loop per thread";    lazy_tls_ptr.Pointer()->Set(this); -  incoming_task_queue_->StartScheduling(); -  message_loop_proxy_->BindToCurrentThread(); +  incoming_task_queue_ = new internal::IncomingTaskQueue(this); +  message_loop_proxy_ = +      new internal::MessageLoopProxyImpl(incoming_task_queue_);    thread_task_runner_handle_.reset(        new ThreadTaskRunnerHandle(message_loop_proxy_));  } diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h index f2f89d0..fd7596a 100644 --- a/base/message_loop/message_loop.h +++ b/base/message_loop/message_loop.h @@ -114,8 +114,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {    explicit MessageLoop(Type type = TYPE_DEFAULT);    // Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must    // be non-NULL. -  explicit MessageLoop(scoped_ptr<MessagePump> pump); - +  explicit MessageLoop(scoped_ptr<base::MessagePump> pump);    ~MessageLoop() override;    // Returns the MessageLoop object for the current thread, or null if none. @@ -395,6 +394,10 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {    // 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_; } @@ -408,33 +411,9 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {   private:    friend class RunLoop; -  friend class internal::IncomingTaskQueue; -  friend class ScheduleWorkTest; -  friend class Thread; - -  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(); +  // Configures various members for the two constructors. +  void Init();    // Invokes the actual run loop using the message pump.    void RunHandler(); @@ -458,10 +437,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {    // 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(); @@ -515,10 +490,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {    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_; diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_proxy_impl.cc index 0da21a0..b7abca3 100644 --- a/base/message_loop/message_loop_proxy_impl.cc +++ b/base/message_loop/message_loop_proxy_impl.cc @@ -15,12 +15,7 @@ namespace internal {  MessageLoopProxyImpl::MessageLoopProxyImpl(      scoped_refptr<IncomingTaskQueue> incoming_queue)      : incoming_queue_(incoming_queue), -      valid_thread_id_(kInvalidThreadId) { -} - -void MessageLoopProxyImpl::BindToCurrentThread() { -  DCHECK_EQ(kInvalidThreadId, valid_thread_id_); -  valid_thread_id_ = PlatformThread::CurrentId(); +      valid_thread_id_(PlatformThread::CurrentId()) {  }  bool MessageLoopProxyImpl::PostDelayedTask( diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_proxy_impl.h index c477320..0fe629f 100644 --- a/base/message_loop/message_loop_proxy_impl.h +++ b/base/message_loop/message_loop_proxy_impl.h @@ -24,9 +24,6 @@ class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy {    explicit MessageLoopProxyImpl(        scoped_refptr<IncomingTaskQueue> incoming_queue); -  // Initialize this message loop proxy on the current thread. -  void BindToCurrentThread(); -    // MessageLoopProxy implementation    bool PostDelayedTask(const tracked_objects::Location& from_here,                         const base::Closure& task, diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc index 0bf3d0c..b3e5604 100644 --- a/base/message_loop/message_pump_perftest.cc +++ b/base/message_loop/message_pump_perftest.cc @@ -20,6 +20,7 @@  #endif  namespace base { +namespace {  class ScheduleWorkTest : public testing::Test {   public: @@ -223,6 +224,9 @@ TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {  }  #endif +static void DoNothing() { +} +  class FakeMessagePump : public MessagePump {   public:    FakeMessagePump() {} @@ -285,4 +289,5 @@ TEST_F(PostTaskTest, OneHundredTasksPerReload) {    Run(1000, 100);  } +}  // namespace  }  // namespace base diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h index 69a2b0d..d8f06e5 100644 --- a/base/threading/platform_thread.h +++ b/base/threading/platform_thread.h @@ -89,10 +89,6 @@ class PlatformThreadHandle {          id_(id) {    } -  PlatformThreadId id() const { -    return id_; -  } -    bool is_equal(const PlatformThreadHandle& other) const {      return handle_ == other.handle_;    } diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc index aeaa7c7..4eb2cb2 100644 --- a/base/threading/platform_thread_win.cc +++ b/base/threading/platform_thread_win.cc @@ -108,16 +108,15 @@ bool CreateThreadInternal(size_t stack_size,    // have to work running on CreateThread() threads anyway, since we run code    // on the Windows thread pool, etc.  For some background on the difference:    //   http://www.microsoft.com/msj/1099/win32/win321099.aspx -  PlatformThreadId thread_id;    void* thread_handle = CreateThread( -      NULL, stack_size, ThreadFunc, params, flags, &thread_id); +      NULL, stack_size, ThreadFunc, params, flags, NULL);    if (!thread_handle) {      delete params;      return false;    }    if (out_thread_handle) -    *out_thread_handle = PlatformThreadHandle(thread_handle, thread_id); +    *out_thread_handle = PlatformThreadHandle(thread_handle);    else      CloseHandle(thread_handle);    return true; diff --git a/base/threading/thread.cc b/base/threading/thread.cc index b753a6b..0e4aab2 100644 --- a/base/threading/thread.cc +++ b/base/threading/thread.cc @@ -37,6 +37,20 @@ 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), @@ -58,11 +72,13 @@ Thread::Thread(const std::string& name)  #if defined(OS_WIN)        com_status_(NONE),  #endif +      started_(false),        stopping_(false),        running_(false), +      startup_data_(NULL),        thread_(0), -      message_loop_(nullptr), -      message_loop_timer_slack_(TIMER_SLACK_NONE), +      message_loop_(NULL), +      thread_id_(kInvalidThreadId),        name_(name) {  } @@ -88,50 +104,34 @@ bool Thread::StartWithOptions(const Options& options) {    SetThreadWasQuitProperly(false); -  MessageLoop::Type type = options.message_loop_type; -  if (!options.message_pump_factory.is_null()) -    type = MessageLoop::TYPE_CUSTOM; - -  message_loop_timer_slack_ = options.timer_slack; -  message_loop_ = new MessageLoop(type, options.message_pump_factory); - -  start_event_.reset(new WaitableEvent(false, false)); +  StartupData startup_data(options); +  startup_data_ = &startup_data; -  // Hold the thread_lock_ while starting a new thread, so that we can make sure -  // that thread_ is populated before the newly created thread accesses it. -  { -    AutoLock lock(thread_lock_); -    if (!PlatformThread::Create(options.stack_size, this, &thread_)) { -      DLOG(ERROR) << "failed to create thread"; -      delete message_loop_; -      message_loop_ = nullptr; -      start_event_.reset(); -      return false; -    } +  if (!PlatformThread::Create(options.stack_size, this, &thread_)) { +    DLOG(ERROR) << "failed to create thread"; +    startup_data_ = NULL; +    return false;    } -  DCHECK(message_loop_); -  return true; -} - -bool Thread::StartAndWaitForTesting() { -  bool result = Start(); -  if (!result) -    return false; -  WaitUntilThreadStarted(); -  return true; -} +  // TODO(kinuko): Remove once crbug.com/465458 is solved. +  tracked_objects::ScopedTracker tracking_profile_wait( +      FROM_HERE_WITH_EXPLICIT_FUNCTION( +          "465458 base::Thread::StartWithOptions (Wait)")); -bool Thread::WaitUntilThreadStarted() { -  if (!start_event_) -    return false; +  // Wait for the thread to start and initialize message_loop_    base::ThreadRestrictions::ScopedAllowWait allow_wait; -  start_event_->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;  }  void Thread::Stop() { -  if (!start_event_) +  if (!started_)      return;    StopSoon(); @@ -147,7 +147,7 @@ void Thread::Stop() {    DCHECK(!message_loop_);    // The thread no longer needs to be joined. -  start_event_.reset(); +  started_ = false;    stopping_ = false;  } @@ -155,7 +155,9 @@ void Thread::Stop() {  void Thread::StopSoon() {    // We should only be called on the same thread that started us. -  DCHECK_NE(thread_id(), PlatformThread::CurrentId()); +  // Reading thread_id_ without a lock can lead to a benign data race +  // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer. +  DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());    if (stopping_ || !message_loop_)      return; @@ -164,28 +166,14 @@ void Thread::StopSoon() {    task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));  } -PlatformThreadId Thread::thread_id() const { -  AutoLock lock(thread_lock_); -  return thread_.id(); -} -  bool Thread::IsRunning() const { -  // If the thread's already started (i.e. message_loop_ is non-null) and -  // not yet requested to stop (i.e. stopping_ is false) we can just return -  // true. (Note that stopping_ is touched only on the same thread that -  // starts / started the new thread so we need no locking here.) -  if (message_loop_ && !stopping_) -    return true; -  // Otherwise check the running_ flag, which is set to true by the new thread -  // only while it is inside Run(). -  AutoLock lock(running_lock_);    return running_;  }  void Thread::SetPriority(ThreadPriority priority) {    // The thread must be started (and id known) for this to be    // compatible with all platforms. -  DCHECK(message_loop_ != nullptr); +  DCHECK_NE(thread_id_, kInvalidThreadId);    PlatformThread::SetThreadPriority(thread_, priority);  } @@ -206,60 +194,60 @@ bool Thread::GetThreadWasQuitProperly() {  }  void Thread::ThreadMain() { -  // Complete the initialization of our Thread object. -  PlatformThread::SetName(name_.c_str()); -  ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector. +  { +    // 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)); +    } -  // 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_->BindToCurrentThread(); -  message_loop_->set_thread_name(name_); -  message_loop_->SetTimerSlack(message_loop_timer_slack_); +    // Complete the initialization of our Thread object. +    thread_id_ = PlatformThread::CurrentId(); +    PlatformThread::SetName(name_); +    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();  #if defined(OS_WIN) -  scoped_ptr<win::ScopedCOMInitializer> com_initializer; -  if (com_status_ != NONE) { -    com_initializer.reset((com_status_ == STA) ? -        new win::ScopedCOMInitializer() : -        new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA)); -  } +    scoped_ptr<win::ScopedCOMInitializer> com_initializer; +    if (com_status_ != NONE) { +      com_initializer.reset((com_status_ == STA) ? +          new win::ScopedCOMInitializer() : +          new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA)); +    }  #endif -  // Make sure the thread_id() returns current thread. -  // (This internally acquires lock against PlatformThread::Create) -  DCHECK_EQ(thread_id(), PlatformThread::CurrentId()); +    // Let the thread do extra initialization. +    // Let's do this before signaling we are started. +    Init(); -  // Let the thread do extra initialization. -  Init(); - -  { -    AutoLock lock(running_lock_);      running_ = true; -  } - -  start_event_->Signal(); +    startup_data_->event.Signal(); +    // startup_data_ can't be touched anymore since the starting thread is now +    // unlocked. -  Run(message_loop_); - -  { -    AutoLock lock(running_lock_); +    Run(message_loop_);      running_ = false; -  } -  // Let the thread do extra cleanup. -  CleanUp(); +    // Let the thread do extra cleanup. +    CleanUp();  #if defined(OS_WIN) -  com_initializer.reset(); +    com_initializer.reset();  #endif -  // Assert that MessageLoop::Quit was called by ThreadQuitHelper. -  DCHECK(GetThreadWasQuitProperly()); +    // Assert that MessageLoop::Quit was called by ThreadQuitHelper. +    DCHECK(GetThreadWasQuitProperly()); -  // We can't receive messages anymore. -  // (The message loop is destructed at the end of this block) -  message_loop_ = NULL; +    // We can't receive messages anymore. +    message_loop_ = NULL; +  }  }  }  // namespace base diff --git a/base/threading/thread.h b/base/threading/thread.h index 6b2f1c5..4915606 100644 --- a/base/threading/thread.h +++ b/base/threading/thread.h @@ -13,13 +13,11 @@  #include "base/message_loop/message_loop.h"  #include "base/message_loop/timer_slack.h"  #include "base/single_thread_task_runner.h" -#include "base/synchronization/lock.h"  #include "base/threading/platform_thread.h"  namespace base {  class MessagePump; -class WaitableEvent;  // A simple thread abstraction that establishes a MessageLoop on a new thread.  // The consumer uses the MessageLoop of the thread to cause code to execute on @@ -47,7 +45,7 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {      // This is ignored if message_pump_factory.is_null() is false.      MessageLoop::Type message_loop_type; -    // Specifies timer slack for thread message loop. +    // Specify timer slack for thread message loop.      TimerSlack timer_slack;      // Used to create the MessagePump for the MessageLoop. The callback is Run() @@ -83,7 +81,7 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {    // init_com_with_mta(false) and then StartWithOptions() with any message loop    // type other than TYPE_UI.    void init_com_with_mta(bool use_mta) { -    DCHECK(!start_event_); +    DCHECK(!started_);      com_status_ = use_mta ? MTA : STA;    }  #endif @@ -105,18 +103,6 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {    // callback.    bool StartWithOptions(const Options& options); -  // Starts the thread and wait for the thread to start and run initialization -  // before returning. It's same as calling Start() and then -  // WaitUntilThreadStarted(). -  // Note that using this (instead of Start() or StartWithOptions() causes -  // jank on the calling thread, should be used only in testing code. -  bool StartAndWaitForTesting(); - -  // Blocks until the thread starts running. Called within StartAndWait(). -  // Note that calling this causes jank on the calling thread, must be used -  // carefully for production code. -  bool WaitUntilThreadStarted(); -    // Signals the thread to exit and returns once the thread has exited.  After    // this method returns, the Thread object is completely reset and may be used    // as if it were newly constructed (i.e., Start may be called again). @@ -180,7 +166,7 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {    PlatformThreadHandle thread_handle() { return thread_; }    // The thread ID. -  PlatformThreadId thread_id() const; +  PlatformThreadId thread_id() const { return thread_id_; }    // Returns true if the thread has been started, and not yet stopped.    bool IsRunning() const; @@ -222,32 +208,33 @@ class BASE_EXPORT Thread : PlatformThread::Delegate {    ComStatus com_status_;  #endif +  // Whether we successfully started the thread. +  bool started_; +    // If true, we're in the middle of stopping, and shouldn't access    // |message_loop_|. It may non-NULL and invalid.    bool stopping_;    // True while inside of Run().    bool running_; -  mutable base::Lock running_lock_;  // Protects running_. + +  // Used to pass data to ThreadMain. +  struct StartupData; +  StartupData* startup_data_;    // The thread's handle.    PlatformThreadHandle thread_; -  mutable base::Lock thread_lock_;  // Protects thread_.    // The thread's message loop.  Valid only while the thread is alive.  Set    // by the created thread.    MessageLoop* message_loop_; -  // Stores Options::timer_slack_ until the message loop has been bound to -  // a thread. -  TimerSlack message_loop_timer_slack_; +  // Our thread's ID. +  PlatformThreadId thread_id_;    // The name of the thread.  Used for debugging purposes.    std::string name_; -  // Non-null if the thread has successfully started. -  scoped_ptr<WaitableEvent> start_event_; -    friend void ThreadQuitHelper();    DISALLOW_COPY_AND_ASSIGN(Thread); diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc index b17c681..b5953d5 100644 --- a/base/threading/thread_id_name_manager_unittest.cc +++ b/base/threading/thread_id_name_manager_unittest.cc @@ -21,8 +21,8 @@ TEST_F(ThreadIdNameManagerTest, AddThreads) {    base::Thread thread_a(kAThread);    base::Thread thread_b(kBThread); -  thread_a.StartAndWaitForTesting(); -  thread_b.StartAndWaitForTesting(); +  thread_a.Start(); +  thread_b.Start();    EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));    EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id())); @@ -35,10 +35,10 @@ TEST_F(ThreadIdNameManagerTest, RemoveThreads) {    base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();    base::Thread thread_a(kAThread); -  thread_a.StartAndWaitForTesting(); +  thread_a.Start();    {      base::Thread thread_b(kBThread); -    thread_b.StartAndWaitForTesting(); +    thread_b.Start();      thread_b.Stop();    }    EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id())); @@ -51,12 +51,12 @@ TEST_F(ThreadIdNameManagerTest, RestartThread) {    base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();    base::Thread thread_a(kAThread); -  thread_a.StartAndWaitForTesting(); +  thread_a.Start();    base::PlatformThreadId a_id = thread_a.thread_id();    EXPECT_STREQ(kAThread, manager->GetName(a_id));    thread_a.Stop(); -  thread_a.StartAndWaitForTesting(); +  thread_a.Start();    EXPECT_STREQ("", manager->GetName(a_id));    EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));    thread_a.Stop(); diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc index e86c758..a89768e 100644 --- a/base/threading/thread_unittest.cc +++ b/base/threading/thread_unittest.cc @@ -194,12 +194,11 @@ TEST_F(ThreadTest, ThreadName) {    EXPECT_EQ("ThreadName", a.thread_name());  } -// Make sure Init() is called after Start() and before -// WaitUntilThreadInitialized() returns. +// Make sure we can't use a thread between Start() and Init().  TEST_F(ThreadTest, SleepInsideInit) {    SleepInsideInitThread t;    EXPECT_FALSE(t.InitCalled()); -  t.StartAndWaitForTesting(); +  t.Start();    EXPECT_TRUE(t.InitCalled());  } diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 907ffbd..46d0e3e 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -608,6 +608,11 @@ net::URLRequestContextGetter* IOThread::system_url_request_context_getter() {  }  void IOThread::Init() { +  // Prefer to use InitAsync unless you need initialization to block +  // the UI thread +} + +void IOThread::InitAsync() {    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466432    // is fixed.    tracked_objects::ScopedTracker tracking_profile1( diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h index d31cb64..0b94438 100644 --- a/chrome/browser/io_thread.h +++ b/chrome/browser/io_thread.h @@ -255,6 +255,7 @@ class IOThread : public content::BrowserThreadDelegate {    // This handles initialization and destruction of state that must    // live on the IO thread.    void Init() override; +  void InitAsync() override;    void CleanUp() override;    // Initializes |params| based on the settings in |globals|. diff --git a/chrome/browser/metrics/thread_watcher_android_unittest.cc b/chrome/browser/metrics/thread_watcher_android_unittest.cc index 2b5c04f..62489b6 100644 --- a/chrome/browser/metrics/thread_watcher_android_unittest.cc +++ b/chrome/browser/metrics/thread_watcher_android_unittest.cc @@ -48,7 +48,7 @@ TEST(ThreadWatcherAndroidTest, DISABLED_ApplicationStatusNotification) {    scoped_ptr<WatchDogThread> watchdog_thread_(new WatchDogThread()); -  watchdog_thread_->StartAndWaitForTesting(); +  watchdog_thread_->Start();    EXPECT_FALSE(ThreadWatcherList::g_thread_watcher_list_); diff --git a/chrome/browser/metrics/thread_watcher_unittest.cc b/chrome/browser/metrics/thread_watcher_unittest.cc index fcd2746..2884698 100644 --- a/chrome/browser/metrics/thread_watcher_unittest.cc +++ b/chrome/browser/metrics/thread_watcher_unittest.cc @@ -257,9 +257,9 @@ class ThreadWatcherTest : public ::testing::Test {      db_thread_.reset(new content::TestBrowserThread(BrowserThread::DB));      io_thread_.reset(new content::TestBrowserThread(BrowserThread::IO));      watchdog_thread_.reset(new WatchDogThread()); -    db_thread_->StartAndWaitForTesting(); -    io_thread_->StartAndWaitForTesting(); -    watchdog_thread_->StartAndWaitForTesting(); +    db_thread_->Start(); +    io_thread_->Start(); +    watchdog_thread_->Start();      WatchDogThread::PostTask(          FROM_HERE, @@ -697,7 +697,7 @@ TEST_F(ThreadWatcherListTest, Restart) {    content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop_for_ui);    scoped_ptr<WatchDogThread> watchdog_thread_(new WatchDogThread()); -  watchdog_thread_->StartAndWaitForTesting(); +  watchdog_thread_->Start();    // See http://crbug.com/347887.    // StartWatchingAll() will PostDelayedTask to create g_thread_watcher_list_, diff --git a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc index 34adb95..3db65e9 100644 --- a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc +++ b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc @@ -336,9 +336,6 @@ TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) {        base::Bind(&SyncBackendRegistrar::Shutdown,                   base::Unretained(registrar.release()))); -  // Make sure the thread starts running. -  sync_thread->WaitUntilThreadStarted(); -    // The test verifies that the sync thread doesn't block because    // of the blocked DB thread and can finish the shutdown.    sync_thread->message_loop()->RunUntilIdle(); diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc index 4ae6607..78e3836 100644 --- a/content/browser/browser_thread_impl.cc +++ b/content/browser/browser_thread_impl.cc @@ -159,8 +159,14 @@ void BrowserThreadImpl::Init() {    AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);    BrowserThreadDelegate* delegate =        reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); -  if (delegate) +  if (delegate) {      delegate->Init(); +    message_loop()->PostTask(FROM_HERE, +                             base::Bind(&BrowserThreadDelegate::InitAsync, +                                        // Delegate is expected to exist for the +                                        // duration of the thread's lifetime +                                        base::Unretained(delegate))); +  }  }  // We disable optimizations for this block of functions so the compiler doesn't diff --git a/content/public/browser/browser_thread_delegate.h b/content/public/browser/browser_thread_delegate.h index 3688e65..ad5fd7e 100644 --- a/content/public/browser/browser_thread_delegate.h +++ b/content/public/browser/browser_thread_delegate.h @@ -22,6 +22,9 @@ class BrowserThreadDelegate {    // Called prior to starting the message loop    virtual void Init() = 0; +  // Called as the first task on the thread's message loop. +  virtual void InitAsync() = 0; +    // Called just after the message loop ends.    virtual void CleanUp() = 0;  }; diff --git a/content/public/test/test_browser_thread.cc b/content/public/test/test_browser_thread.cc index 62d9eb8..ac67480 100644 --- a/content/public/test/test_browser_thread.cc +++ b/content/public/test/test_browser_thread.cc @@ -58,10 +58,6 @@ bool TestBrowserThread::Start() {    return impl_->Start();  } -bool TestBrowserThread::StartAndWaitForTesting() { -  return impl_->StartAndWaitForTesting(); -} -  bool TestBrowserThread::StartIOThread() {    base::Thread::Options options;    options.message_loop_type = base::MessageLoop::TYPE_IO; diff --git a/content/public/test/test_browser_thread.h b/content/public/test/test_browser_thread.h index d3a2564..2428bbb 100644 --- a/content/public/test/test_browser_thread.h +++ b/content/public/test/test_browser_thread.h @@ -36,10 +36,6 @@ class TestBrowserThread {    // Starts the thread with a generic message loop.    bool Start(); -  // Starts the thread with a generic message loop and waits for the -  // thread to run. -  bool StartAndWaitForTesting(); -    // Starts the thread with an IOThread message loop.    bool StartIOThread(); diff --git a/net/android/network_change_notifier_android.cc b/net/android/network_change_notifier_android.cc index 9829235..a6ea628 100644 --- a/net/android/network_change_notifier_android.cc +++ b/net/android/network_change_notifier_android.cc @@ -173,9 +173,6 @@ NetworkChangeNotifierAndroid::NetworkChangeNotifierAndroid(    delegate_->AddObserver(this);    dns_config_service_thread_->StartWithOptions(        base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); -  // Wait until Init is called on the DNS config thread before -  // calling InitAfterStart. -  dns_config_service_thread_->WaitUntilThreadStarted();    dns_config_service_thread_->InitAfterStart();  } diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc index e747c94..ac7d3bc 100644 --- a/net/test/embedded_test_server/embedded_test_server.cc +++ b/net/test/embedded_test_server/embedded_test_server.cc @@ -190,7 +190,6 @@ void EmbeddedTestServer::StartThread() {    thread_options.message_loop_type = base::MessageLoop::TYPE_IO;    io_thread_.reset(new base::Thread("EmbeddedTestServer io thread"));    CHECK(io_thread_->StartWithOptions(thread_options)); -  CHECK(io_thread_->WaitUntilThreadStarted());  }  void EmbeddedTestServer::InitializeOnIOThread() { | 
