Flutter Engine
The Flutter Engine
os_thread_fuchsia.cc
Go to the documentation of this file.
1// Copyright (c) 2016, 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#if defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)
7
8#include "vm/os.h"
9#include "vm/os_thread.h"
11
12#include <errno.h> // NOLINT
13#include <zircon/status.h>
14#include <zircon/syscalls.h>
15#include <zircon/threads.h>
16#include <zircon/tls.h>
17#include <zircon/types.h>
18
20#include "platform/assert.h"
21#include "platform/safe_stack.h"
22
23namespace dart {
24
25#define VALIDATE_PTHREAD_RESULT(result) \
26 if (result != 0) { \
27 FATAL("pthread error: %d", result); \
28 }
29
30#if defined(PRODUCT)
31#define VALIDATE_PTHREAD_RESULT_NAMED(result) VALIDATE_PTHREAD_RESULT(result)
32#else
33#define VALIDATE_PTHREAD_RESULT_NAMED(result) \
34 if (result != 0) { \
35 FATAL("[%s] pthread error: %d", name_, result); \
36 }
37#endif
38
39#if defined(DEBUG)
40#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
41#else
42// NOTE: This (currently) expands to a no-op.
43#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
44#endif
45
46#ifdef DEBUG
47#define RETURN_ON_PTHREAD_FAILURE(result) \
48 if (result != 0) { \
49 fprintf(stderr, "%s:%d: pthread error: %d\n", __FILE__, __LINE__, result); \
50 return result; \
51 }
52#else
53#define RETURN_ON_PTHREAD_FAILURE(result) \
54 if (result != 0) return result;
55#endif
56
57static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
58 // time in nanoseconds.
59 zx_time_t now = zx_clock_get_monotonic();
60 zx_time_t target = now + (micros * kNanosecondsPerMicrosecond);
61 int64_t secs = target / kNanosecondsPerSecond;
62 int64_t nanos = target - (secs * kNanosecondsPerSecond);
63
64 ts->tv_sec = secs;
65 ts->tv_nsec = nanos;
66}
67
68class ThreadStartData {
69 public:
70 ThreadStartData(const char* name,
72 uword parameter)
73 : name_(name), function_(function), parameter_(parameter) {}
74
75 const char* name() const { return name_; }
76 OSThread::ThreadStartFunction function() const { return function_; }
77 uword parameter() const { return parameter_; }
78
79 private:
80 const char* name_;
82 uword parameter_;
83
84 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
85};
86
87// Dispatch to the thread start function provided by the caller. This trampoline
88// is used to ensure that the thread is properly destroyed if the thread just
89// exits.
90static void* ThreadStart(void* data_ptr) {
91 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
92
93 const char* name = data->name();
95 uword parameter = data->parameter();
96 delete data;
97
98 // Set the thread name.
99 char truncated_name[ZX_MAX_NAME_LEN];
100 snprintf(truncated_name, ZX_MAX_NAME_LEN, "%s", name);
101 zx_handle_t thread_handle = thrd_get_zx_handle(thrd_current());
102 zx_object_set_property(thread_handle, ZX_PROP_NAME, truncated_name,
103 ZX_MAX_NAME_LEN);
104
105 // Create new OSThread object and set as TLS for new thread.
106 OSThread* thread = OSThread::CreateOSThread();
107 if (thread != nullptr) {
108 OSThread::SetCurrent(thread);
109 thread->SetName(name);
110 // Call the supplied thread start function handing it its parameters.
111 function(parameter);
112 }
113
114 return nullptr;
115}
116
117int OSThread::Start(const char* name,
118 ThreadStartFunction function,
119 uword parameter) {
120 pthread_attr_t attr;
121 int result = pthread_attr_init(&attr);
122 RETURN_ON_PTHREAD_FAILURE(result);
123
124 result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
125 RETURN_ON_PTHREAD_FAILURE(result);
126
127 ThreadStartData* data = new ThreadStartData(name, function, parameter);
128
129 pthread_t tid;
130 result = pthread_create(&tid, &attr, ThreadStart, data);
131 RETURN_ON_PTHREAD_FAILURE(result);
132
133 result = pthread_attr_destroy(&attr);
134 RETURN_ON_PTHREAD_FAILURE(result);
135
136 return 0;
137}
138
139const ThreadId OSThread::kInvalidThreadId = ZX_HANDLE_INVALID;
141 static_cast<ThreadJoinId>(0);
142
144 pthread_key_t key = kUnsetThreadLocalKey;
145 int result = pthread_key_create(&key, destructor);
146 VALIDATE_PTHREAD_RESULT(result);
148 return key;
149}
150
153 int result = pthread_key_delete(key);
154 VALIDATE_PTHREAD_RESULT(result);
155}
156
159 int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
160 VALIDATE_PTHREAD_RESULT(result);
161}
162
163intptr_t OSThread::GetMaxStackSize() {
164 const int kStackSize = (128 * kWordSize * KB);
165 return kStackSize;
166}
167
169 return thrd_get_zx_handle(thrd_current());
170}
171
172#ifdef SUPPORT_TIMELINE
173ThreadId OSThread::GetCurrentThreadTraceId() {
174 return pthread_self();
175}
176#endif // SUPPORT_TIMELINE
177
178char* OSThread::GetCurrentThreadName() {
179 char* name = static_cast<char*>(malloc(ZX_MAX_NAME_LEN));
180 zx_handle_t thread_handle = thrd_get_zx_handle(thrd_current());
181 zx_object_get_property(thread_handle, ZX_PROP_NAME, name, ZX_MAX_NAME_LEN);
182 return name;
183}
184
186 ASSERT(thread != nullptr);
187 // Make sure we're filling in the join id for the current thread.
188 ASSERT(thread->id() == GetCurrentThreadId());
189 // Make sure the join_id_ hasn't been set, yet.
190 DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
191 pthread_t id = pthread_self();
192#if defined(DEBUG)
193 thread->join_id_ = id;
194#endif
195 return id;
196}
197
199 int result = pthread_join(id, nullptr);
200 ASSERT(result == 0);
201}
202
204 COMPILE_ASSERT(sizeof(id) <= sizeof(intptr_t));
205 return static_cast<intptr_t>(id);
206}
207
209 return static_cast<ThreadId>(id);
210}
211
213 return pthread_equal(a, b) != 0;
214}
215
217 pthread_attr_t attr;
218 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
219 return false;
220 }
221
222 void* base;
223 size_t size;
224 int error = pthread_attr_getstack(&attr, &base, &size);
225 pthread_attr_destroy(&attr);
226 if (error != 0) {
227 return false;
228 }
229
230 *lower = reinterpret_cast<uword>(base);
231 *upper = *lower + size;
232 return true;
233}
234
235#if defined(USING_SAFE_STACK)
236#define STRINGIFY(s) #s
239uword OSThread::GetCurrentSafestackPointer() {
241#if defined(HOST_ARCH_X64)
242#define _loadfsword(index) "movq %%fs:" STRINGIFY(index) ", %0"
243 asm volatile(_loadfsword(ZX_TLS_UNSAFE_SP_OFFSET)
244 : "=r"(result) // outputs
245 );
246#undef _loadfsword
247#elif defined(HOST_ARCH_ARM64)
248#define _loadword(index) "ldr %0, [%0, " STRINGIFY(index) "]"
249 asm volatile("mrs %0, TPIDR_EL0;\n" _loadword(ZX_TLS_UNSAFE_SP_OFFSET)
250 : "=r"(result) // outputs
251 );
252#else
253#error "Architecture not supported"
254#endif
255 return result;
256}
257
260void OSThread::SetCurrentSafestackPointer(uword ssp) {
261#if defined(HOST_ARCH_X64)
262#define str(s) #s
263#define _storefsword(index) "movq %0, %%fs:" str(index)
264 asm volatile(_storefsword(ZX_TLS_UNSAFE_SP_OFFSET)
265 : // outputs.
266 : "r"(ssp) // inputs.
267 : // clobbered.
268 );
269#undef _storefsword
270#undef str
271#elif defined(HOST_ARCH_ARM64)
272#define _storeword(index) "str %1, [%0, " STRINGIFY(index) "]"
273 uword tmp;
274 asm volatile("mrs %0, TPIDR_EL0;\n" _storeword(ZX_TLS_UNSAFE_SP_OFFSET)
275 : "=r"(tmp) // outputs.
276 : "r"(ssp) // inputs.
277 : // clobbered.
278 );
279#else
280#error "Architecture not supported"
281#endif
282}
283#undef STRINGIFY
284#endif
285
286Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
287#if !defined(PRODUCT)
288 : name_(name)
289#endif
290{
291 pthread_mutexattr_t attr;
292 int result = pthread_mutexattr_init(&attr);
293 VALIDATE_PTHREAD_RESULT_NAMED(result);
294
295#if defined(DEBUG)
296 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
297 VALIDATE_PTHREAD_RESULT_NAMED(result);
298#endif // defined(DEBUG)
299
300 result = pthread_mutex_init(data_.mutex(), &attr);
301 // Verify that creating a pthread_mutex succeeded.
302 VALIDATE_PTHREAD_RESULT_NAMED(result);
303
304 result = pthread_mutexattr_destroy(&attr);
305 VALIDATE_PTHREAD_RESULT_NAMED(result);
306
307#if defined(DEBUG)
308 // When running with assertions enabled we track the owner.
310#endif // defined(DEBUG)
311}
312
314 int result = pthread_mutex_destroy(data_.mutex());
315 // Verify that the pthread_mutex was destroyed.
316 VALIDATE_PTHREAD_RESULT_NAMED(result);
317
318#if defined(DEBUG)
319 // When running with assertions enabled we track the owner.
321#endif // defined(DEBUG)
322}
323
324void Mutex::Lock() {
325 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
326
327 int result = pthread_mutex_lock(data_.mutex());
328 // Specifically check for dead lock to help debugging.
329 ASSERT(result != EDEADLK);
330 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
331#if defined(DEBUG)
332 // When running with assertions enabled we track the owner.
334#endif // defined(DEBUG)
335}
336
337bool Mutex::TryLock() {
338 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
339
340 int result = pthread_mutex_trylock(data_.mutex());
341 // Return false if the lock is busy and locking failed.
342 if (result == EBUSY) {
343 return false;
344 }
345 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
346#if defined(DEBUG)
347 // When running with assertions enabled we track the owner.
349#endif // defined(DEBUG)
350 return true;
351}
352
353void Mutex::Unlock() {
354#if defined(DEBUG)
355 // When running with assertions enabled we track the owner.
358#endif // defined(DEBUG)
359 int result = pthread_mutex_unlock(data_.mutex());
360 // Specifically check for wrong thread unlocking to aid debugging.
361 ASSERT(result != EPERM);
362 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
363}
364
366 pthread_mutexattr_t mutex_attr;
367 int result = pthread_mutexattr_init(&mutex_attr);
368 VALIDATE_PTHREAD_RESULT(result);
369
370#if defined(DEBUG)
371 result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
372 VALIDATE_PTHREAD_RESULT(result);
373#endif // defined(DEBUG)
374
375 result = pthread_mutex_init(data_.mutex(), &mutex_attr);
376 VALIDATE_PTHREAD_RESULT(result);
377
378 result = pthread_mutexattr_destroy(&mutex_attr);
379 VALIDATE_PTHREAD_RESULT(result);
380
381 pthread_condattr_t cond_attr;
382 result = pthread_condattr_init(&cond_attr);
383 VALIDATE_PTHREAD_RESULT(result);
384
385 result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
386 VALIDATE_PTHREAD_RESULT(result);
387
388 result = pthread_cond_init(data_.cond(), &cond_attr);
389 VALIDATE_PTHREAD_RESULT(result);
390
391 result = pthread_condattr_destroy(&cond_attr);
392 VALIDATE_PTHREAD_RESULT(result);
393
394#if defined(DEBUG)
395 // When running with assertions enabled we track the owner.
397#endif // defined(DEBUG)
398}
399
401#if defined(DEBUG)
402 // When running with assertions enabled we track the owner.
404#endif // defined(DEBUG)
405
406 int result = pthread_mutex_destroy(data_.mutex());
407 VALIDATE_PTHREAD_RESULT(result);
408
409 result = pthread_cond_destroy(data_.cond());
410 VALIDATE_PTHREAD_RESULT(result);
411}
412
413bool Monitor::TryEnter() {
414 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
415
416 int result = pthread_mutex_trylock(data_.mutex());
417 // Return false if the lock is busy and locking failed.
418 if (result == EBUSY) {
419 return false;
420 }
421 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
422#if defined(DEBUG)
423 // When running with assertions enabled we track the owner.
426#endif // defined(DEBUG)
427 return true;
428}
429
430void Monitor::Enter() {
431 DEBUG_ASSERT(!ThreadInterruptScope::in_thread_interrupt_scope());
432
433 int result = pthread_mutex_lock(data_.mutex());
434 VALIDATE_PTHREAD_RESULT(result);
435
436#if defined(DEBUG)
437 // When running with assertions enabled we track the owner.
440#endif // defined(DEBUG)
441}
442
443void Monitor::Exit() {
444#if defined(DEBUG)
445 // When running with assertions enabled we track the owner.
448#endif // defined(DEBUG)
449
450 int result = pthread_mutex_unlock(data_.mutex());
451 VALIDATE_PTHREAD_RESULT(result);
452}
453
454Monitor::WaitResult Monitor::Wait(int64_t millis) {
455 Monitor::WaitResult retval = WaitMicros(millis * kMicrosecondsPerMillisecond);
456 return retval;
457}
458
459Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
460#if defined(DEBUG)
461 // When running with assertions enabled we track the owner.
463 ThreadId saved_owner = owner_;
465#endif // defined(DEBUG)
466
468 if (micros == kNoTimeout) {
469 // Wait forever.
470 int result = pthread_cond_wait(data_.cond(), data_.mutex());
471 VALIDATE_PTHREAD_RESULT(result);
472 } else {
473 struct timespec ts;
474 ComputeTimeSpecMicros(&ts, micros);
475 int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
476 ASSERT((result == 0) || (result == ETIMEDOUT));
477 if (result == ETIMEDOUT) {
478 retval = kTimedOut;
479 }
480 }
481
482#if defined(DEBUG)
483 // When running with assertions enabled we track the owner.
486 ASSERT(owner_ == saved_owner);
487#endif // defined(DEBUG)
488 return retval;
489}
490
491void Monitor::Notify() {
492 // When running with assertions enabled we track the owner.
494 int result = pthread_cond_signal(data_.cond());
495 VALIDATE_PTHREAD_RESULT(result);
496}
497
498void Monitor::NotifyAll() {
499 // When running with assertions enabled we track the owner.
501 int result = pthread_cond_broadcast(data_.cond());
502 VALIDATE_PTHREAD_RESULT(result);
503}
504
505} // namespace dart
506
507#endif // defined(DART_HOST_OS_FUCHSIA) && !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]
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
uint32_t * target
Dart_NativeFunction function
Definition: fuchsia.cc:51
Definition: dart_vm.cc:33
constexpr intptr_t kMicrosecondsPerMillisecond
Definition: globals.h:561
const char *const name
pthread_t ThreadJoinId
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
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)
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
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
#define NO_SANITIZE_SAFE_STACK
Definition: safe_stack.h:17