Chromium Code Reviews| Index: base/threading/thread.cc |
| diff --git a/base/threading/thread.cc b/base/threading/thread.cc |
| index a8833aeb3f39b553d15d41f66737b7d83bfcad54..98610a63c09875878ffceca6417d7af16980ca89 100644 |
| --- a/base/threading/thread.cc |
| +++ b/base/threading/thread.cc |
| @@ -33,42 +33,26 @@ base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool = |
| } // namespace |
| -Thread::Options::Options() |
| - : message_loop_type(MessageLoop::TYPE_DEFAULT), |
| - timer_slack(TIMER_SLACK_NONE), |
| - stack_size(0), |
| - priority(ThreadPriority::NORMAL) { |
| -} |
| +Thread::Options::Options() = default; |
| -Thread::Options::Options(MessageLoop::Type type, |
| - size_t size) |
| - : message_loop_type(type), |
| - timer_slack(TIMER_SLACK_NONE), |
| - stack_size(size), |
| - priority(ThreadPriority::NORMAL) { |
| -} |
| +Thread::Options::Options(MessageLoop::Type type, size_t size) |
| + : message_loop_type(type), stack_size(size) {} |
| Thread::Options::Options(const Options& other) = default; |
| -Thread::Options::~Options() { |
| -} |
| +Thread::Options::~Options() = default; |
| Thread::Thread(const std::string& name) |
| - : |
| -#if defined(OS_WIN) |
| - com_status_(NONE), |
| -#endif |
| - stopping_(false), |
| - running_(false), |
| - thread_(0), |
| - id_(kInvalidThreadId), |
| - id_event_(WaitableEvent::ResetPolicy::MANUAL, |
| + : id_event_(WaitableEvent::ResetPolicy::MANUAL, |
| WaitableEvent::InitialState::NOT_SIGNALED), |
| - message_loop_(nullptr), |
| - message_loop_timer_slack_(TIMER_SLACK_NONE), |
| name_(name), |
| start_event_(WaitableEvent::ResetPolicy::MANUAL, |
| WaitableEvent::InitialState::NOT_SIGNALED) { |
| + // Only bind the sequence on Start(): the state is constant between |
| + // construction and Start() and it's thus valid for Start() to be called on |
| + // another sequence as long as every other operation is then performed on that |
| + // sequence. |
| + owning_sequence_checker_.DetachFromSequence(); |
| } |
| Thread::~Thread() { |
| @@ -76,6 +60,8 @@ Thread::~Thread() { |
| } |
| bool Thread::Start() { |
| + DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); |
| + |
| Options options; |
| #if defined(OS_WIN) |
| if (com_status_ == STA) |
| @@ -85,7 +71,9 @@ bool Thread::Start() { |
| } |
| bool Thread::StartWithOptions(const Options& options) { |
| + DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); |
| DCHECK(!message_loop_); |
| + DCHECK(!IsRunning()); |
| #if defined(OS_WIN) |
| DCHECK((com_status_ != STA) || |
| (options.message_loop_type == MessageLoop::TYPE_UI)); |
| @@ -102,13 +90,14 @@ bool Thread::StartWithOptions(const Options& options) { |
| type = MessageLoop::TYPE_CUSTOM; |
| message_loop_timer_slack_ = options.timer_slack; |
| - std::unique_ptr<MessageLoop> message_loop = |
| + std::unique_ptr<MessageLoop> message_loop_owned = |
| MessageLoop::CreateUnbound(type, options.message_pump_factory); |
| - message_loop_ = message_loop.get(); |
| + message_loop_ = message_loop_owned.get(); |
| start_event_.Reset(); |
| - // 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. |
| + // Hold |thread_lock_| while starting the new thread to synchronize with |
| + // Stop() while it's not guaranteed to be sequenced (until crbug/629139 is |
| + // fixed). |
| { |
| AutoLock lock(thread_lock_); |
| if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_, |
| @@ -119,15 +108,16 @@ bool Thread::StartWithOptions(const Options& options) { |
| } |
| } |
| - // The ownership of message_loop is managemed by the newly created thread |
| + // The ownership of |message_loop_| is managed by the newly created thread |
| // within the ThreadMain. |
| - ignore_result(message_loop.release()); |
| + ignore_result(message_loop_owned.release()); |
| DCHECK(message_loop_); |
| return true; |
| } |
| bool Thread::StartAndWaitForTesting() { |
| + DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); |
| bool result = Start(); |
| if (!result) |
| return false; |
| @@ -136,6 +126,7 @@ bool Thread::StartAndWaitForTesting() { |
| } |
| bool Thread::WaitUntilThreadStarted() const { |
| + DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); |
| if (!message_loop_) |
| return false; |
| base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| @@ -144,7 +135,12 @@ bool Thread::WaitUntilThreadStarted() const { |
| } |
| void Thread::Stop() { |
| + // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and |
| + // enable this check, until then synchronization with Start() via |
| + // |thread_lock_| is required... |
|
Wez
2016/07/25 21:20:29
FWIW, this comment as worded implies that callers
gab
2016/07/26 02:48:23
Generally in Chromium, unless specified otherwise,
|
| + // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); |
| AutoLock lock(thread_lock_); |
| + |
| if (thread_.is_null()) |
| return; |
| @@ -152,22 +148,23 @@ void Thread::Stop() { |
| // Wait for the thread to exit. |
| // |
| - // TODO(darin): Unfortunately, we need to keep message_loop_ around until |
| + // TODO(darin): Unfortunately, we need to keep |message_loop_| around until |
| // the thread exits. Some consumers are abusing the API. Make them stop. |
| // |
| PlatformThread::Join(thread_); |
| thread_ = base::PlatformThreadHandle(); |
| - // The thread should nullify message_loop_ on exit. |
| + // The thread should nullify |message_loop_| on exit (note: Join() adds an |
| + // implicit memory barrier and no lock is thus required for this check). |
| DCHECK(!message_loop_); |
| stopping_ = false; |
| } |
| void Thread::StopSoon() { |
| - // We should only be called on the same thread that started us. |
| - |
| - DCHECK_NE(GetThreadId(), PlatformThread::CurrentId()); |
| + // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and |
| + // enable this check. |
| + // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); |
| if (stopping_ || !message_loop_) |
| return; |
| @@ -185,26 +182,35 @@ PlatformThreadId Thread::GetThreadId() const { |
| } |
| 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.) |
| + // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and |
| + // enable this check. |
| + // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); |
| + |
| + // 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 sequence 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 |
| + // 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::Run(RunLoop* run_loop) { |
| + // Overridable protected method to be called from our |thread_| only. |
| + DCHECK_EQ(id_, PlatformThread::CurrentId()); |
|
Wez
2016/07/25 21:22:36
What is this DCHECK intended to protect against? C
gab
2016/07/26 02:48:23
As is often the case with DCHECKs, it's intended a
|
| + |
| run_loop->Run(); |
| } |
| +// static |
| void Thread::SetThreadWasQuitProperly(bool flag) { |
| lazy_tls_bool.Pointer()->Set(flag); |
| } |
| +// static |
| bool Thread::GetThreadWasQuitProperly() { |
| bool quit_properly = true; |
| #ifndef NDEBUG |
| @@ -224,7 +230,7 @@ void Thread::ThreadMain() { |
| PlatformThread::SetName(name_.c_str()); |
| ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. |
| - // Lazily initialize the message_loop so that it can run on this thread. |
| + // Lazily initialize the |message_loop| so that it can run on this thread. |
| DCHECK(message_loop_); |
| std::unique_ptr<MessageLoop> message_loop(message_loop_); |
| message_loop_->BindToCurrentThread(); |