1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/threading/thread.h"
8 #include "base/lazy_instance.h"
9 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
10 #include "base/threading/thread_local.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "base/synchronization/waitable_event.h"
15 #include "base/win/scoped_com_initializer.h"
22 // We use this thread-local variable to record whether or not a thread exited
23 // because its Stop method was called. This allows us to catch cases where
24 // MessageLoop::Quit() is called directly, which is unexpected when using a
25 // Thread to setup and run a MessageLoop.
26 base::LazyInstance
<base::ThreadLocalBoolean
> lazy_tls_bool
=
27 LAZY_INSTANCE_INITIALIZER
;
31 // This is used to trigger the message loop to exit.
32 void ThreadQuitHelper() {
33 MessageLoop::current()->Quit();
34 Thread::SetThreadWasQuitProperly(true);
37 // Used to pass data to ThreadMain. This structure is allocated on the stack
38 // from within StartWithOptions.
39 struct Thread::StartupData
{
40 // We get away with a const reference here because of how we are allocated.
41 const Thread::Options
& options
;
43 // Used to synchronize thread startup.
46 explicit StartupData(const Options
& opt
)
48 event(false, false) {}
51 Thread::Thread(const char* name
)
62 thread_id_(kInvalidThreadId
),
70 bool Thread::Start() {
73 if (com_status_
== STA
)
74 options
.message_loop_type
= MessageLoop::TYPE_UI
;
76 return StartWithOptions(options
);
79 bool Thread::StartWithOptions(const Options
& options
) {
80 DCHECK(!message_loop_
);
82 DCHECK((com_status_
!= STA
) ||
83 (options
.message_loop_type
== MessageLoop::TYPE_UI
));
86 SetThreadWasQuitProperly(false);
88 StartupData
startup_data(options
);
89 startup_data_
= &startup_data
;
91 if (!PlatformThread::Create(options
.stack_size
, this, &thread_
)) {
92 DLOG(ERROR
) << "failed to create thread";
97 // Wait for the thread to start and initialize message_loop_
98 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
99 startup_data
.event
.Wait();
101 // set it to NULL so we don't keep a pointer to some object on the stack.
102 startup_data_
= NULL
;
105 DCHECK(message_loop_
);
109 void Thread::Stop() {
115 // Wait for the thread to exit.
117 // TODO(darin): Unfortunately, we need to keep message_loop_ around until
118 // the thread exits. Some consumers are abusing the API. Make them stop.
120 PlatformThread::Join(thread_
);
122 // The thread should NULL message_loop_ on exit.
123 DCHECK(!message_loop_
);
125 // The thread no longer needs to be joined.
131 void Thread::StopSoon() {
132 // We should only be called on the same thread that started us.
134 // Reading thread_id_ without a lock can lead to a benign data race
135 // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
136 DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_
), PlatformThread::CurrentId());
138 if (stopping_
|| !message_loop_
)
142 message_loop_
->PostTask(FROM_HERE
, base::Bind(&ThreadQuitHelper
));
145 bool Thread::IsRunning() const {
149 void Thread::Run(MessageLoop
* message_loop
) {
153 void Thread::SetThreadWasQuitProperly(bool flag
) {
154 lazy_tls_bool
.Pointer()->Set(flag
);
157 bool Thread::GetThreadWasQuitProperly() {
158 bool quit_properly
= true;
160 quit_properly
= lazy_tls_bool
.Pointer()->Get();
162 return quit_properly
;
165 void Thread::ThreadMain() {
167 // The message loop for this thread.
168 MessageLoop
message_loop(startup_data_
->options
.message_loop_type
);
170 // Complete the initialization of our Thread object.
171 thread_id_
= PlatformThread::CurrentId();
172 PlatformThread::SetName(name_
.c_str());
173 ANNOTATE_THREAD_NAME(name_
.c_str()); // Tell the name to race detector.
174 message_loop
.set_thread_name(name_
);
175 message_loop_
= &message_loop
;
178 scoped_ptr
<win::ScopedCOMInitializer
> com_initializer
;
179 if (com_status_
!= NONE
) {
180 com_initializer
.reset((com_status_
== STA
) ?
181 new win::ScopedCOMInitializer() :
182 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA
));
186 // Let the thread do extra initialization.
187 // Let's do this before signaling we are started.
191 startup_data_
->event
.Signal();
192 // startup_data_ can't be touched anymore since the starting thread is now
198 // Let the thread do extra cleanup.
202 com_initializer
.reset();
205 // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
206 DCHECK(GetThreadWasQuitProperly());
208 // We can't receive messages anymore.
209 message_loop_
= NULL
;