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// On iOS, thread_local requires iOS 9+.
16#if !HOST_OS_IOS
17#define HAS_C11_THREAD_LOCAL 1
18#endif
19
20// Declare the OS-specific types ahead of defining the generic classes.
21#if defined(HOST_OS_ANDROID)
22#include "vm/os_thread_android.h"
23#elif defined(HOST_OS_FUCHSIA)
24#include "vm/os_thread_fuchsia.h"
25#elif defined(HOST_OS_LINUX)
26#include "vm/os_thread_linux.h"
27#elif defined(HOST_OS_MACOS)
28#include "vm/os_thread_macos.h"
29#elif defined(HOST_OS_WINDOWS)
30#include "vm/os_thread_win.h"
31#else
32#error Unknown target os.
33#endif
34
35namespace dart {
36
37// Forward declarations.
38class Log;
39class Mutex;
40class ThreadState;
41class TimelineEventBlock;
42
43class Mutex {
44 public:
45 explicit Mutex(NOT_IN_PRODUCT(const char* name = "anonymous mutex"));
46 ~Mutex();
47
48 bool IsOwnedByCurrentThread() const;
49
50 private:
51 void Lock();
52 bool TryLock(); // Returns false if lock is busy and locking failed.
53 void Unlock();
54
55 MutexData data_;
56 NOT_IN_PRODUCT(const char* name_);
57#if defined(DEBUG)
58 ThreadId owner_;
59#endif // defined(DEBUG)
60
61 friend class MallocLocker;
62 friend class MutexLocker;
63 friend class SafepointMutexLocker;
64 friend class OSThreadIterator;
65 friend class TimelineEventBlockIterator;
66 friend class TimelineEventRecorder;
67 friend class PageSpace;
68 friend void Dart_TestMutex();
69 DISALLOW_COPY_AND_ASSIGN(Mutex);
70};
71
72class BaseThread {
73 public:
74 bool is_os_thread() const { return is_os_thread_; }
75
76 private:
77 explicit BaseThread(bool is_os_thread) : is_os_thread_(is_os_thread) {}
78 virtual ~BaseThread() {}
79
80 bool is_os_thread_;
81
82 friend class ThreadState;
83 friend class OSThread;
84
85 DISALLOW_IMPLICIT_CONSTRUCTORS(BaseThread);
86};
87
88// Low-level operations on OS platform threads.
89class OSThread : public BaseThread {
90 public:
91 // The constructor of OSThread is never called directly, instead we call
92 // this factory style method 'CreateOSThread' to create OSThread structures.
93 // The method can return a NULL if the Dart VM is in shutdown mode.
94 static OSThread* CreateOSThread();
95 ~OSThread();
96
97 ThreadId id() const {
98 ASSERT(id_ != OSThread::kInvalidThreadId);
99 return id_;
100 }
101
102#ifdef SUPPORT_TIMELINE
103 ThreadId trace_id() const {
104 ASSERT(trace_id_ != OSThread::kInvalidThreadId);
105 return trace_id_;
106 }
107#endif
108
109 const char* name() const { return name_; }
110
111 void SetName(const char* name);
112
113 void set_name(const char* name) {
114 ASSERT(OSThread::Current() == this);
115 ASSERT(name_ == NULL);
116 ASSERT(name != NULL);
117 name_ = Utils::StrDup(name);
118 }
119
120 Mutex* timeline_block_lock() const { return &timeline_block_lock_; }
121
122 // Only safe to access when holding |timeline_block_lock_|.
123 TimelineEventBlock* timeline_block() const { return timeline_block_; }
124
125 // Only safe to access when holding |timeline_block_lock_|.
126 void set_timeline_block(TimelineEventBlock* block) {
127 timeline_block_ = block;
128 }
129
130 Log* log() const { return log_; }
131
132 uword stack_base() const { return stack_base_; }
133 uword stack_limit() const { return stack_limit_; }
134 uword overflow_stack_limit() const { return stack_limit_ + stack_headroom_; }
135
136 bool HasStackHeadroom() { return HasStackHeadroom(stack_headroom_); }
137 bool HasStackHeadroom(intptr_t headroom) {
138 return GetCurrentStackPointer() > (stack_limit_ + headroom);
139 }
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.
148 static uword GetCurrentStackPointer();
149
150#if defined(USING_SAFE_STACK)
151 static uword GetCurrentSafestackPointer();
152 static void SetCurrentSafestackPointer(uword ssp);
153#endif
154
155 // Used to temporarily disable or enable thread interrupts.
156 void DisableThreadInterrupts();
157 void EnableThreadInterrupts();
158 bool ThreadInterruptsEnabled();
159
160 // The currently executing thread, or NULL if not yet initialized.
161 static OSThread* TryCurrent() {
162 BaseThread* thread = GetCurrentTLS();
163 OSThread* os_thread = NULL;
164 if (thread != NULL) {
165 if (thread->is_os_thread()) {
166 os_thread = reinterpret_cast<OSThread*>(thread);
167 } else {
168 ThreadState* vm_thread = reinterpret_cast<ThreadState*>(thread);
169 os_thread = GetOSThreadFromThread(vm_thread);
170 }
171 }
172 return os_thread;
173 }
174
175 // The currently executing thread. If there is no currently executing thread,
176 // a new OSThread is created and returned.
177 static OSThread* Current() {
178 OSThread* os_thread = TryCurrent();
179 if (os_thread == NULL) {
180 os_thread = CreateAndSetUnknownThread();
181 }
182 return os_thread;
183 }
184 static void SetCurrent(OSThread* current) { SetCurrentTLS(current); }
185
186#if defined(HAS_C11_THREAD_LOCAL)
187 static ThreadState* CurrentVMThread() { return current_vm_thread_; }
188#endif
189
190 // TODO(5411455): Use flag to override default value and Validate the
191 // stack size by querying OS.
192 static uword GetSpecifiedStackSize() {
193 intptr_t headroom =
194 OSThread::CalculateHeadroom(OSThread::GetMaxStackSize());
195 ASSERT(headroom < OSThread::GetMaxStackSize());
196 uword stack_size = OSThread::GetMaxStackSize() - headroom;
197 return stack_size;
198 }
199 static BaseThread* GetCurrentTLS() {
200 return reinterpret_cast<BaseThread*>(OSThread::GetThreadLocal(thread_key_));
201 }
202 static void SetCurrentTLS(BaseThread* value);
203
204 typedef void (*ThreadStartFunction)(uword parameter);
205 typedef void (*ThreadDestructor)(void* parameter);
206
207 // Start a thread running the specified function. Returns 0 if the
208 // thread started successfuly and a system specific error code if
209 // the thread failed to start.
210 static int Start(const char* name,
211 ThreadStartFunction function,
212 uword parameter);
213
214 static ThreadLocalKey CreateThreadLocal(ThreadDestructor destructor = NULL);
215 static void DeleteThreadLocal(ThreadLocalKey key);
216 static uword GetThreadLocal(ThreadLocalKey key) {
217 return ThreadInlineImpl::GetThreadLocal(key);
218 }
219 static ThreadId GetCurrentThreadId();
220 static void SetThreadLocal(ThreadLocalKey key, uword value);
221 static intptr_t GetMaxStackSize();
222 static void Join(ThreadJoinId id);
223 static intptr_t ThreadIdToIntPtr(ThreadId id);
224 static ThreadId ThreadIdFromIntPtr(intptr_t id);
225 static bool Compare(ThreadId a, ThreadId b);
226
227 // This function can be called only once per OSThread, and should only be
228 // called when the retunred id will eventually be passed to OSThread::Join().
229 static ThreadJoinId GetCurrentThreadJoinId(OSThread* thread);
230
231 // Called at VM startup and shutdown.
232 static void Init();
233
234 static bool IsThreadInList(ThreadId id);
235
236 static void DisableOSThreadCreation();
237 static void EnableOSThreadCreation();
238
239 static const intptr_t kStackSizeBufferMax = (16 * KB * kWordSize);
240 static constexpr float kStackSizeBufferFraction = 0.5;
241
242 static const ThreadId kInvalidThreadId;
243 static const ThreadJoinId kInvalidThreadJoinId;
244
245 private:
246 // The constructor is private as CreateOSThread should be used
247 // to create a new OSThread structure.
248 OSThread();
249
250 // These methods should not be used in a generic way and hence
251 // are private, they have been added to solve the problem of
252 // accessing the VM thread structure from an OSThread object
253 // in the windows thread interrupter which is used for profiling.
254 // We could eliminate this requirement if the windows thread interrupter
255 // is implemented differently.
256 ThreadState* thread() const { return thread_; }
257 void set_thread(ThreadState* value) { thread_ = value; }
258
259 static void Cleanup();
260#ifdef SUPPORT_TIMELINE
261 static ThreadId GetCurrentThreadTraceId();
262#endif // PRODUCT
263 static OSThread* GetOSThreadFromThread(ThreadState* thread);
264 static void AddThreadToListLocked(OSThread* thread);
265 static void RemoveThreadFromList(OSThread* thread);
266 static OSThread* CreateAndSetUnknownThread();
267
268 static uword CalculateHeadroom(uword stack_size) {
269 uword headroom = kStackSizeBufferFraction * stack_size;
270 return (headroom > kStackSizeBufferMax) ? kStackSizeBufferMax : headroom;
271 }
272
273 static ThreadLocalKey thread_key_;
274
275 const ThreadId id_;
276#if defined(DEBUG)
277 // In DEBUG mode we use this field to ensure that GetCurrentThreadJoinId is
278 // only called once per OSThread.
279 ThreadJoinId join_id_;
280#endif
281#ifdef SUPPORT_TIMELINE
282 const ThreadId trace_id_; // Used to interface with tracing tools.
283#endif
284 char* name_; // A name for this thread.
285
286 mutable Mutex timeline_block_lock_;
287 TimelineEventBlock* timeline_block_;
288
289 // All |Thread|s are registered in the thread list.
290 OSThread* thread_list_next_;
291
292 RelaxedAtomic<uintptr_t> thread_interrupt_disabled_;
293 Log* log_;
294 uword stack_base_;
295 uword stack_limit_;
296 uword stack_headroom_;
297 ThreadState* thread_;
298 // The ThreadPool::Worker which owns this OSThread. If this OSThread was not
299 // started by a ThreadPool it will be nullptr. This TLS value is not
300 // protected and should only be read/written by the OSThread itself.
301 void* owning_thread_pool_worker_ = nullptr;
302
303 // thread_list_lock_ cannot have a static lifetime because the order in which
304 // destructors run is undefined. At the moment this lock cannot be deleted
305 // either since otherwise, if a thread only begins to run after we have
306 // started to run TLS destructors for a call to exit(), there will be a race
307 // on its deletion in CreateOSThread().
308 static Mutex* thread_list_lock_;
309 static OSThread* thread_list_head_;
310 static bool creation_enabled_;
311
312#if defined(HAS_C11_THREAD_LOCAL)
313 static thread_local ThreadState* current_vm_thread_;
314#endif
315
316 friend class IsolateGroup; // to access set_thread(Thread*).
317 friend class OSThreadIterator;
318 friend class ThreadInterrupterWin;
319 friend class ThreadInterrupterFuchsia;
320 friend class ThreadPool; // to access owning_thread_pool_worker_
321};
322
323// Note that this takes the thread list lock, prohibiting threads from coming
324// on- or off-line.
325class OSThreadIterator : public ValueObject {
326 public:
327 OSThreadIterator();
328 ~OSThreadIterator();
329
330 // Returns false when there are no more threads left.
331 bool HasNext() const;
332
333 // Returns the current thread and moves forward.
334 OSThread* Next();
335
336 private:
337 OSThread* next_;
338};
339
340class Monitor {
341 public:
342 enum WaitResult { kNotified, kTimedOut };
343
344 static const int64_t kNoTimeout = 0;
345
346 Monitor();
347 ~Monitor();
348
349#if defined(DEBUG)
350 bool IsOwnedByCurrentThread() const {
351 return owner_ == OSThread::GetCurrentThreadId();
352 }
353#else
354 bool IsOwnedByCurrentThread() const {
355 UNREACHABLE();
356 return false;
357 }
358#endif
359
360 private:
361 bool TryEnter(); // Returns false if lock is busy and locking failed.
362 void Enter();
363 void Exit();
364
365 // Wait for notification or timeout.
366 WaitResult Wait(int64_t millis);
367 WaitResult WaitMicros(int64_t micros);
368
369 // Notify waiting threads.
370 void Notify();
371 void NotifyAll();
372
373 MonitorData data_; // OS-specific data.
374#if defined(DEBUG)
375 ThreadId owner_;
376#endif // defined(DEBUG)
377
378 friend class MonitorLocker;
379 friend class SafepointMonitorLocker;
380 friend void Dart_TestMonitor();
381 DISALLOW_COPY_AND_ASSIGN(Monitor);
382};
383
384inline bool Mutex::IsOwnedByCurrentThread() const {
385#if defined(DEBUG)
386 return owner_ == OSThread::GetCurrentThreadId();
387#else
388 UNREACHABLE();
389 return false;
390#endif
391}
392
393} // namespace dart
394
395#endif // RUNTIME_VM_OS_THREAD_H_
396