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