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 | |
35 | namespace dart { |
36 | |
37 | // Forward declarations. |
38 | class Log; |
39 | class Mutex; |
40 | class ThreadState; |
41 | class TimelineEventBlock; |
42 | |
43 | class 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 | |
72 | class 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. |
89 | class 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. |
325 | class 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 | |
340 | class 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 | |
384 | inline 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 | |