OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2009 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. | |
4 | |
5 #include "base/thread.h" | |
6 | |
7 #include "base/lazy_instance.h" | |
8 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | |
9 #include "base/threading/thread_local.h" | |
10 #include "base/waitable_event.h" | |
11 | |
12 namespace base { | |
13 | |
14 // This task is used to trigger the message loop to exit. | |
15 class ThreadQuitTask : public Task { | |
16 public: | |
17 virtual void Run() { | |
18 MessageLoop::current()->Quit(); | |
19 Thread::SetThreadWasQuitProperly(true); | |
20 } | |
21 }; | |
22 | |
23 // Used to pass data to ThreadMain. This structure is allocated on the stack | |
24 // from within StartWithOptions. | |
25 struct Thread::StartupData { | |
26 // We get away with a const reference here because of how we are allocated. | |
27 const Thread::Options& options; | |
28 | |
29 // Used to synchronize thread startup. | |
30 WaitableEvent event; | |
31 | |
32 explicit StartupData(const Options& opt) | |
33 : options(opt), | |
34 event(false, false) {} | |
35 }; | |
36 | |
37 Thread::Thread(const char* name) | |
38 : started_(false), | |
39 stopping_(false), | |
40 startup_data_(NULL), | |
41 thread_(0), | |
42 message_loop_(NULL), | |
43 thread_id_(kInvalidThreadId), | |
44 name_(name) { | |
45 } | |
46 | |
47 Thread::~Thread() { | |
48 Stop(); | |
49 } | |
50 | |
51 namespace { | |
52 | |
53 // We use this thread-local variable to record whether or not a thread exited | |
54 // because its Stop method was called. This allows us to catch cases where | |
55 // MessageLoop::Quit() is called directly, which is unexpected when using a | |
56 // Thread to setup and run a MessageLoop. | |
57 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool( | |
58 base::LINKER_INITIALIZED); | |
59 | |
60 } // namespace | |
61 | |
62 void Thread::SetThreadWasQuitProperly(bool flag) { | |
63 lazy_tls_bool.Pointer()->Set(flag); | |
64 } | |
65 | |
66 bool Thread::GetThreadWasQuitProperly() { | |
67 bool quit_properly = true; | |
68 #ifndef NDEBUG | |
69 quit_properly = lazy_tls_bool.Pointer()->Get(); | |
70 #endif | |
71 return quit_properly; | |
72 } | |
73 | |
74 bool Thread::Start() { | |
75 return StartWithOptions(Options()); | |
76 } | |
77 | |
78 bool Thread::StartWithOptions(const Options& options) { | |
79 DCHECK(!message_loop_); | |
80 | |
81 SetThreadWasQuitProperly(false); | |
82 | |
83 StartupData startup_data(options); | |
84 startup_data_ = &startup_data; | |
85 | |
86 if (!PlatformThread::Create(options.stack_size, this, &thread_)) { | |
87 DLOG(ERROR) << "failed to create thread"; | |
88 startup_data_ = NULL; | |
89 return false; | |
90 } | |
91 | |
92 // Wait for the thread to start and initialize message_loop_ | |
93 startup_data.event.Wait(); | |
94 | |
95 // set it to NULL so we don't keep a pointer to some object on the stack. | |
96 startup_data_ = NULL; | |
97 started_ = true; | |
98 | |
99 DCHECK(message_loop_); | |
100 return true; | |
101 } | |
102 | |
103 void Thread::Stop() { | |
104 if (!thread_was_started()) | |
105 return; | |
106 | |
107 StopSoon(); | |
108 | |
109 // Wait for the thread to exit. | |
110 // | |
111 // TODO(darin): Unfortunately, we need to keep message_loop_ around until | |
112 // the thread exits. Some consumers are abusing the API. Make them stop. | |
113 // | |
114 PlatformThread::Join(thread_); | |
115 | |
116 // The thread should NULL message_loop_ on exit. | |
117 DCHECK(!message_loop_); | |
118 | |
119 // The thread no longer needs to be joined. | |
120 started_ = false; | |
121 | |
122 stopping_ = false; | |
123 } | |
124 | |
125 void Thread::StopSoon() { | |
126 // We should only be called on the same thread that started us. | |
127 | |
128 // Reading thread_id_ without a lock can lead to a benign data race | |
129 // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer. | |
130 DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId()); | |
131 | |
132 if (stopping_ || !message_loop_) | |
133 return; | |
134 | |
135 stopping_ = true; | |
136 message_loop_->PostTask(FROM_HERE, new ThreadQuitTask()); | |
137 } | |
138 | |
139 void Thread::Run(MessageLoop* message_loop) { | |
140 message_loop->Run(); | |
141 } | |
142 | |
143 void Thread::ThreadMain() { | |
144 { | |
145 // The message loop for this thread. | |
146 MessageLoop message_loop(startup_data_->options.message_loop_type); | |
147 | |
148 // Complete the initialization of our Thread object. | |
149 thread_id_ = PlatformThread::CurrentId(); | |
150 PlatformThread::SetName(name_.c_str()); | |
151 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. | |
152 message_loop.set_thread_name(name_); | |
153 message_loop_ = &message_loop; | |
154 message_loop_proxy_ = MessageLoopProxy::CreateForCurrentThread(); | |
155 | |
156 // Let the thread do extra initialization. | |
157 // Let's do this before signaling we are started. | |
158 Init(); | |
159 | |
160 startup_data_->event.Signal(); | |
161 // startup_data_ can't be touched anymore since the starting thread is now | |
162 // unlocked. | |
163 | |
164 Run(message_loop_); | |
165 | |
166 // Let the thread do extra cleanup. | |
167 CleanUp(); | |
168 | |
169 // Assert that MessageLoop::Quit was called by ThreadQuitTask. | |
170 DCHECK(GetThreadWasQuitProperly()); | |
171 | |
172 // We can't receive messages anymore. | |
173 message_loop_ = NULL; | |
174 message_loop_proxy_ = NULL; | |
175 } | |
176 CleanUpAfterMessageLoopDestruction(); | |
177 thread_id_ = kInvalidThreadId; | |
178 } | |
179 | |
180 } // namespace base | |
OLD | NEW |