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(HOST_OS_FUCHSIA)
7
8#include "vm/os.h"
9#include "vm/os_thread.h"
10#include "vm/os_thread_fuchsia.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
19#include "platform/address_sanitizer.h"
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 FATAL1("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 FATAL2("[%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,
71 OSThread::ThreadStartFunction function,
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_;
81 OSThread::ThreadStartFunction function_;
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();
94 OSThread::ThreadStartFunction function = data->function();
95 uword parameter = data->parameter();
96 delete data;
97
98 // Set the thread name.
99 zx_handle_t thread_handle = thrd_get_zx_handle(thrd_current());
100 zx_object_set_property(thread_handle, ZX_PROP_NAME, name, strlen(name) + 1);
101
102 // Create new OSThread object and set as TLS for new thread.
103 OSThread* thread = OSThread::CreateOSThread();
104 if (thread != NULL) {
105 OSThread::SetCurrent(thread);
106 thread->set_name(name);
107 // Call the supplied thread start function handing it its parameters.
108 function(parameter);
109 }
110
111 return NULL;
112}
113
114int OSThread::Start(const char* name,
115 ThreadStartFunction function,
116 uword parameter) {
117 pthread_attr_t attr;
118 int result = pthread_attr_init(&attr);
119 RETURN_ON_PTHREAD_FAILURE(result);
120
121 result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
122 RETURN_ON_PTHREAD_FAILURE(result);
123
124 ThreadStartData* data = new ThreadStartData(name, function, parameter);
125
126 pthread_t tid;
127 result = pthread_create(&tid, &attr, ThreadStart, data);
128 RETURN_ON_PTHREAD_FAILURE(result);
129
130 result = pthread_attr_destroy(&attr);
131 RETURN_ON_PTHREAD_FAILURE(result);
132
133 return 0;
134}
135
136const ThreadId OSThread::kInvalidThreadId = ZX_KOID_INVALID;
137const ThreadJoinId OSThread::kInvalidThreadJoinId =
138 static_cast<ThreadJoinId>(0);
139
140ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
141 pthread_key_t key = kUnsetThreadLocalKey;
142 int result = pthread_key_create(&key, destructor);
143 VALIDATE_PTHREAD_RESULT(result);
144 ASSERT(key != kUnsetThreadLocalKey);
145 return key;
146}
147
148void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
149 ASSERT(key != kUnsetThreadLocalKey);
150 int result = pthread_key_delete(key);
151 VALIDATE_PTHREAD_RESULT(result);
152}
153
154void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
155 ASSERT(key != kUnsetThreadLocalKey);
156 int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
157 VALIDATE_PTHREAD_RESULT(result);
158}
159
160intptr_t OSThread::GetMaxStackSize() {
161 const int kStackSize = (128 * kWordSize * KB);
162 return kStackSize;
163}
164
165ThreadId OSThread::GetCurrentThreadId() {
166 zx_info_handle_basic_t info;
167 zx_handle_t thread_handle = thrd_get_zx_handle(thrd_current());
168 zx_status_t status =
169 zx_object_get_info(thread_handle, ZX_INFO_HANDLE_BASIC, &info,
170 sizeof(info), nullptr, nullptr);
171 if (status != ZX_OK) {
172 FATAL1("Failed to get thread koid: %s\n", zx_status_get_string(status));
173 }
174 return info.koid;
175}
176
177#ifdef SUPPORT_TIMELINE
178ThreadId OSThread::GetCurrentThreadTraceId() {
179 return pthread_self();
180}
181#endif // PRODUCT
182
183ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
184 ASSERT(thread != NULL);
185 // Make sure we're filling in the join id for the current thread.
186 ASSERT(thread->id() == GetCurrentThreadId());
187 // Make sure the join_id_ hasn't been set, yet.
188 DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
189 pthread_t id = pthread_self();
190#if defined(DEBUG)
191 thread->join_id_ = id;
192#endif
193 return id;
194}
195
196void OSThread::Join(ThreadJoinId id) {
197 int result = pthread_join(id, NULL);
198 ASSERT(result == 0);
199}
200
201intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) {
202 ASSERT(sizeof(id) == sizeof(intptr_t));
203 return static_cast<intptr_t>(id);
204}
205
206ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) {
207 return static_cast<ThreadId>(id);
208}
209
210bool OSThread::Compare(ThreadId a, ThreadId b) {
211 return pthread_equal(a, b) != 0;
212}
213
214bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) {
215 pthread_attr_t attr;
216 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
217 return false;
218 }
219
220 void* base;
221 size_t size;
222 int error = pthread_attr_getstack(&attr, &base, &size);
223 pthread_attr_destroy(&attr);
224 if (error != 0) {
225 return false;
226 }
227
228 *lower = reinterpret_cast<uword>(base);
229 *upper = *lower + size;
230 return true;
231}
232
233#if defined(USING_SAFE_STACK)
234#define STRINGIFY(s) #s
235NO_SANITIZE_ADDRESS
236NO_SANITIZE_SAFE_STACK
237uword OSThread::GetCurrentSafestackPointer() {
238 uword result;
239#if defined(HOST_ARCH_X64)
240#define _loadfsword(index) "movq %%fs:" STRINGIFY(index) ", %0"
241 asm volatile(
242 _loadfsword(ZX_TLS_UNSAFE_SP_OFFSET)
243 : "=r"(result) // outputs
244 );
245#undef _loadfsword
246#elif defined(HOST_ARCH_ARM64)
247#define _loadword(index) "ldr %0, [%0, " STRINGIFY(index) "]"
248 asm volatile(
249 "mrs %0, TPIDR_EL0;\n"
250 _loadword(ZX_TLS_UNSAFE_SP_OFFSET)
251 : "=r"(result) // outputs
252 );
253#else
254#error "Architecture not supported"
255#endif
256 return result;
257}
258
259NO_SANITIZE_ADDRESS
260NO_SANITIZE_SAFE_STACK
261void OSThread::SetCurrentSafestackPointer(uword ssp) {
262#if defined(HOST_ARCH_X64)
263#define str(s) #s
264#define _storefsword(index) "movq %0, %%fs:" str(index)
265 asm volatile(
266 _storefsword(ZX_TLS_UNSAFE_SP_OFFSET)
267 : // outputs.
268 : "r"(ssp) // inputs.
269 : // clobbered.
270 );
271#undef _storefsword
272#undef str
273#elif defined(HOST_ARCH_ARM64)
274#define _storeword(index) "str %1, [%0, " STRINGIFY(index) "]"
275 uword tmp;
276 asm volatile(
277 "mrs %0, TPIDR_EL0;\n"
278 _storeword(ZX_TLS_UNSAFE_SP_OFFSET)
279 : "=r"(tmp) // outputs.
280 : "r"(ssp) // inputs.
281 : // clobbered.
282 );
283#else
284#error "Architecture not supported"
285#endif
286}
287#undef STRINGIFY
288#endif
289
290Mutex::Mutex(NOT_IN_PRODUCT(const char* name))
291#if !defined(PRODUCT)
292 : name_(name)
293#endif
294{
295 pthread_mutexattr_t attr;
296 int result = pthread_mutexattr_init(&attr);
297 VALIDATE_PTHREAD_RESULT_NAMED(result);
298
299#if defined(DEBUG)
300 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
301 VALIDATE_PTHREAD_RESULT_NAMED(result);
302#endif // defined(DEBUG)
303
304 result = pthread_mutex_init(data_.mutex(), &attr);
305 // Verify that creating a pthread_mutex succeeded.
306 VALIDATE_PTHREAD_RESULT_NAMED(result);
307
308 result = pthread_mutexattr_destroy(&attr);
309 VALIDATE_PTHREAD_RESULT_NAMED(result);
310
311#if defined(DEBUG)
312 // When running with assertions enabled we track the owner.
313 owner_ = OSThread::kInvalidThreadId;
314#endif // defined(DEBUG)
315}
316
317Mutex::~Mutex() {
318 int result = pthread_mutex_destroy(data_.mutex());
319 // Verify that the pthread_mutex was destroyed.
320 VALIDATE_PTHREAD_RESULT_NAMED(result);
321
322#if defined(DEBUG)
323 // When running with assertions enabled we track the owner.
324 ASSERT(owner_ == OSThread::kInvalidThreadId);
325#endif // defined(DEBUG)
326}
327
328void Mutex::Lock() {
329 int result = pthread_mutex_lock(data_.mutex());
330 // Specifically check for dead lock to help debugging.
331 ASSERT(result != EDEADLK);
332 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
333#if defined(DEBUG)
334 // When running with assertions enabled we track the owner.
335 owner_ = OSThread::GetCurrentThreadId();
336#endif // defined(DEBUG)
337}
338
339bool Mutex::TryLock() {
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.
348 owner_ = OSThread::GetCurrentThreadId();
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.
356 ASSERT(IsOwnedByCurrentThread());
357 owner_ = OSThread::kInvalidThreadId;
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
365Monitor::Monitor() {
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.
396 owner_ = OSThread::kInvalidThreadId;
397#endif // defined(DEBUG)
398}
399
400Monitor::~Monitor() {
401#if defined(DEBUG)
402 // When running with assertions enabled we track the owner.
403 ASSERT(owner_ == OSThread::kInvalidThreadId);
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 int result = pthread_mutex_trylock(data_.mutex());
415 // Return false if the lock is busy and locking failed.
416 if (result == EBUSY) {
417 return false;
418 }
419 ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
420#if defined(DEBUG)
421 // When running with assertions enabled we track the owner.
422 ASSERT(owner_ == OSThread::kInvalidThreadId);
423 owner_ = OSThread::GetCurrentThreadId();
424#endif // defined(DEBUG)
425 return true;
426}
427
428void Monitor::Enter() {
429 int result = pthread_mutex_lock(data_.mutex());
430 VALIDATE_PTHREAD_RESULT(result);
431
432#if defined(DEBUG)
433 // When running with assertions enabled we track the owner.
434 ASSERT(owner_ == OSThread::kInvalidThreadId);
435 owner_ = OSThread::GetCurrentThreadId();
436#endif // defined(DEBUG)
437}
438
439void Monitor::Exit() {
440#if defined(DEBUG)
441 // When running with assertions enabled we track the owner.
442 ASSERT(IsOwnedByCurrentThread());
443 owner_ = OSThread::kInvalidThreadId;
444#endif // defined(DEBUG)
445
446 int result = pthread_mutex_unlock(data_.mutex());
447 VALIDATE_PTHREAD_RESULT(result);
448}
449
450Monitor::WaitResult Monitor::Wait(int64_t millis) {
451 Monitor::WaitResult retval = WaitMicros(millis * kMicrosecondsPerMillisecond);
452 return retval;
453}
454
455Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
456#if defined(DEBUG)
457 // When running with assertions enabled we track the owner.
458 ASSERT(IsOwnedByCurrentThread());
459 ThreadId saved_owner = owner_;
460 owner_ = OSThread::kInvalidThreadId;
461#endif // defined(DEBUG)
462
463 Monitor::WaitResult retval = kNotified;
464 if (micros == kNoTimeout) {
465 // Wait forever.
466 int result = pthread_cond_wait(data_.cond(), data_.mutex());
467 VALIDATE_PTHREAD_RESULT(result);
468 } else {
469 struct timespec ts;
470 ComputeTimeSpecMicros(&ts, micros);
471 int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
472 ASSERT((result == 0) || (result == ETIMEDOUT));
473 if (result == ETIMEDOUT) {
474 retval = kTimedOut;
475 }
476 }
477
478#if defined(DEBUG)
479 // When running with assertions enabled we track the owner.
480 ASSERT(owner_ == OSThread::kInvalidThreadId);
481 owner_ = OSThread::GetCurrentThreadId();
482 ASSERT(owner_ == saved_owner);
483#endif // defined(DEBUG)
484 return retval;
485}
486
487void Monitor::Notify() {
488 // When running with assertions enabled we track the owner.
489 ASSERT(IsOwnedByCurrentThread());
490 int result = pthread_cond_signal(data_.cond());
491 VALIDATE_PTHREAD_RESULT(result);
492}
493
494void Monitor::NotifyAll() {
495 // When running with assertions enabled we track the owner.
496 ASSERT(IsOwnedByCurrentThread());
497 int result = pthread_cond_broadcast(data_.cond());
498 VALIDATE_PTHREAD_RESULT(result);
499}
500
501} // namespace dart
502
503#endif // defined(HOST_OS_FUCHSIA)
504