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

source code of flutter_engine/third_party/dart/runtime/vm/os_thread.cc