Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
os_thread_android.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_ANDROID) && !defined(DART_USE_ABSL)
8
9#include "vm/os_thread.h"
10
11#include <errno.h> // NOLINT
12#include <stdio.h>
13#include <sys/prctl.h>
14#include <sys/resource.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_message[kBufferSize]; \
36 Utils::StrError(result, error_message, kBufferSize); \
37 FATAL("pthread error: %d (%s)", result, error_message); \
38 }
39
40#if defined(PRODUCT)
41#define VALIDATE_PTHREAD_RESULT_NAMED(result) VALIDATE_PTHREAD_RESULT(result)
42#else
43#define VALIDATE_PTHREAD_RESULT_NAMED(result) \
44 if (result != 0) { \
45 const int kBufferSize = 1024; \
46 char error_message[kBufferSize]; \
47 Utils::StrError(result, error_message, kBufferSize); \
48 FATAL("[%s] pthread error: %d (%s)", name_, result, error_message); \
49 }
50#endif
51
52#if defined(DEBUG)
53#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
54#else
55// NOTE: This (currently) expands to a no-op.
56#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
57#endif
58
59#ifdef DEBUG
60#define RETURN_ON_PTHREAD_FAILURE(result) \
61 if (result != 0) { \
62 const int kBufferSize = 1024; \
63 char error_message[kBufferSize]; \
64 Utils::StrError(result, error_message, kBufferSize); \
65 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
66 result, error_message); \
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 struct timeval tv;
76 int64_t secs = micros / kMicrosecondsPerSecond;
77 int64_t remaining_micros = (micros - (secs * kMicrosecondsPerSecond));
78 int result = gettimeofday(&tv, nullptr);
79 ASSERT(result == 0);
80 ts->tv_sec = tv.tv_sec + secs;
81 ts->tv_nsec = (tv.tv_usec + remaining_micros) * kNanosecondsPerMicrosecond;
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, gettid(), FLAG_worker_thread_priority) ==
128 -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 gettid();
213}
214
215#ifdef SUPPORT_TIMELINE
216ThreadId OSThread::GetCurrentThreadTraceId() {
217 return GetCurrentThreadId();
218}
219#endif // SUPPORT_TIMELINE
220
221char* OSThread::GetCurrentThreadName() {
222 const intptr_t kNameBufferSize = 16;
223 char* name = static_cast<char*>(malloc(kNameBufferSize));
224 prctl(PR_GET_NAME, name);
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 a == b;
257}
258
259bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
260 pthread_attr_t attr;
261 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
262 return false;
263 }
264
265 void* base;
266 size_t size;
267 int error = pthread_attr_getstack(&attr, &base, &size);
268 pthread_attr_destroy(&attr);
269 if (error != 0) {
270 return false;
271 }
272
273 *lower = reinterpret_cast<uword>(base);
274 *upper = *lower + size;
275 return true;
276}
277
278#if defined(USING_SAFE_STACK)
281uword OSThread::GetCurrentSafestackPointer() {
282#error "SAFE_STACK is unsupported on this platform"
283 return 0;
284}
285
288void OSThread::SetCurrentSafestackPointer(uword ssp) {
289#error "SAFE_STACK is unsupported on this platform"
290}
291#endif
292
293Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
294#if !defined(PRODUCT)
295 : name_(name)
296#endif
297{
298 pthread_mutexattr_t attr;
299 int result = pthread_mutexattr_init(&attr);
300 VALIDATE_PTHREAD_RESULT_NAMED(result);
301
302#if defined(DEBUG)
303 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
304 VALIDATE_PTHREAD_RESULT_NAMED(result);
305#endif // defined(DEBUG)
306
307 result = pthread_mutex_init(data_.mutex(), &attr);
308 // Verify that creating a pthread_mutex succeeded.
309 VALIDATE_PTHREAD_RESULT_NAMED(result);
310
311 result = pthread_mutexattr_destroy(&attr);
312 VALIDATE_PTHREAD_RESULT_NAMED(result);
313
314#if defined(DEBUG)
315 // When running with assertions enabled we do track the owner.
317#endif // defined(DEBUG)
318}
319
321 int result = pthread_mutex_destroy(data_.mutex());
322 // Verify that the pthread_mutex was destroyed.
323 VALIDATE_PTHREAD_RESULT_NAMED(result);
324
325#if defined(DEBUG)
326 // When running with assertions enabled we do track the owner.
328#endif // defined(DEBUG)
329}
330
331void Mutex::Lock() {
332 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
333
334 int result = pthread_mutex_lock(data_.mutex());
335 // Specifically check for dead lock to help debugging.
336 ASSERT(result != EDEADLK);
337 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
338#if defined(DEBUG)
339 // When running with assertions enabled we do track the owner.
341#endif // defined(DEBUG)
342}
343
344bool Mutex::TryLock() {
345 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
346
347 int result = pthread_mutex_trylock(data_.mutex());
348 // Return false if the lock is busy and locking failed.
349 if (result == EBUSY) {
350 return false;
351 }
352 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
353#if defined(DEBUG)
354 // When running with assertions enabled we do track the owner.
356#endif // defined(DEBUG)
357 return true;
358}
359
360void Mutex::Unlock() {
361#if defined(DEBUG)
362 // When running with assertions enabled we do track the owner.
365#endif // defined(DEBUG)
366 int result = pthread_mutex_unlock(data_.mutex());
367 // Specifically check for wrong thread unlocking to aid debugging.
368 ASSERT(result != EPERM);
369 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
370}
371
373 pthread_mutexattr_t mutex_attr;
374 int result = pthread_mutexattr_init(&mutex_attr);
375 VALIDATE_PTHREAD_RESULT(result);
376
377#if defined(DEBUG)
378 result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
379 VALIDATE_PTHREAD_RESULT(result);
380#endif // defined(DEBUG)
381
382 result = pthread_mutex_init(data_.mutex(), &mutex_attr);
383 VALIDATE_PTHREAD_RESULT(result);
384
385 result = pthread_mutexattr_destroy(&mutex_attr);
386 VALIDATE_PTHREAD_RESULT(result);
387
388 pthread_condattr_t cond_attr;
389 result = pthread_condattr_init(&cond_attr);
390 VALIDATE_PTHREAD_RESULT(result);
391
392 result = pthread_cond_init(data_.cond(), &cond_attr);
393 VALIDATE_PTHREAD_RESULT(result);
394
395 result = pthread_condattr_destroy(&cond_attr);
396 VALIDATE_PTHREAD_RESULT(result);
397
398#if defined(DEBUG)
399 // When running with assertions enabled we track the owner.
401#endif // defined(DEBUG)
402}
403
405#if defined(DEBUG)
406 // When running with assertions enabled we track the owner.
408#endif // defined(DEBUG)
409
410 int result = pthread_mutex_destroy(data_.mutex());
411 VALIDATE_PTHREAD_RESULT(result);
412
413 result = pthread_cond_destroy(data_.cond());
414 VALIDATE_PTHREAD_RESULT(result);
415}
416
417bool Monitor::TryEnter() {
418 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
419
420 int result = pthread_mutex_trylock(data_.mutex());
421 // Return false if the lock is busy and locking failed.
422 if (result == EBUSY) {
423 return false;
424 }
425 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
426#if defined(DEBUG)
427 // When running with assertions enabled we track the owner.
430#endif // defined(DEBUG)
431 return true;
432}
433
434void Monitor::Enter() {
435 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
436
437 int result = pthread_mutex_lock(data_.mutex());
438 VALIDATE_PTHREAD_RESULT(result);
439
440#if defined(DEBUG)
441 // When running with assertions enabled we track the owner.
444#endif // defined(DEBUG)
445}
446
447void Monitor::Exit() {
448#if defined(DEBUG)
449 // When running with assertions enabled we track the owner.
452#endif // defined(DEBUG)
453
454 int result = pthread_mutex_unlock(data_.mutex());
455 VALIDATE_PTHREAD_RESULT(result);
456}
457
458Monitor::WaitResult Monitor::Wait(int64_t millis) {
459 return WaitMicros(millis * kMicrosecondsPerMillisecond);
460}
461
462Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
463#if defined(DEBUG)
464 // When running with assertions enabled we track the owner.
466 ThreadId saved_owner = owner_;
468#endif // defined(DEBUG)
469
471 if (micros == kNoTimeout) {
472 // Wait forever.
473 int result = pthread_cond_wait(data_.cond(), data_.mutex());
474 VALIDATE_PTHREAD_RESULT(result);
475 } else {
476 struct timespec ts;
477 ComputeTimeSpecMicros(&ts, micros);
478 int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
479 ASSERT((result == 0) || (result == ETIMEDOUT));
480 if (result == ETIMEDOUT) {
481 retval = kTimedOut;
482 }
483 }
484
485#if defined(DEBUG)
486 // When running with assertions enabled we track the owner.
489 ASSERT(owner_ == saved_owner);
490#endif // defined(DEBUG)
491 return retval;
492}
493
494void Monitor::Notify() {
495 // When running with assertions enabled we track the owner.
497 int result = pthread_cond_signal(data_.cond());
498 VALIDATE_PTHREAD_RESULT(result);
499}
500
501void Monitor::NotifyAll() {
502 // When running with assertions enabled we track the owner.
504 int result = pthread_cond_broadcast(data_.cond());
505 VALIDATE_PTHREAD_RESULT(result);
506}
507
508} // namespace dart
509
510#endif // defined(DART_HOST_OS_ANDROID) && !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