| Index: base/threading/thread.cc
|
| diff --git a/base/threading/thread.cc b/base/threading/thread.cc
|
| index 4ba6ad156ebb8b36e4f984b9dc58512048755702..387c79459c196c6ac60a9678e5d464e4c71bb480 100644
|
| --- a/base/threading/thread.cc
|
| +++ b/base/threading/thread.cc
|
| @@ -8,6 +8,7 @@
|
| #include "base/bind_helpers.h"
|
| #include "base/lazy_instance.h"
|
| #include "base/location.h"
|
| +#include "base/logging.h"
|
| #include "base/run_loop.h"
|
| #include "base/synchronization/waitable_event.h"
|
| #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
|
| @@ -28,7 +29,7 @@ namespace {
|
| // because its Stop method was called. This allows us to catch cases where
|
| // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
|
| // using a Thread to setup and run a MessageLoop.
|
| -base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
|
| +base::LazyInstance<base::ThreadLocalBoolean>::Leaky lazy_tls_bool =
|
| LAZY_INSTANCE_INITIALIZER;
|
|
|
| } // namespace
|
| @@ -74,6 +75,8 @@ bool Thread::StartWithOptions(const Options& options) {
|
| DCHECK(owning_sequence_checker_.CalledOnValidSequence());
|
| DCHECK(!message_loop_);
|
| DCHECK(!IsRunning());
|
| + DCHECK(!stopping_) << "Starting a non-joinable thread a second time? That's "
|
| + << "not allowed!";
|
| #if defined(OS_WIN)
|
| DCHECK((com_status_ != STA) ||
|
| (options.message_loop_type == MessageLoop::TYPE_UI));
|
| @@ -100,14 +103,21 @@ bool Thread::StartWithOptions(const Options& options) {
|
| // fixed).
|
| {
|
| AutoLock lock(thread_lock_);
|
| - if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,
|
| - options.priority)) {
|
| + bool success =
|
| + options.joinable
|
| + ? PlatformThread::CreateWithPriority(options.stack_size, this,
|
| + &thread_, options.priority)
|
| + : PlatformThread::CreateNonJoinableWithPriority(
|
| + options.stack_size, this, options.priority);
|
| + if (!success) {
|
| DLOG(ERROR) << "failed to create thread";
|
| message_loop_ = nullptr;
|
| return false;
|
| }
|
| }
|
|
|
| + joinable_ = options.joinable;
|
| +
|
| // The ownership of |message_loop_| is managed by the newly created thread
|
| // within the ThreadMain.
|
| ignore_result(message_loop_owned.release());
|
| @@ -135,17 +145,20 @@ bool Thread::WaitUntilThreadStarted() const {
|
| }
|
|
|
| void Thread::Stop() {
|
| + DCHECK(joinable_);
|
| +
|
| // 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...
|
| // DCHECK(owning_sequence_checker_.CalledOnValidSequence());
|
| AutoLock lock(thread_lock_);
|
|
|
| + StopSoon();
|
| +
|
| + // Can't join if the |thread_| is either already gone or is non-joinable.
|
| if (thread_.is_null())
|
| return;
|
|
|
| - StopSoon();
|
| -
|
| // Wait for the thread to exit.
|
| //
|
| // TODO(darin): Unfortunately, we need to keep |message_loop_| around until
|
| @@ -170,6 +183,16 @@ void Thread::StopSoon() {
|
| return;
|
|
|
| stopping_ = true;
|
| +
|
| + if (using_external_message_loop_) {
|
| + // Setting |stopping_| to true above should have been sufficient for this
|
| + // thread to be considered "stopped" per it having never set its |running_|
|
| + // bit by lack of its own ThreadMain.
|
| + DCHECK(!IsRunning());
|
| + message_loop_ = nullptr;
|
| + return;
|
| + }
|
| +
|
| task_runner()->PostTask(
|
| FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this)));
|
| }
|
| @@ -219,6 +242,24 @@ bool Thread::GetThreadWasQuitProperly() {
|
| return quit_properly;
|
| }
|
|
|
| +void Thread::SetMessageLoop(MessageLoop* message_loop) {
|
| + DCHECK(owning_sequence_checker_.CalledOnValidSequence());
|
| +
|
| + // TODO(gab): Figure out why some callers pass in a null |message_loop|...
|
| + // https://crbug.com/629139#c15
|
| + // DCHECK(message_loop);
|
| + if (!message_loop)
|
| + return;
|
| +
|
| + // Setting |message_loop_| should suffice for this thread to be considered
|
| + // as "running", until Stop() is invoked.
|
| + DCHECK(!IsRunning());
|
| + message_loop_ = message_loop;
|
| + DCHECK(IsRunning());
|
| +
|
| + using_external_message_loop_ = true;
|
| +}
|
| +
|
| void Thread::ThreadMain() {
|
| // First, make GetThreadId() available to avoid deadlocks. It could be called
|
| // any place in the following thread initialization code.
|
|
|