// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" // NOLINT #if defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL) #include "vm/os.h" #include "vm/os_thread.h" #include "vm/os_thread_fuchsia.h" #include // NOLINT #include #include #include #include #include #include "platform/address_sanitizer.h" #include "platform/assert.h" #include "platform/safe_stack.h" namespace dart { class ThreadStartData { public: ThreadStartData(const char* name, OSThread::ThreadStartFunction function, uword parameter) : name_(name), function_(function), parameter_(parameter) {} const char* name() const { return name_; } OSThread::ThreadStartFunction function() const { return function_; } uword parameter() const { return parameter_; } private: const char* name_; OSThread::ThreadStartFunction function_; uword parameter_; DISALLOW_COPY_AND_ASSIGN(ThreadStartData); }; // Dispatch to the thread start function provided by the caller. This trampoline // is used to ensure that the thread is properly destroyed if the thread just // exits. static void* ThreadStart(void* data_ptr) { ThreadStartData* data = reinterpret_cast(data_ptr); const char* name = data->name(); OSThread::ThreadStartFunction function = data->function(); uword parameter = data->parameter(); delete data; // Set the thread name. char truncated_name[ZX_MAX_NAME_LEN]; snprintf(truncated_name, ZX_MAX_NAME_LEN, "%s", name); zx_handle_t thread_handle = thrd_get_zx_handle(thrd_current()); zx_object_set_property(thread_handle, ZX_PROP_NAME, truncated_name, ZX_MAX_NAME_LEN); // Create new OSThread object and set as TLS for new thread. OSThread* thread = OSThread::CreateOSThread(); if (thread != nullptr) { OSThread::SetCurrent(thread); thread->SetName(name); // Call the supplied thread start function handing it its parameters. function(parameter); } return nullptr; } int OSThread::TryStart(const char* name, ThreadStartFunction function, uword parameter) { pthread_attr_t attr; int result = pthread_attr_init(&attr); RETURN_ON_PTHREAD_FAILURE(result); result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize()); RETURN_ON_PTHREAD_FAILURE(result); ThreadStartData* data = new ThreadStartData(name, function, parameter); pthread_t tid; result = pthread_create(&tid, &attr, ThreadStart, data); RETURN_ON_PTHREAD_FAILURE(result); result = pthread_attr_destroy(&attr); RETURN_ON_PTHREAD_FAILURE(result); return 0; } const ThreadJoinId OSThread::kInvalidThreadJoinId = static_cast(0); intptr_t OSThread::GetMaxStackSize() { const int kStackSize = (128 * kWordSize * KB); return kStackSize; } #ifdef SUPPORT_TIMELINE ThreadId OSThread::GetCurrentThreadTraceId() { return pthread_self(); } #endif // SUPPORT_TIMELINE char* OSThread::GetCurrentThreadName() { char* name = static_cast(malloc(ZX_MAX_NAME_LEN)); zx_handle_t thread_handle = thrd_get_zx_handle(thrd_current()); zx_object_get_property(thread_handle, ZX_PROP_NAME, name, ZX_MAX_NAME_LEN); return name; } ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) { ASSERT(thread != nullptr); // Make sure we're filling in the join id for the current thread. ASSERT(thread->id() == GetCurrentThreadId()); // Make sure the join_id_ hasn't been set, yet. DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId); pthread_t id = pthread_self(); #if defined(DEBUG) thread->join_id_ = id; #endif return id; } void OSThread::Join(ThreadJoinId id) { int result = pthread_join(id, nullptr); VALIDATE_PTHREAD_RESULT(result); } void OSThread::Detach(ThreadJoinId id) { int result = pthread_detach(id); // NOLINT VALIDATE_PTHREAD_RESULT(result); } intptr_t OSThread::ThreadIdToIntPtr(ThreadId id) { COMPILE_ASSERT(sizeof(id) <= sizeof(intptr_t)); return static_cast(id); } ThreadId OSThread::ThreadIdFromIntPtr(intptr_t id) { return static_cast(id); } bool OSThread::GetCurrentStackBounds(uword* lower, uword* upper) { pthread_attr_t attr; if (pthread_getattr_np(pthread_self(), &attr) != 0) { return false; } void* base; size_t size; int error = pthread_attr_getstack(&attr, &base, &size); pthread_attr_destroy(&attr); if (error != 0) { return false; } *lower = reinterpret_cast(base); *upper = *lower + size; return true; } #if defined(USING_SAFE_STACK) #define STRINGIFY(s) #s NO_SANITIZE_ADDRESS NO_SANITIZE_SAFE_STACK uword OSThread::GetCurrentSafestackPointer() { uword result; #if defined(HOST_ARCH_X64) #define _loadfsword(index) "movq %%fs:" STRINGIFY(index) ", %0" asm volatile(_loadfsword(ZX_TLS_UNSAFE_SP_OFFSET) : "=r"(result) // outputs ); #undef _loadfsword #elif defined(HOST_ARCH_ARM64) #define _loadword(index) "ldr %0, [%0, " STRINGIFY(index) "]" asm volatile("mrs %0, TPIDR_EL0;\n" _loadword(ZX_TLS_UNSAFE_SP_OFFSET) : "=r"(result) // outputs ); #elif defined(HOST_ARCH_RISCV64) asm volatile("ld %0, " STRINGIFY(ZX_TLS_UNSAFE_SP_OFFSET) "(tp)" : "=r"(result) // outputs ); #else #error "Architecture not supported" #endif return result; } NO_SANITIZE_ADDRESS NO_SANITIZE_SAFE_STACK void OSThread::SetCurrentSafestackPointer(uword ssp) { #if defined(HOST_ARCH_X64) #define str(s) #s #define _storefsword(index) "movq %0, %%fs:" str(index) asm volatile(_storefsword(ZX_TLS_UNSAFE_SP_OFFSET) : // outputs. : "r"(ssp) // inputs. : // clobbered. ); #undef _storefsword #undef str #elif defined(HOST_ARCH_ARM64) #define _storeword(index) "str %1, [%0, " STRINGIFY(index) "]" uword tmp; asm volatile("mrs %0, TPIDR_EL0;\n" _storeword(ZX_TLS_UNSAFE_SP_OFFSET) : "=r"(tmp) // outputs. : "r"(ssp) // inputs. : // clobbered. ); #elif defined(HOST_ARCH_RISCV64) asm volatile("sd %0, " STRINGIFY(ZX_TLS_UNSAFE_SP_OFFSET) "(tp)" : // outputs. : "r"(ssp) // inputs. : // clobbered. ); #else #error "Architecture not supported" #endif } #undef STRINGIFY #endif } // namespace dart #endif // defined(DART_HOST_OS_FUCHSIA) && !defined(DART_USE_ABSL)