Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
os_thread_linux.cc
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#include "platform/globals.h" // NOLINT
6
7#if defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL)
8
9#include "vm/os_thread.h"
10
11#include <errno.h> // NOLINT
12#include <stdio.h>
13#include <sys/resource.h> // NOLINT
14#include <sys/syscall.h> // NOLINT
15#include <sys/time.h> // NOLINT
16
18#include "platform/assert.h"
19#include "platform/safe_stack.h"
21#include "platform/utils.h"
22
23#include "vm/flags.h"
24
25namespace dart {
26
27DEFINE_FLAG(int,
28 worker_thread_priority,
29 kMinInt,
30 "The thread priority the VM should use for new worker threads.");
31
32#define VALIDATE_PTHREAD_RESULT(result) \
33 if (result != 0) { \
34 const int kBufferSize = 1024; \
35 char error_buf[kBufferSize]; \
36 FATAL("pthread error: %d (%s)", result, \
37 Utils::StrError(result, error_buf, kBufferSize)); \
38 }
39
40// Variation of VALIDATE_PTHREAD_RESULT for named objects.
41#if defined(PRODUCT)
42#define VALIDATE_PTHREAD_RESULT_NAMED(result) VALIDATE_PTHREAD_RESULT(result)
43#else
44#define VALIDATE_PTHREAD_RESULT_NAMED(result) \
45 if (result != 0) { \
46 const int kBufferSize = 1024; \
47 char error_buf[kBufferSize]; \
48 FATAL("[%s] pthread error: %d (%s)", name_, result, \
49 Utils::StrError(result, error_buf, kBufferSize)); \
50 }
51#endif
52
53#if defined(DEBUG)
54#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
55#else
56// NOTE: This (currently) expands to a no-op.
57#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
58#endif
59
60#ifdef DEBUG
61#define RETURN_ON_PTHREAD_FAILURE(result) \
62 if (result != 0) { \
63 const int kBufferSize = 1024; \
64 char error_buf[kBufferSize]; \
65 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
66 result, Utils::StrError(result, error_buf, kBufferSize)); \
67 return result; \
68 }
69#else
70#define RETURN_ON_PTHREAD_FAILURE(result) \
71 if (result != 0) return result;
72#endif
73
74static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
75 int64_t secs = micros / kMicrosecondsPerSecond;
76 int64_t nanos =
78 int result = clock_gettime(CLOCK_MONOTONIC, ts);
79 ASSERT(result == 0);
80 ts->tv_sec += secs;
81 ts->tv_nsec += nanos;
82 if (ts->tv_nsec >= kNanosecondsPerSecond) {
83 ts->tv_sec += 1;
84 ts->tv_nsec -= kNanosecondsPerSecond;
85 }
86}
87
88class ThreadStartData {
89 public:
90 ThreadStartData(const char* name,
91 OSThread::ThreadStartFunction function,
92 uword parameter)
93 : name_(name), function_(function), parameter_(parameter) {}
94
95 const char* name() const { return name_; }
96 OSThread::ThreadStartFunction function() const { return function_; }
97 uword parameter() const { return parameter_; }
98
99 private:
100 const char* name_;
101 OSThread::ThreadStartFunction function_;
102 uword parameter_;
103
104 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
105};
106
107// TODO(bkonyi): remove this call once the prebuilt SDK is updated.
108// Spawned threads inherit their spawner's signal mask. We sometimes spawn
109// threads for running Dart code from a thread that is blocking SIGPROF.
110// This function explicitly unblocks SIGPROF so the profiler continues to
111// sample this thread.
112static void UnblockSIGPROF() {
113 sigset_t set;
114 sigemptyset(&set);
115 sigaddset(&set, SIGPROF);
116 int r = pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
117 USE(r);
118 ASSERT(r == 0);
119 ASSERT(!CHECK_IS_BLOCKING(SIGPROF));
120}
121
122// Dispatch to the thread start function provided by the caller. This trampoline
123// is used to ensure that the thread is properly destroyed if the thread just
124// exits.
125static void* ThreadStart(void* data_ptr) {
126 if (FLAG_worker_thread_priority != kMinInt) {
127 if (setpriority(PRIO_PROCESS, syscall(__NR_gettid),
128 FLAG_worker_thread_priority) == -1) {
129 FATAL("Setting thread priority to %d failed: errno = %d\n",
130 FLAG_worker_thread_priority, errno);
131 }
132 }
133
134 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
135
136 const char* name = data->name();
138 uword parameter = data->parameter();
139 delete data;
140
141 // Set the thread name. There is 16 bytes limit on the name (including \0).
142 // pthread_setname_np ignores names that are too long rather than truncating.
143 char truncated_name[16];
144 snprintf(truncated_name, ARRAY_SIZE(truncated_name), "%s", name);
145 pthread_setname_np(pthread_self(), truncated_name);
146
147 // Create new OSThread object and set as TLS for new thread.
148 OSThread* thread = OSThread::CreateOSThread();
149 if (thread != nullptr) {
150 OSThread::SetCurrent(thread);
151 thread->SetName(name);
152 UnblockSIGPROF();
153 // Call the supplied thread start function handing it its parameters.
154 function(parameter);
155 }
156
157 return nullptr;
158}
159
160int OSThread::Start(const char* name,
161 ThreadStartFunction function,
162 uword parameter) {
163 pthread_attr_t attr;
164 int result = pthread_attr_init(&attr);
165 RETURN_ON_PTHREAD_FAILURE(result);
166
167 result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
168 RETURN_ON_PTHREAD_FAILURE(result);
169
170 ThreadStartData* data = new ThreadStartData(name, function, parameter);
171
172 pthread_t tid;
173 result = pthread_create(&tid, &attr, ThreadStart, data);
174 RETURN_ON_PTHREAD_FAILURE(result);
175
176 result = pthread_attr_destroy(&attr);
177 RETURN_ON_PTHREAD_FAILURE(result);
178
179 return 0;
180}
181
182const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
184 static_cast<ThreadJoinId>(0);
185
187 pthread_key_t key = kUnsetThreadLocalKey;
188 int result = pthread_key_create(&key, destructor);
189 VALIDATE_PTHREAD_RESULT(result);
191 return key;
192}
193
196 int result = pthread_key_delete(key);
197 VALIDATE_PTHREAD_RESULT(result);
198}
199
202 int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
203 VALIDATE_PTHREAD_RESULT(result);
204}
205
206intptr_t OSThread::GetMaxStackSize() {
207 const int kStackSize = (128 * kWordSize * KB);
208 return kStackSize;
209}
210
212 return pthread_self();
213}
214
215#ifdef SUPPORT_TIMELINE
216ThreadId OSThread::GetCurrentThreadTraceId() {
217 return syscall(__NR_gettid);
218}
219#endif // SUPPORT_TIMELINE
220
221char* OSThread::GetCurrentThreadName() {
222 const intptr_t kNameBufferSize = 16;
223 char* name = static_cast<char*>(malloc(kNameBufferSize));
224 pthread_getname_np(pthread_self(), name, kNameBufferSize);
225 return name;
226}
227
229 ASSERT(thread != nullptr);
230 // Make sure we're filling in the join id for the current thread.
231 ASSERT(thread->id() == GetCurrentThreadId());
232 // Make sure the join_id_ hasn't been set, yet.
233 DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
234 pthread_t id = pthread_self();
235#if defined(DEBUG)
236 thread->join_id_ = id;
237#endif
238 return id;
239}
240
242 int result = pthread_join(id, nullptr);
243 ASSERT(result == 0);
244}
245
247 COMPILE_ASSERT(sizeof(id) <= sizeof(intptr_t));
248 return static_cast<intptr_t>(id);
249}
250
252 return static_cast<ThreadId>(id);
253}
254
256 return pthread_equal(a, b) != 0;
257}
258
259bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
260 pthread_attr_t attr;
261 // May fail on the main thread.
262 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
263 return false;
264 }
265
266 void* base;
267 size_t size;
268 int error = pthread_attr_getstack(&attr, &base, &size);
269 pthread_attr_destroy(&attr);
270 if (error != 0) {
271 return false;
272 }
273
274 *lower = reinterpret_cast<uword>(base);
275 *upper = *lower + size;
276 return true;
277}
278
279#if defined(USING_SAFE_STACK)
282uword OSThread::GetCurrentSafestackPointer() {
283#error "SAFE_STACK is unsupported on this platform"
284 return 0;
285}
286
289void OSThread::SetCurrentSafestackPointer(uword ssp) {
290#error "SAFE_STACK is unsupported on this platform"
291}
292#endif
293
294Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
295#if !defined(PRODUCT)
296 : name_(name)
297#endif
298{
299 pthread_mutexattr_t attr;
300 int result = pthread_mutexattr_init(&attr);
301 VALIDATE_PTHREAD_RESULT_NAMED(result);
302
303#if defined(DEBUG)
304 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
305 VALIDATE_PTHREAD_RESULT_NAMED(result);
306#endif // defined(DEBUG)
307
308 result = pthread_mutex_init(data_.mutex(), &attr);
309 // Verify that creating a pthread_mutex succeeded.
310 VALIDATE_PTHREAD_RESULT_NAMED(result);
311
312 result = pthread_mutexattr_destroy(&attr);
313 VALIDATE_PTHREAD_RESULT_NAMED(result);
314
315#if defined(DEBUG)
316 // When running with assertions enabled we track the owner.
318#endif // defined(DEBUG)
319}
320
322 int result = pthread_mutex_destroy(data_.mutex());
323 // Verify that the pthread_mutex was destroyed.
324 VALIDATE_PTHREAD_RESULT_NAMED(result);
325
326#if defined(DEBUG)
327 // When running with assertions enabled we track the owner.
329#endif // defined(DEBUG)
330}
331
332void Mutex::Lock() {
333 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
334
335 int result = pthread_mutex_lock(data_.mutex());
336 // Specifically check for dead lock to help debugging.
337 ASSERT(result != EDEADLK);
338 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
339#if defined(DEBUG)
340 // When running with assertions enabled we track the owner.
342#endif // defined(DEBUG)
343}
344
345bool Mutex::TryLock() {
346 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
347
348 int result = pthread_mutex_trylock(data_.mutex());
349 // Return false if the lock is busy and locking failed.
350 if (result == EBUSY) {
351 return false;
352 }
353 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
354#if defined(DEBUG)
355 // When running with assertions enabled we track the owner.
357#endif // defined(DEBUG)
358 return true;
359}
360
361void Mutex::Unlock() {
362#if defined(DEBUG)
363 // When running with assertions enabled we track the owner.
366#endif // defined(DEBUG)
367 int result = pthread_mutex_unlock(data_.mutex());
368 // Specifically check for wrong thread unlocking to aid debugging.
369 ASSERT(result != EPERM);
370 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
371}
372
374 pthread_mutexattr_t mutex_attr;
375 int result = pthread_mutexattr_init(&mutex_attr);
376 VALIDATE_PTHREAD_RESULT(result);
377
378#if defined(DEBUG)
379 result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
380 VALIDATE_PTHREAD_RESULT(result);
381#endif // defined(DEBUG)
382
383 result = pthread_mutex_init(data_.mutex(), &mutex_attr);
384 VALIDATE_PTHREAD_RESULT(result);
385
386 result = pthread_mutexattr_destroy(&mutex_attr);
387 VALIDATE_PTHREAD_RESULT(result);
388
389 pthread_condattr_t cond_attr;
390 result = pthread_condattr_init(&cond_attr);
391 VALIDATE_PTHREAD_RESULT(result);
392
393 result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
394 VALIDATE_PTHREAD_RESULT(result);
395
396 result = pthread_cond_init(data_.cond(), &cond_attr);
397 VALIDATE_PTHREAD_RESULT(result);
398
399 result = pthread_condattr_destroy(&cond_attr);
400 VALIDATE_PTHREAD_RESULT(result);
401
402#if defined(DEBUG)
403 // When running with assertions enabled we track the owner.
405#endif // defined(DEBUG)
406}
407
409#if defined(DEBUG)
410 // When running with assertions enabled we track the owner.
412#endif // defined(DEBUG)
413
414 int result = pthread_mutex_destroy(data_.mutex());
415 VALIDATE_PTHREAD_RESULT(result);
416
417 result = pthread_cond_destroy(data_.cond());
418 VALIDATE_PTHREAD_RESULT(result);
419}
420
421bool Monitor::TryEnter() {
422 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
423
424 int result = pthread_mutex_trylock(data_.mutex());
425 // Return false if the lock is busy and locking failed.
426 if (result == EBUSY) {
427 return false;
428 }
429 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
430#if defined(DEBUG)
431 // When running with assertions enabled we track the owner.
434#endif // defined(DEBUG)
435 return true;
436}
437
438void Monitor::Enter() {
439 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
440
441 int result = pthread_mutex_lock(data_.mutex());
442 VALIDATE_PTHREAD_RESULT(result);
443
444#if defined(DEBUG)
445 // When running with assertions enabled we track the owner.
448#endif // defined(DEBUG)
449}
450
451void Monitor::Exit() {
452#if defined(DEBUG)
453 // When running with assertions enabled we track the owner.
456#endif // defined(DEBUG)
457
458 int result = pthread_mutex_unlock(data_.mutex());
459 VALIDATE_PTHREAD_RESULT(result);
460}
461
462Monitor::WaitResult Monitor::Wait(int64_t millis) {
463 Monitor::WaitResult retval = WaitMicros(millis * kMicrosecondsPerMillisecond);
464 return retval;
465}
466
467Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
468#if defined(DEBUG)
469 // When running with assertions enabled we track the owner.
471 ThreadId saved_owner = owner_;
473#endif // defined(DEBUG)
474
476 if (micros == kNoTimeout) {
477 // Wait forever.
478 int result = pthread_cond_wait(data_.cond(), data_.mutex());
479 VALIDATE_PTHREAD_RESULT(result);
480 } else {
481 struct timespec ts;
482 ComputeTimeSpecMicros(&ts, micros);
483 int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
484 ASSERT((result == 0) || (result == ETIMEDOUT));
485 if (result == ETIMEDOUT) {
486 retval = kTimedOut;
487 }
488 }
489
490#if defined(DEBUG)
491 // When running with assertions enabled we track the owner.
494 ASSERT(owner_ == saved_owner);
495#endif // defined(DEBUG)
496 return retval;
497}
498
499void Monitor::Notify() {
500 // When running with assertions enabled we track the owner.
502 int result = pthread_cond_signal(data_.cond());
503 VALIDATE_PTHREAD_RESULT(result);
504}
505
506void Monitor::NotifyAll() {
507 // When running with assertions enabled we track the owner.
509 int result = pthread_cond_broadcast(data_.cond());
510 VALIDATE_PTHREAD_RESULT(result);
511}
512
513} // namespace dart
514
515#endif // defined(DART_HOST_OS_LINUX) && !defined(DART_USE_ABSL)
#define NO_SANITIZE_ADDRESS
#define DEBUG_ASSERT(cond)
Definition assert.h:321
#define COMPILE_ASSERT(expr)
Definition assert.h:339
bool IsOwnedByCurrentThread() const
Definition os_thread.h:370
static constexpr int64_t kNoTimeout
Definition os_thread.h:360
Mutex(NOT_IN_PRODUCT(const char *name="anonymous mutex"))
bool IsOwnedByCurrentThread() const
Definition os_thread.h:401
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:182
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:244
static ThreadJoinId GetCurrentThreadJoinId(OSThread *thread)
void(* ThreadStartFunction)(uword parameter)
Definition os_thread.h:205
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:245
#define ASSERT(E)
static bool b
struct MyStruct a[10]
#define FATAL(error)
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
Dart_NativeFunction function
Definition fuchsia.cc:51
const char * name
Definition fuchsia.cc:50
constexpr int kMinInt
Definition globals.h:489
constexpr intptr_t kMicrosecondsPerMillisecond
Definition globals.h:561
const char *const name
pthread_t ThreadJoinId
constexpr intptr_t kMicrosecondsPerSecond
Definition globals.h:562
constexpr intptr_t kNanosecondsPerMicrosecond
Definition globals.h:564
void * malloc(size_t size)
Definition allocation.cc:19
constexpr intptr_t KB
Definition globals.h:528
uintptr_t uword
Definition globals.h:501
constexpr intptr_t kNanosecondsPerSecond
Definition globals.h:567
static void USE(T &&)
Definition globals.h:618
void(* ThreadDestructor)(void *parameter)
constexpr intptr_t kWordSize
Definition globals.h:509
pthread_key_t ThreadLocalKey
static int8_t data[kExtLength]
static const ThreadLocalKey kUnsetThreadLocalKey
pthread_t ThreadId
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
#define NOT_IN_PRODUCT(code)
Definition globals.h:84