1// Copyright (c) 2022, 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 "platform/globals.h" // NOLINT
6
7#if defined(DART_USE_ABSL)
8
9#include <errno.h> // NOLINT
10#include <stdio.h>
11#include <sys/resource.h> // NOLINT
12#include <sys/syscall.h> // NOLINT
13#include <sys/time.h> // NOLINT
14#if defined(DART_HOST_OS_ANDROID)
15#include <sys/prctl.h>
16#endif // defined(DART_HOST_OS_ANDROID)
17
18#include "platform/address_sanitizer.h"
19#include "platform/assert.h"
20#include "platform/safe_stack.h"
21#include "platform/signal_blocker.h"
22#include "platform/utils.h"
23#include "vm/flags.h"
24#include "vm/os_thread.h"
25
26namespace dart {
27
28DEFINE_FLAG(int,
29 worker_thread_priority,
30 kMinInt,
31 "The thread priority the VM should use for new worker threads.");
32
33#define VALIDATE_PTHREAD_RESULT(result) \
34 if (result != 0) { \
35 const int kBufferSize = 1024; \
36 char error_buf[kBufferSize]; \
37 FATAL("pthread error: %d (%s)", result, \
38 Utils::StrError(result, error_buf, kBufferSize)); \
39 }
40
41// Variation of VALIDATE_PTHREAD_RESULT for named objects.
42#if defined(PRODUCT)
43#define VALIDATE_PTHREAD_RESULT_NAMED(result) VALIDATE_PTHREAD_RESULT(result)
44#else
45#define VALIDATE_PTHREAD_RESULT_NAMED(result) \
46 if (result != 0) { \
47 const int kBufferSize = 1024; \
48 char error_buf[kBufferSize]; \
49 FATAL("[%s] pthread error: %d (%s)", name_, result, \
50 Utils::StrError(result, error_buf, kBufferSize)); \
51 }
52#endif
53
54#if defined(DEBUG)
55#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
56#else
57// NOTE: This (currently) expands to a no-op.
58#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
59#endif
60
61#ifdef DEBUG
62#define RETURN_ON_PTHREAD_FAILURE(result) \
63 if (result != 0) { \
64 const int kBufferSize = 1024; \
65 char error_buf[kBufferSize]; \
66 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
67 result, Utils::StrError(result, error_buf, kBufferSize)); \
68 return result; \
69 }
70#else
71#define RETURN_ON_PTHREAD_FAILURE(result) \
72 if (result != 0) return result;
73#endif
74
75class ThreadStartData {
76 public:
77 ThreadStartData(const char* name,
78 OSThread::ThreadStartFunction function,
79 uword parameter)
80 : name_(name), function_(function), parameter_(parameter) {}
81
82 const char* name() const { return name_; }
83 OSThread::ThreadStartFunction function() const { return function_; }
84 uword parameter() const { return parameter_; }
85
86 private:
87 const char* name_;
88 OSThread::ThreadStartFunction function_;
89 uword parameter_;
90
91 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
92};
93
94// TODO(bkonyi): remove this call once the prebuilt SDK is updated.
95// Spawned threads inherit their spawner's signal mask. We sometimes spawn
96// threads for running Dart code from a thread that is blocking SIGPROF.
97// This function explicitly unblocks SIGPROF so the profiler continues to
98// sample this thread.
99static void UnblockSIGPROF() {
100 sigset_t set;
101 sigemptyset(&set);
102 sigaddset(&set, SIGPROF);
103 int r = pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
104 USE(r);
105 ASSERT(r == 0);
106 ASSERT(!CHECK_IS_BLOCKING(SIGPROF));
107}
108
109// Dispatch to the thread start function provided by the caller. This trampoline
110// is used to ensure that the thread is properly destroyed if the thread just
111// exits.
112static void* ThreadStart(void* data_ptr) {
113#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
114 if (FLAG_worker_thread_priority != kMinInt) {
115 if (setpriority(PRIO_PROCESS, syscall(__NR_gettid),
116 FLAG_worker_thread_priority) == -1) {
117 FATAL("Setting thread priority to %d failed: errno = %d\n",
118 FLAG_worker_thread_priority, errno);
119 }
120 }
121#elif defined(DART_HOST_OS_MACOS)
122 if (FLAG_worker_thread_priority != kMinInt) {
123 const pthread_t thread = pthread_self();
124 int policy = SCHED_FIFO;
125 struct sched_param schedule;
126 if (pthread_getschedparam(thread, &policy, &schedule) != 0) {
127 FATAL("Obtaining sched param failed: errno = %d\n", errno);
128 }
129 schedule.sched_priority = FLAG_worker_thread_priority;
130 if (pthread_setschedparam(thread, policy, &schedule) != 0) {
131 FATAL("Setting thread priority to %d failed: errno = %d\n",
132 FLAG_worker_thread_priority, errno);
133 }
134 }
135#endif
136
137 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
138
139 const char* name = data->name();
140 OSThread::ThreadStartFunction function = data->function();
141 uword parameter = data->parameter();
142 delete data;
143
144 // Set the thread name. There is 16 bytes limit on the name (including \0).
145 // pthread_setname_np ignores names that are too long rather than truncating.
146 char truncated_name[16];
147 snprintf(truncated_name, ARRAY_SIZE(truncated_name), "%s", name);
148#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
149 pthread_setname_np(pthread_self(), truncated_name);
150#elif defined(DART_HOST_OS_MACOS)
151 // Set the thread name.
152 pthread_setname_np(name);
153#endif
154
155 // Create new OSThread object and set as TLS for new thread.
156 OSThread* thread = OSThread::CreateOSThread();
157 if (thread != nullptr) {
158 OSThread::SetCurrent(thread);
159 thread->SetName(name);
160 UnblockSIGPROF();
161 // Call the supplied thread start function handing it its parameters.
162 function(parameter);
163 }
164
165 return nullptr;
166}
167
168int OSThread::Start(const char* name,
169 ThreadStartFunction function,
170 uword parameter) {
171 pthread_attr_t attr;
172 int result = pthread_attr_init(&attr);
173 RETURN_ON_PTHREAD_FAILURE(result);
174
175 result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
176 RETURN_ON_PTHREAD_FAILURE(result);
177
178 ThreadStartData* data = new ThreadStartData(name, function, parameter);
179
180 pthread_t tid;
181 result = pthread_create(&tid, &attr, ThreadStart, data);
182 RETURN_ON_PTHREAD_FAILURE(result);
183
184 result = pthread_attr_destroy(&attr);
185 RETURN_ON_PTHREAD_FAILURE(result);
186
187 return 0;
188}
189
190const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
191const ThreadJoinId OSThread::kInvalidThreadJoinId =
192 static_cast<ThreadJoinId>(0);
193
194ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
195 pthread_key_t key = kUnsetThreadLocalKey;
196 int result = pthread_key_create(&key, destructor);
197 VALIDATE_PTHREAD_RESULT(result);
198 ASSERT(key != kUnsetThreadLocalKey);
199 return key;
200}
201
202void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
203 ASSERT(key != kUnsetThreadLocalKey);
204 int result = pthread_key_delete(key);
205 VALIDATE_PTHREAD_RESULT(result);
206}
207
208void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
209 ASSERT(key != kUnsetThreadLocalKey);
210 int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
211 VALIDATE_PTHREAD_RESULT(result);
212}
213
214intptr_t OSThread::GetMaxStackSize() {
215 const int kStackSize = (128 * kWordSize * KB);
216 return kStackSize;
217}
218
219ThreadId OSThread::GetCurrentThreadId() {
220 return pthread_self();
221}
222
223#ifdef SUPPORT_TIMELINE
224ThreadId OSThread::GetCurrentThreadTraceId() {
225#if defined(DART_HOST_OS_ANDROID)
226 return GetCurrentThreadId();
227#elif defined(DART_HOST_OS_LINUX)
228 return syscall(__NR_gettid);
229#elif defined(DART_HOST_OS_MACOS)
230 return ThreadIdFromIntPtr(pthread_mach_thread_np(pthread_self()));
231#endif
232}
233#endif // SUPPORT_TIMELINE
234
235char* OSThread::GetCurrentThreadName() {
236 const intptr_t kNameBufferSize = 16;
237 char* name = static_cast<char*>(malloc(kNameBufferSize));
238
239#if defined(DART_HOST_OS_ANDROID)
240 prctl(PR_GET_NAME, name);
241#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS)
242 pthread_getname_np(pthread_self(), name, kNameBufferSize);
243#endif
244
245 return name;
246}
247
248ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
249 ASSERT(thread != nullptr);
250 // Make sure we're filling in the join id for the current thread.
251 ASSERT(thread->id() == GetCurrentThreadId());
252 // Make sure the join_id_ hasn't been set, yet.
253 DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
254 pthread_t id = pthread_self();
255#if defined(DEBUG)
256 thread->join_id_ = id;
257#endif
258 return id;
259}
260
261void OSThread::Join(ThreadJoinId id) {
262 int result = pthread_join(id, nullptr);
263 ASSERT(result == 0);
264}
265
266intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) {
267 COMPILE_ASSERT(sizeof(id) <= sizeof(intptr_t));
268#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
269 return static_cast<intptr_t>(id);
270#elif defined(DART_HOST_OS_MACOS)
271 return reinterpret_cast<intptr_t>(id);
272#endif
273}
274
275ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
276#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
277 return static_cast<ThreadId>(id);
278#elif defined(DART_HOST_OS_MACOS)
279 return reinterpret_cast<ThreadId>(id);
280#endif
281}
282
283bool OSThread::Compare(ThreadId a, ThreadId b) {
284 return pthread_equal(a, b) != 0;
285}
286
287bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
288#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
289 pthread_attr_t attr;
290 // May fail on the main thread.
291 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
292 return false;
293 }
294
295 void* base;
296 size_t size;
297 int error = pthread_attr_getstack(&attr, &base, &size);
298 pthread_attr_destroy(&attr);
299 if (error != 0) {
300 return false;
301 }
302
303 *lower = reinterpret_cast<uword>(base);
304 *upper = *lower + size;
305 return true;
306#elif defined(DART_HOST_OS_MACOS)
307 *upper = reinterpret_cast<uword>(pthread_get_stackaddr_np(pthread_self()));
308 *lower = *upper - pthread_get_stacksize_np(pthread_self());
309 return true;
310#endif
311}
312
313#if defined(USING_SAFE_STACK)
314NO_SANITIZE_ADDRESS
315NO_SANITIZE_SAFE_STACK
316uword OSThread::GetCurrentSafestackPointer() {
317#error "SAFE_STACK is unsupported on this platform"
318 return 0;
319}
320
321NO_SANITIZE_ADDRESS
322NO_SANITIZE_SAFE_STACK
323void OSThread::SetCurrentSafestackPointer(uword ssp) {
324#error "SAFE_STACK is unsupported on this platform"
325}
326#endif
327
328Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
329#if !defined(PRODUCT)
330 : name_(name)
331#endif
332{
333#if defined(DEBUG)
334 // When running with assertions enabled we track the owner.
335 owner_ = OSThread::kInvalidThreadId;
336#endif // defined(DEBUG)
337}
338
339Mutex::~Mutex() {
340#if defined(DEBUG)
341 // When running with assertions enabled we track the owner.
342 ASSERT(owner_ == OSThread::kInvalidThreadId);
343#endif // defined(DEBUG)
344}
345
346ABSL_NO_THREAD_SAFETY_ANALYSIS
347void Mutex::Lock() {
348 data_.mutex()->Lock();
349#if defined(DEBUG)
350 // When running with assertions enabled we track the owner.
351 owner_ = OSThread::GetCurrentThreadId();
352#endif // defined(DEBUG)
353}
354
355ABSL_NO_THREAD_SAFETY_ANALYSIS
356bool Mutex::TryLock() {
357 if (!data_.mutex()->TryLock()) {
358 return false;
359 }
360#if defined(DEBUG)
361 // When running with assertions enabled we track the owner.
362 owner_ = OSThread::GetCurrentThreadId();
363#endif // defined(DEBUG)
364 return true;
365}
366
367ABSL_NO_THREAD_SAFETY_ANALYSIS
368void Mutex::Unlock() {
369#if defined(DEBUG)
370 // When running with assertions enabled we track the owner.
371 ASSERT(IsOwnedByCurrentThread());
372 owner_ = OSThread::kInvalidThreadId;
373#endif // defined(DEBUG)
374 data_.mutex()->Unlock();
375}
376
377Monitor::Monitor() {
378#if defined(DEBUG)
379 // When running with assertions enabled we track the owner.
380 owner_ = OSThread::kInvalidThreadId;
381#endif // defined(DEBUG)
382}
383
384Monitor::~Monitor() {
385#if defined(DEBUG)
386 // When running with assertions enabled we track the owner.
387 ASSERT(owner_ == OSThread::kInvalidThreadId);
388#endif // defined(DEBUG)
389}
390
391ABSL_NO_THREAD_SAFETY_ANALYSIS
392bool Monitor::TryEnter() {
393 if (!data_.mutex()->TryLock()) {
394 return false;
395 }
396#if defined(DEBUG)
397 // When running with assertions enabled we track the owner.
398 ASSERT(owner_ == OSThread::kInvalidThreadId);
399 owner_ = OSThread::GetCurrentThreadId();
400#endif // defined(DEBUG)
401 return true;
402}
403
404ABSL_NO_THREAD_SAFETY_ANALYSIS
405void Monitor::Enter() {
406 data_.mutex()->Lock();
407#if defined(DEBUG)
408 // When running with assertions enabled we track the owner.
409 ASSERT(owner_ == OSThread::kInvalidThreadId);
410 owner_ = OSThread::GetCurrentThreadId();
411#endif // defined(DEBUG)
412}
413
414ABSL_NO_THREAD_SAFETY_ANALYSIS
415void Monitor::Exit() {
416#if defined(DEBUG)
417 // When running with assertions enabled we track the owner.
418 ASSERT(IsOwnedByCurrentThread());
419 owner_ = OSThread::kInvalidThreadId;
420#endif // defined(DEBUG)
421 data_.mutex()->Unlock();
422}
423
424Monitor::WaitResult Monitor::Wait(int64_t millis) {
425 Monitor::WaitResult retval = WaitMicros(millis * kMicrosecondsPerMillisecond);
426 return retval;
427}
428
429ABSL_NO_THREAD_SAFETY_ANALYSIS
430Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
431#if defined(DEBUG)
432 // When running with assertions enabled we track the owner.
433 ASSERT(IsOwnedByCurrentThread());
434 ThreadId saved_owner = owner_;
435 owner_ = OSThread::kInvalidThreadId;
436#endif // defined(DEBUG)
437
438 Monitor::WaitResult retval = kNotified;
439 if (micros == kNoTimeout) {
440 // Wait forever.
441 data_.cond()->Wait(data_.mutex());
442 } else {
443 if (data_.cond()->WaitWithTimeout(data_.mutex(),
444 absl::Microseconds(micros))) {
445 retval = kTimedOut;
446 }
447 }
448
449#if defined(DEBUG)
450 // When running with assertions enabled we track the owner.
451 ASSERT(owner_ == OSThread::kInvalidThreadId);
452 owner_ = OSThread::GetCurrentThreadId();
453 ASSERT(owner_ == saved_owner);
454#endif // defined(DEBUG)
455 return retval;
456}
457
458ABSL_NO_THREAD_SAFETY_ANALYSIS
459void Monitor::Notify() {
460 // When running with assertions enabled we track the owner.
461 ASSERT(IsOwnedByCurrentThread());
462 data_.cond()->Signal();
463}
464
465ABSL_NO_THREAD_SAFETY_ANALYSIS
466void Monitor::NotifyAll() {
467 // When running with assertions enabled we track the owner.
468 ASSERT(IsOwnedByCurrentThread());
469 data_.cond()->SignalAll();
470}
471
472} // namespace dart
473
474#endif // defined(DART_USE_ABSL)
475

source code of dart_sdk/runtime/vm/os_thread_absl.cc