1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "vm/os_thread.h" |
6 | |
7 | #include "platform/address_sanitizer.h" |
8 | #include "platform/atomic.h" |
9 | #include "vm/lockers.h" |
10 | #include "vm/log.h" |
11 | #include "vm/thread_interrupter.h" |
12 | #include "vm/timeline.h" |
13 | |
14 | namespace dart { |
15 | |
16 | // The single thread local key which stores all the thread local data |
17 | // for a thread. |
18 | ThreadLocalKey OSThread::thread_key_ = kUnsetThreadLocalKey; |
19 | OSThread* OSThread::thread_list_head_ = NULL; |
20 | Mutex* OSThread::thread_list_lock_ = NULL; |
21 | bool OSThread::creation_enabled_ = false; |
22 | |
23 | #if defined(HAS_C11_THREAD_LOCAL) |
24 | thread_local ThreadState* OSThread::current_vm_thread_ = NULL; |
25 | #endif |
26 | |
27 | OSThread::OSThread() |
28 | : BaseThread(true), |
29 | id_(OSThread::GetCurrentThreadId()), |
30 | #if defined(DEBUG) |
31 | join_id_(kInvalidThreadJoinId), |
32 | #endif |
33 | #ifdef SUPPORT_TIMELINE |
34 | trace_id_(OSThread::GetCurrentThreadTraceId()), |
35 | #endif |
36 | name_(NULL), |
37 | timeline_block_lock_(), |
38 | timeline_block_(NULL), |
39 | thread_list_next_(NULL), |
40 | thread_interrupt_disabled_(1), // Thread interrupts disabled by default. |
41 | log_(new class Log()), |
42 | stack_base_(0), |
43 | stack_limit_(0), |
44 | stack_headroom_(0), |
45 | thread_(NULL) { |
46 | // Try to get accurate stack bounds from pthreads, etc. |
47 | if (!GetCurrentStackBounds(&stack_limit_, &stack_base_)) { |
48 | FATAL("Failed to retrieve stack bounds" ); |
49 | } |
50 | |
51 | stack_headroom_ = CalculateHeadroom(stack_base_ - stack_limit_); |
52 | |
53 | ASSERT(stack_base_ != 0); |
54 | ASSERT(stack_limit_ != 0); |
55 | ASSERT(stack_base_ > stack_limit_); |
56 | ASSERT(stack_base_ > GetCurrentStackPointer()); |
57 | ASSERT(stack_limit_ < GetCurrentStackPointer()); |
58 | RELEASE_ASSERT(HasStackHeadroom()); |
59 | } |
60 | |
61 | OSThread* OSThread::CreateOSThread() { |
62 | ASSERT(thread_list_lock_ != NULL); |
63 | MutexLocker ml(thread_list_lock_); |
64 | if (!creation_enabled_) { |
65 | return NULL; |
66 | } |
67 | OSThread* os_thread = new OSThread(); |
68 | AddThreadToListLocked(os_thread); |
69 | return os_thread; |
70 | } |
71 | |
72 | OSThread::~OSThread() { |
73 | if (!is_os_thread()) { |
74 | // If the embedder enters an isolate on this thread and does not exit the |
75 | // isolate, the thread local at thread_key_, which we are destructing here, |
76 | // will contain a dart::Thread instead of a dart::OSThread. |
77 | FATAL("Thread exited without calling Dart_ExitIsolate" ); |
78 | } |
79 | RemoveThreadFromList(this); |
80 | delete log_; |
81 | log_ = NULL; |
82 | #if defined(SUPPORT_TIMELINE) |
83 | if (Timeline::recorder() != NULL) { |
84 | Timeline::recorder()->FinishBlock(timeline_block_); |
85 | } |
86 | #endif |
87 | timeline_block_ = NULL; |
88 | free(name_); |
89 | } |
90 | |
91 | void OSThread::SetName(const char* name) { |
92 | MutexLocker ml(thread_list_lock_); |
93 | // Clear the old thread name. |
94 | if (name_ != NULL) { |
95 | free(name_); |
96 | name_ = NULL; |
97 | } |
98 | set_name(name); |
99 | } |
100 | |
101 | // Disable AdressSanitizer and SafeStack transformation on this function. In |
102 | // particular, taking the address of a local gives an address on the stack |
103 | // instead of an address in the shadow memory (AddressSanitizer) or the safe |
104 | // stack (SafeStack). |
105 | NO_SANITIZE_ADDRESS |
106 | NO_SANITIZE_SAFE_STACK |
107 | DART_NOINLINE |
108 | uword OSThread::GetCurrentStackPointer() { |
109 | uword stack_allocated_local = reinterpret_cast<uword>(&stack_allocated_local); |
110 | return stack_allocated_local; |
111 | } |
112 | |
113 | void OSThread::DisableThreadInterrupts() { |
114 | ASSERT(OSThread::Current() == this); |
115 | thread_interrupt_disabled_.fetch_add(1u); |
116 | } |
117 | |
118 | void OSThread::EnableThreadInterrupts() { |
119 | ASSERT(OSThread::Current() == this); |
120 | uintptr_t old = thread_interrupt_disabled_.fetch_sub(1u); |
121 | if (FLAG_profiler && (old == 1)) { |
122 | // We just decremented from 1 to 0. |
123 | // Make sure the thread interrupter is awake. |
124 | ThreadInterrupter::WakeUp(); |
125 | } |
126 | if (old == 0) { |
127 | // We just decremented from 0, this means we've got a mismatched pair |
128 | // of calls to EnableThreadInterrupts and DisableThreadInterrupts. |
129 | FATAL("Invalid call to OSThread::EnableThreadInterrupts()" ); |
130 | } |
131 | } |
132 | |
133 | bool OSThread::ThreadInterruptsEnabled() { |
134 | return thread_interrupt_disabled_ == 0; |
135 | } |
136 | |
137 | static void DeleteThread(void* thread) { |
138 | delete reinterpret_cast<OSThread*>(thread); |
139 | } |
140 | |
141 | void OSThread::Init() { |
142 | // Allocate the global OSThread lock. |
143 | if (thread_list_lock_ == NULL) { |
144 | thread_list_lock_ = new Mutex(); |
145 | } |
146 | ASSERT(thread_list_lock_ != NULL); |
147 | |
148 | // Create the thread local key. |
149 | if (thread_key_ == kUnsetThreadLocalKey) { |
150 | thread_key_ = CreateThreadLocal(DeleteThread); |
151 | } |
152 | ASSERT(thread_key_ != kUnsetThreadLocalKey); |
153 | |
154 | // Enable creation of OSThread structures in the VM. |
155 | EnableOSThreadCreation(); |
156 | |
157 | // Create a new OSThread strcture and set it as the TLS. |
158 | OSThread* os_thread = CreateOSThread(); |
159 | ASSERT(os_thread != NULL); |
160 | OSThread::SetCurrent(os_thread); |
161 | os_thread->set_name("Dart_Initialize" ); |
162 | } |
163 | |
164 | void OSThread::Cleanup() { |
165 | // We cannot delete the thread local key and thread list lock, yet. |
166 | // See the note on thread_list_lock_ in os_thread.h. |
167 | #if 0 |
168 | if (thread_list_lock_ != NULL) { |
169 | // Delete the thread local key. |
170 | ASSERT(thread_key_ != kUnsetThreadLocalKey); |
171 | DeleteThreadLocal(thread_key_); |
172 | thread_key_ = kUnsetThreadLocalKey; |
173 | |
174 | // Delete the global OSThread lock. |
175 | ASSERT(thread_list_lock_ != NULL); |
176 | delete thread_list_lock_; |
177 | thread_list_lock_ = NULL; |
178 | } |
179 | #endif |
180 | } |
181 | |
182 | OSThread* OSThread::CreateAndSetUnknownThread() { |
183 | ASSERT(OSThread::GetCurrentTLS() == NULL); |
184 | OSThread* os_thread = CreateOSThread(); |
185 | if (os_thread != NULL) { |
186 | OSThread::SetCurrent(os_thread); |
187 | os_thread->set_name("Unknown" ); |
188 | } |
189 | return os_thread; |
190 | } |
191 | |
192 | bool OSThread::IsThreadInList(ThreadId id) { |
193 | if (id == OSThread::kInvalidThreadId) { |
194 | return false; |
195 | } |
196 | OSThreadIterator it; |
197 | while (it.HasNext()) { |
198 | ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); |
199 | OSThread* t = it.Next(); |
200 | // An address test is not sufficient because the allocator may recycle |
201 | // the address for another Thread. Test against the thread's id. |
202 | if (t->id() == id) { |
203 | return true; |
204 | } |
205 | } |
206 | return false; |
207 | } |
208 | |
209 | void OSThread::DisableOSThreadCreation() { |
210 | MutexLocker ml(thread_list_lock_); |
211 | creation_enabled_ = false; |
212 | } |
213 | |
214 | void OSThread::EnableOSThreadCreation() { |
215 | MutexLocker ml(thread_list_lock_); |
216 | creation_enabled_ = true; |
217 | } |
218 | |
219 | OSThread* OSThread::GetOSThreadFromThread(ThreadState* thread) { |
220 | ASSERT(thread->os_thread() != NULL); |
221 | return thread->os_thread(); |
222 | } |
223 | |
224 | void OSThread::AddThreadToListLocked(OSThread* thread) { |
225 | ASSERT(thread != NULL); |
226 | ASSERT(thread_list_lock_ != NULL); |
227 | ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); |
228 | ASSERT(creation_enabled_); |
229 | ASSERT(thread->thread_list_next_ == NULL); |
230 | |
231 | #if defined(DEBUG) |
232 | { |
233 | // Ensure that we aren't already in the list. |
234 | OSThread* current = thread_list_head_; |
235 | while (current != NULL) { |
236 | ASSERT(current != thread); |
237 | current = current->thread_list_next_; |
238 | } |
239 | } |
240 | #endif |
241 | |
242 | // Insert at head of list. |
243 | thread->thread_list_next_ = thread_list_head_; |
244 | thread_list_head_ = thread; |
245 | } |
246 | |
247 | void OSThread::RemoveThreadFromList(OSThread* thread) { |
248 | bool final_thread = false; |
249 | { |
250 | ASSERT(thread != NULL); |
251 | ASSERT(thread_list_lock_ != NULL); |
252 | MutexLocker ml(thread_list_lock_); |
253 | OSThread* current = thread_list_head_; |
254 | OSThread* previous = NULL; |
255 | |
256 | // Scan across list and remove |thread|. |
257 | while (current != NULL) { |
258 | if (current == thread) { |
259 | // We found |thread|, remove from list. |
260 | if (previous == NULL) { |
261 | thread_list_head_ = thread->thread_list_next_; |
262 | } else { |
263 | previous->thread_list_next_ = current->thread_list_next_; |
264 | } |
265 | thread->thread_list_next_ = NULL; |
266 | final_thread = !creation_enabled_ && (thread_list_head_ == NULL); |
267 | break; |
268 | } |
269 | previous = current; |
270 | current = current->thread_list_next_; |
271 | } |
272 | } |
273 | // Check if this is the last thread. The last thread does a cleanup |
274 | // which removes the thread local key and the associated mutex. |
275 | if (final_thread) { |
276 | Cleanup(); |
277 | } |
278 | } |
279 | |
280 | void OSThread::SetCurrentTLS(BaseThread* value) { |
281 | // Provides thread-local destructors. |
282 | SetThreadLocal(thread_key_, reinterpret_cast<uword>(value)); |
283 | |
284 | #if defined(HAS_C11_THREAD_LOCAL) |
285 | // Allows the C compiler more freedom to optimize. |
286 | if ((value != NULL) && !value->is_os_thread()) { |
287 | current_vm_thread_ = static_cast<Thread*>(value); |
288 | } else { |
289 | current_vm_thread_ = NULL; |
290 | } |
291 | #endif |
292 | } |
293 | |
294 | OSThreadIterator::OSThreadIterator() { |
295 | ASSERT(OSThread::thread_list_lock_ != NULL); |
296 | // Lock the thread list while iterating. |
297 | OSThread::thread_list_lock_->Lock(); |
298 | next_ = OSThread::thread_list_head_; |
299 | } |
300 | |
301 | OSThreadIterator::~OSThreadIterator() { |
302 | ASSERT(OSThread::thread_list_lock_ != NULL); |
303 | // Unlock the thread list when done. |
304 | OSThread::thread_list_lock_->Unlock(); |
305 | } |
306 | |
307 | bool OSThreadIterator::HasNext() const { |
308 | ASSERT(OSThread::thread_list_lock_ != NULL); |
309 | ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); |
310 | return next_ != NULL; |
311 | } |
312 | |
313 | OSThread* OSThreadIterator::Next() { |
314 | ASSERT(OSThread::thread_list_lock_ != NULL); |
315 | ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); |
316 | OSThread* current = next_; |
317 | next_ = next_->thread_list_next_; |
318 | return current; |
319 | } |
320 | |
321 | } // namespace dart |
322 | |