Flutter Engine
The Flutter Engine
os_thread_absl.cc
Go to the documentation of this file.
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
19#include "platform/assert.h"
20#include "platform/safe_stack.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,
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_;
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();
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);
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);
192 static_cast<ThreadJoinId>(0);
193
195 pthread_key_t key = kUnsetThreadLocalKey;
196 int result = pthread_key_create(&key, destructor);
197 VALIDATE_PTHREAD_RESULT(result);
199 return key;
200}
201
204 int result = pthread_key_delete(key);
205 VALIDATE_PTHREAD_RESULT(result);
206}
207
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
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
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
262 int result = pthread_join(id, nullptr);
263 ASSERT(result == 0);
264}
265
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
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
284 return pthread_equal(a, b) != 0;
285}
286
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)
316uword OSThread::GetCurrentSafestackPointer() {
317#error "SAFE_STACK is unsupported on this platform"
318 return 0;
319}
320
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.
336#endif // defined(DEBUG)
337}
338
340#if defined(DEBUG)
341 // When running with assertions enabled we track the owner.
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.
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.
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.
373#endif // defined(DEBUG)
374 data_.mutex()->Unlock();
375}
376
378#if defined(DEBUG)
379 // When running with assertions enabled we track the owner.
381#endif // defined(DEBUG)
382}
383
385#if defined(DEBUG)
386 // When running with assertions enabled we track the owner.
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.
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.
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.
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.
434 ThreadId saved_owner = owner_;
436#endif // defined(DEBUG)
437
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.
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.
462 data_.cond()->Signal();
463}
464
465ABSL_NO_THREAD_SAFETY_ANALYSIS
466void Monitor::NotifyAll() {
467 // When running with assertions enabled we track the owner.
469 data_.cond()->SignalAll();
470}
471
472} // namespace dart
473
474#endif // defined(DART_USE_ABSL)
#define NO_SANITIZE_ADDRESS
#define DEBUG_ASSERT(cond)
Definition: assert.h:321
bool IsOwnedByCurrentThread() const
Definition: os_thread.h:371
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
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)
static OSThread * CreateOSThread()
Definition: os_thread.cc:66
static void SetCurrent(OSThread *current)
Definition: os_thread.h:186
static ThreadId ThreadIdFromIntPtr(intptr_t id)
static ThreadId GetCurrentThreadId()
static void Join(ThreadJoinId id)
static bool Compare(ThreadId a, ThreadId b)
static ThreadLocalKey CreateThreadLocal(ThreadDestructor destructor=nullptr)
static const ThreadId kInvalidThreadId
Definition: os_thread.h:248
static ThreadJoinId GetCurrentThreadJoinId(OSThread *thread)
void(* ThreadStartFunction)(uword parameter)
Definition: os_thread.h:209
static void SetThreadLocal(ThreadLocalKey key, uword value)
static intptr_t ThreadIdToIntPtr(ThreadId id)
static intptr_t GetMaxStackSize()
static const ThreadJoinId kInvalidThreadJoinId
Definition: os_thread.h:249
#define ASSERT(E)
static bool b
struct MyStruct a[10]
#define FATAL(error)
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
Definition: dart_vm.cc:33
constexpr int kMinInt
Definition: globals.h:489
constexpr intptr_t kMicrosecondsPerMillisecond
Definition: globals.h:561
const char *const name
pthread_t ThreadJoinId
void * malloc(size_t size)
Definition: allocation.cc:19
constexpr intptr_t KB
Definition: globals.h:528
uintptr_t uword
Definition: globals.h:501
static void USE(T &&)
Definition: globals.h:618
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
void(* ThreadDestructor)(void *parameter)
Definition: os_thread_win.h:69
constexpr intptr_t kWordSize
Definition: globals.h:509
pthread_key_t ThreadLocalKey
static int8_t data[kExtLength]
NOT_IN_PRODUCT(LibraryPtr ReloadTestScript(const char *script))
static const ThreadLocalKey kUnsetThreadLocalKey
pthread_t ThreadId
COMPILE_ASSERT(kUnreachableReference==WeakTable::kNoValue)
static void UnblockSIGPROF()
Definition: tester_main.cc:325
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition: switches.h:248
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
#define NO_SANITIZE_SAFE_STACK
Definition: safe_stack.h:17
#define CHECK_IS_BLOCKING(signal)
#define ARRAY_SIZE(array)
Definition: globals.h:72