Flutter Engine
The Flutter Engine
os_thread.h
Go to the documentation of this file.
1// Copyright (c) 2012, 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#ifndef RUNTIME_VM_OS_THREAD_H_
6#define RUNTIME_VM_OS_THREAD_H_
7
8#include "platform/atomic.h"
9#include "platform/globals.h"
10#include "platform/safe_stack.h"
11#include "platform/utils.h"
12#include "vm/allocation.h"
13#include "vm/globals.h"
14
15// Declare the OS-specific types ahead of defining the generic classes.
16#if defined(DART_USE_ABSL)
17#include "vm/os_thread_absl.h"
18#elif defined(DART_HOST_OS_ANDROID)
20#elif defined(DART_HOST_OS_FUCHSIA)
22#elif defined(DART_HOST_OS_LINUX)
23#include "vm/os_thread_linux.h"
24#elif defined(DART_HOST_OS_MACOS)
25#include "vm/os_thread_macos.h"
26#elif defined(DART_HOST_OS_WINDOWS)
27#include "vm/os_thread_win.h"
28#else
29#error Unknown target os.
30#endif
31
32namespace dart {
33
34// Forward declarations.
35class Log;
36class Mutex;
37class ThreadState;
38class TimelineEventBlock;
39
40class Mutex {
41 public:
42 explicit Mutex(NOT_IN_PRODUCT(const char* name = "anonymous mutex"));
44
45 bool IsOwnedByCurrentThread() const;
46
47 private:
48 void Lock();
49 bool TryLock(); // Returns false if lock is busy and locking failed.
50 void Unlock();
51
52 MutexData data_;
53 NOT_IN_PRODUCT(const char* name_);
54#if defined(DEBUG)
55 ThreadId owner_;
56#endif // defined(DEBUG)
57
58 friend class MallocLocker;
59 friend class MutexLocker;
61 friend class OSThreadIterator;
64 friend class PageSpace;
65 friend void Dart_TestMutex();
67};
68
70 public:
71 bool is_os_thread() const { return is_os_thread_; }
72
73 private:
74 explicit BaseThread(bool is_os_thread) : is_os_thread_(is_os_thread) {}
75 virtual ~BaseThread() {}
76
77 bool is_os_thread_;
78
79 friend class ThreadState;
80 friend class OSThread;
81
83};
84
85// Low-level operations on OS platform threads.
86class OSThread : public BaseThread {
87 public:
88 static const uword kInvalidStackLimit = ~static_cast<uword>(0);
89
90 // The constructor of OSThread is never called directly, instead we call
91 // this factory style method 'CreateOSThread' to create OSThread structures.
92 // The method can return a nullptr if the Dart VM is in shutdown mode.
93 static OSThread* CreateOSThread();
94 ~OSThread();
95
96 ThreadId id() const {
98 return id_;
99 }
100
101#ifdef SUPPORT_TIMELINE
102 ThreadId trace_id() const {
104 return trace_id_;
105 }
106#endif
107
108 const char* name() const { return name_; }
109
110 void SetName(const char* name);
111
112 Mutex* timeline_block_lock() const { return &timeline_block_lock_; }
113
114 // Only safe to access when holding |timeline_block_lock_|.
115 TimelineEventBlock* TimelineBlockLocked() const {
116 ASSERT(timeline_block_lock()->IsOwnedByCurrentThread());
117 return timeline_block_;
118 }
119
120 // Only safe to access when holding |timeline_block_lock_|.
121 void SetTimelineBlockLocked(TimelineEventBlock* block) {
122 ASSERT(timeline_block_lock()->IsOwnedByCurrentThread());
123 timeline_block_ = block;
124 }
125
126 Log* log() const { return log_; }
127
128 uword stack_base() const { return stack_base_; }
129 uword stack_limit() const { return stack_limit_; }
130 uword overflow_stack_limit() const { return stack_limit_ + stack_headroom_; }
131
132 bool HasStackHeadroom() { return HasStackHeadroom(stack_headroom_); }
133 bool HasStackHeadroom(intptr_t headroom) {
134 return GetCurrentStackPointer() > (stack_limit_ + headroom);
135 }
136
137#ifdef SUPPORT_TIMELINE
138 static ThreadId GetCurrentThreadTraceId();
139#endif // SUPPORT_TIMELINE
140
141 // May fail for the main thread on Linux if resources are low.
142 static bool GetCurrentStackBounds(uword* lower, uword* upper);
143
144 // Returns the current C++ stack pointer. Equivalent taking the address of a
145 // stack allocated local, but plays well with AddressSanitizer and SafeStack.
146 // Accurate enough for stack overflow checks but not accurate enough for
147 // alignment checks.
149
150#if defined(USING_SAFE_STACK)
151 static uword GetCurrentSafestackPointer();
152 static void SetCurrentSafestackPointer(uword ssp);
153#endif
154
155#if !defined(PRODUCT)
156 // Used to temporarily disable or enable thread interrupts.
160#endif // !defined(PRODUCT)
161
162 // The currently executing thread, or nullptr if not yet initialized.
164 BaseThread* thread = GetCurrentTLS();
165 OSThread* os_thread = nullptr;
166 if (thread != nullptr) {
167 if (thread->is_os_thread()) {
168 os_thread = reinterpret_cast<OSThread*>(thread);
169 } else {
170 ThreadState* vm_thread = reinterpret_cast<ThreadState*>(thread);
171 os_thread = GetOSThreadFromThread(vm_thread);
172 }
173 }
174 return os_thread;
175 }
176
177 // The currently executing thread. If there is no currently executing thread,
178 // a new OSThread is created and returned.
179 static OSThread* Current() {
180 OSThread* os_thread = TryCurrent();
181 if (os_thread == nullptr) {
182 os_thread = CreateAndSetUnknownThread();
183 }
184 return os_thread;
185 }
186 static void SetCurrent(OSThread* current) { SetCurrentTLS(current); }
187
188 static ThreadState* CurrentVMThread() { return current_vm_thread_; }
189#if defined(DEBUG)
190 static void SetCurrentVMThread(ThreadState* thread) {
191 current_vm_thread_ = thread;
192 }
193#endif
194
195 // TODO(5411455): Use flag to override default value and Validate the
196 // stack size by querying OS.
198 intptr_t headroom =
199 OSThread::CalculateHeadroom(OSThread::GetMaxStackSize());
200 ASSERT(headroom < OSThread::GetMaxStackSize());
201 uword stack_size = OSThread::GetMaxStackSize() - headroom;
202 return stack_size;
203 }
205 return reinterpret_cast<BaseThread*>(OSThread::GetThreadLocal(thread_key_));
206 }
207 static void SetCurrentTLS(BaseThread* value);
208
209 typedef void (*ThreadStartFunction)(uword parameter);
210 typedef void (*ThreadDestructor)(void* parameter);
211
212 // Start a thread running the specified function. Returns 0 if the
213 // thread started successfully and a system specific error code if
214 // the thread failed to start.
215 static int Start(const char* name,
217 uword parameter);
218
220 ThreadDestructor destructor = nullptr);
223 return ThreadInlineImpl::GetThreadLocal(key);
224 }
227 static intptr_t GetMaxStackSize();
228 static void Join(ThreadJoinId id);
229 static intptr_t ThreadIdToIntPtr(ThreadId id);
230 static ThreadId ThreadIdFromIntPtr(intptr_t id);
231 static bool Compare(ThreadId a, ThreadId b);
232
233 // This function can be called only once per OSThread, and should only be
234 // called when the returned id will eventually be passed to OSThread::Join().
236
237 // Called at VM startup and shutdown.
238 static void Init();
239
240 static bool IsThreadInList(ThreadId id);
241
242 static void DisableOSThreadCreation();
243 static void EnableOSThreadCreation();
244
245 static constexpr intptr_t kStackSizeBufferMax = (16 * KB * kWordSize);
246 static constexpr float kStackSizeBufferFraction = 0.5;
247
250
251 private:
252 // The constructor is private as CreateOSThread should be used
253 // to create a new OSThread structure.
254 OSThread();
255
256 // These methods should not be used in a generic way and hence
257 // are private, they have been added to solve the problem of
258 // accessing the VM thread structure from an OSThread object
259 // in the windows thread interrupter which is used for profiling.
260 // We could eliminate this requirement if the windows thread interrupter
261 // is implemented differently.
262 ThreadState* thread() const { return thread_; }
263 void set_thread(ThreadState* value) { thread_ = value; }
264
265 static void Cleanup();
266
267 // Retrieves the name given to the current thread at the OS level and returns
268 // it as a heap-allocated string that must eventually be freed by the caller
269 // using free. Returns |nullptr| when the name cannot be retrieved.
270 static char* GetCurrentThreadName();
271 static OSThread* GetOSThreadFromThread(ThreadState* thread);
272 static void AddThreadToListLocked(OSThread* thread);
273 static void RemoveThreadFromList(OSThread* thread);
274 static OSThread* CreateAndSetUnknownThread();
275
276 static uword CalculateHeadroom(uword stack_size) {
277 uword headroom = kStackSizeBufferFraction * stack_size;
278 return (headroom > kStackSizeBufferMax) ? kStackSizeBufferMax : headroom;
279 }
280
281 static ThreadLocalKey thread_key_;
282
283 const ThreadId id_;
284#if defined(DEBUG)
285 // In DEBUG mode we use this field to ensure that GetCurrentThreadJoinId is
286 // only called once per OSThread.
288#endif
289#ifdef SUPPORT_TIMELINE
290 const ThreadId trace_id_; // Used to interface with tracing tools.
291#endif
292 char* name_; // A name for this thread.
293
294 mutable Mutex timeline_block_lock_;
295 // The block that the timeline recorder has permitted this thread to write
296 // events to.
297 TimelineEventBlock* timeline_block_ = nullptr;
298
299 // All |Thread|s are registered in the thread list.
300 OSThread* thread_list_next_ = nullptr;
301
302#if !defined(PRODUCT)
303 // Thread interrupts disabled by default.
304 RelaxedAtomic<uintptr_t> thread_interrupt_disabled_ = {1};
305 bool prepared_for_interrupts_ = false;
306 void* thread_interrupter_state_ = nullptr;
307#endif // !defined(PRODUCT)
308
309 Log* log_;
310 uword stack_base_ = 0;
311 uword stack_limit_ = 0;
312 uword stack_headroom_ = 0;
313 ThreadState* thread_ = nullptr;
314 // The ThreadPool::Worker which owns this OSThread. If this OSThread was not
315 // started by a ThreadPool it will be nullptr. This TLS value is not
316 // protected and should only be read/written by the OSThread itself.
317 void* owning_thread_pool_worker_ = nullptr;
318
319 // thread_list_lock_ cannot have a static lifetime because the order in which
320 // destructors run is undefined. At the moment this lock cannot be deleted
321 // either since otherwise, if a thread only begins to run after we have
322 // started to run TLS destructors for a call to exit(), there will be a race
323 // on its deletion in CreateOSThread().
324 static Mutex* thread_list_lock_;
325 static OSThread* thread_list_head_;
326 static bool creation_enabled_;
327
328 // Inline initialization is important for avoiding unnecessary TLS
329 // initialization checks at each use.
330 static inline thread_local ThreadState* current_vm_thread_ = nullptr;
331
332 friend class Thread; // to access set_thread(Thread*).
333 friend class OSThreadIterator;
337 friend class ThreadPool; // to access owning_thread_pool_worker_
338};
339
340// Note that this takes the thread list lock, prohibiting threads from coming
341// on- or off-line.
343 public:
346
347 // Returns false when there are no more threads left.
348 bool HasNext() const;
349
350 // Returns the current thread and moves forward.
351 OSThread* Next();
352
353 private:
354 OSThread* next_;
355};
356
357class Monitor {
358 public:
360
361 static constexpr int64_t kNoTimeout = 0;
362
365
366#if defined(DEBUG)
367 bool IsOwnedByCurrentThread() const {
368 return owner_ == OSThread::GetCurrentThreadId();
369 }
370#else
372 UNREACHABLE();
373 return false;
374 }
375#endif
376
377 private:
378 bool TryEnter(); // Returns false if lock is busy and locking failed.
379 void Enter();
380 void Exit();
381
382 // Wait for notification or timeout.
383 WaitResult Wait(int64_t millis);
384 WaitResult WaitMicros(int64_t micros);
385
386 // Notify waiting threads.
387 void Notify();
388 void NotifyAll();
389
390 MonitorData data_; // OS-specific data.
391#if defined(DEBUG)
392 ThreadId owner_;
393#endif // defined(DEBUG)
394
395 friend class MonitorLocker;
397 friend class SafepointRwLock;
398 friend void Dart_TestMonitor();
400};
401
402inline bool Mutex::IsOwnedByCurrentThread() const {
403#if defined(DEBUG)
404 return owner_ == OSThread::GetCurrentThreadId();
405#else
406 UNREACHABLE();
407 return false;
408#endif
409}
410
411// Mark when we are running in a signal handler (Linux, Android) or with a
412// suspended thread (Windows, Mac, Fuchia). During this time, we cannot take
413// locks, access Thread/Isolate::Current(), or use malloc.
415#if defined(DEBUG)
416 public:
418 ASSERT(!in_thread_interrupt_scope_); // We don't use nested signals.
419 in_thread_interrupt_scope_ = true;
420
421 // Poison attempts to use Thread::Current. This is much cheaper than adding
422 // an assert in Thread::Current itself.
423 saved_current_vm_thread_ = OSThread::CurrentVMThread();
424 OSThread::SetCurrentVMThread(reinterpret_cast<ThreadState*>(0xabababab));
425 }
426
428 OSThread::SetCurrentVMThread(saved_current_vm_thread_);
429 in_thread_interrupt_scope_ = false;
430 }
431
432 static bool in_thread_interrupt_scope() { return in_thread_interrupt_scope_; }
433
434 private:
435 ThreadState* saved_current_vm_thread_;
436 static inline thread_local bool in_thread_interrupt_scope_ = false;
437#endif // DEBUG
438};
439
440} // namespace dart
441
442#endif // RUNTIME_VM_OS_THREAD_H_
#define UNREACHABLE()
Definition: assert.h:248
friend class ThreadState
Definition: os_thread.h:79
bool is_os_thread() const
Definition: os_thread.h:71
virtual ~BaseThread()
Definition: os_thread.h:75
Definition: log.h:27
bool IsOwnedByCurrentThread() const
Definition: os_thread.h:371
friend void Dart_TestMonitor()
static constexpr int64_t kNoTimeout
Definition: os_thread.h:361
Mutex(NOT_IN_PRODUCT(const char *name="anonymous mutex"))
bool IsOwnedByCurrentThread() const
Definition: os_thread.h:402
friend class TimelineEventRingRecorder
Definition: os_thread.h:63
friend void Dart_TestMutex()
friend class TimelineEventRecorder
Definition: os_thread.h:62
friend class MallocLocker
Definition: os_thread.h:58
bool HasNext() const
Definition: os_thread.cc:343
bool HasStackHeadroom(intptr_t headroom)
Definition: os_thread.h:133
uword stack_base() const
Definition: os_thread.h:128
static constexpr intptr_t kStackSizeBufferMax
Definition: os_thread.h:245
static void DeleteThreadLocal(ThreadLocalKey key)
static int Start(const char *name, ThreadStartFunction function, uword parameter)
const char * name() const
Definition: os_thread.h:108
ThreadId id() const
Definition: os_thread.h:96
static bool GetCurrentStackBounds(uword *lower, uword *upper)
Log * log() const
Definition: os_thread.h:126
bool ThreadInterruptsEnabled()
Definition: os_thread.cc:167
void DisableThreadInterrupts()
Definition: os_thread.cc:143
static OSThread * CreateOSThread()
Definition: os_thread.cc:66
void SetTimelineBlockLocked(TimelineEventBlock *block)
Definition: os_thread.h:121
static void SetCurrent(OSThread *current)
Definition: os_thread.h:186
static uword GetThreadLocal(ThreadLocalKey key)
Definition: os_thread.h:222
void(* ThreadDestructor)(void *parameter)
Definition: os_thread.h:210
void SetName(const char *name)
Definition: os_thread.cc:115
static uword GetCurrentStackPointer()
Definition: os_thread.cc:132
static OSThread * TryCurrent()
Definition: os_thread.h:163
static ThreadId ThreadIdFromIntPtr(intptr_t id)
static const uword kInvalidStackLimit
Definition: os_thread.h:88
static void SetCurrentTLS(BaseThread *value)
Definition: os_thread.cc:318
static ThreadId GetCurrentThreadId()
TimelineEventBlock * TimelineBlockLocked() const
Definition: os_thread.h:115
static void Join(ThreadJoinId id)
static ThreadState * CurrentVMThread()
Definition: os_thread.h:188
friend class ThreadInterrupterFuchsia
Definition: os_thread.h:334
static bool Compare(ThreadId a, ThreadId b)
static uword GetSpecifiedStackSize()
Definition: os_thread.h:197
static ThreadLocalKey CreateThreadLocal(ThreadDestructor destructor=nullptr)
bool HasStackHeadroom()
Definition: os_thread.h:132
static void Init()
Definition: os_thread.cc:177
static OSThread * Current()
Definition: os_thread.h:179
static void EnableOSThreadCreation()
Definition: os_thread.cc:252
static void DisableOSThreadCreation()
Definition: os_thread.cc:247
friend class ThreadInterrupterWin
Definition: os_thread.h:336
static BaseThread * GetCurrentTLS()
Definition: os_thread.h:204
uword stack_limit() const
Definition: os_thread.h:129
friend class ThreadInterrupterMacOS
Definition: os_thread.h:335
static const ThreadId kInvalidThreadId
Definition: os_thread.h:248
uword overflow_stack_limit() const
Definition: os_thread.h:130
static ThreadJoinId GetCurrentThreadJoinId(OSThread *thread)
void EnableThreadInterrupts()
Definition: os_thread.cc:148
Mutex * timeline_block_lock() const
Definition: os_thread.h:112
static bool IsThreadInList(ThreadId id)
Definition: os_thread.cc:230
void(* ThreadStartFunction)(uword parameter)
Definition: os_thread.h:209
static void SetThreadLocal(ThreadLocalKey key, uword value)
static intptr_t ThreadIdToIntPtr(ThreadId id)
static constexpr float kStackSizeBufferFraction
Definition: os_thread.h:246
static intptr_t GetMaxStackSize()
static const ThreadJoinId kInvalidThreadJoinId
Definition: os_thread.h:249
#define ASSERT(E)
static bool b
struct MyStruct a[10]
uint8_t value
Dart_NativeFunction function
Definition: fuchsia.cc:51
void Log(const char *format,...) SK_PRINTF_LIKE(1
Definition: TestRunner.cpp:137
Definition: dart_vm.cc:33
const char *const name
pthread_t ThreadJoinId
constexpr intptr_t KB
Definition: globals.h:528
uintptr_t uword
Definition: globals.h:501
constexpr intptr_t kWordSize
Definition: globals.h:509
pthread_key_t ThreadLocalKey
pthread_t ThreadId
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)
Definition: globals.h:593
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581