// Copyright (c) 2013, 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" #if defined(DART_HOST_OS_MACOS) #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include "vm/flags.h" #include "vm/os.h" #include "vm/profiler.h" #include "vm/signal_handler.h" #include "vm/thread_interrupter.h" namespace dart { #ifndef PRODUCT DECLARE_FLAG(bool, trace_thread_interrupter); #if defined(HOST_ARCH_X64) #define THREAD_STATE_FLAVOR x86_THREAD_STATE64 #define THREAD_STATE_FLAVOR_SIZE x86_THREAD_STATE64_COUNT typedef x86_thread_state64_t thread_state_flavor_t; #elif defined(HOST_ARCH_ARM64) #define THREAD_STATE_FLAVOR ARM_THREAD_STATE64 #define THREAD_STATE_FLAVOR_SIZE ARM_THREAD_STATE64_COUNT typedef arm_thread_state64_t thread_state_flavor_t; #elif defined(HOST_ARCH_ARM) #define THREAD_STATE_FLAVOR ARM_THREAD_STATE32 #define THREAD_STATE_FLAVOR_SIZE ARM_THREAD_STATE32_COUNT typedef arm_thread_state32_t thread_state_flavor_t; #else #error "Unsupported architecture." #endif // HOST_ARCH_... class ThreadInterrupterMacOS { public: explicit ThreadInterrupterMacOS(OSThread* os_thread) : os_thread_(os_thread) { ASSERT(os_thread != nullptr); mach_thread_ = pthread_mach_thread_np(os_thread->id()); ASSERT(reinterpret_cast(mach_thread_) != nullptr); res = thread_suspend(mach_thread_); } void CollectSample() { if (res != KERN_SUCCESS) { return; } auto count = static_cast(THREAD_STATE_FLAVOR_SIZE); thread_state_flavor_t state; kern_return_t res = thread_get_state(mach_thread_, THREAD_STATE_FLAVOR, reinterpret_cast(&state), &count); ASSERT(res == KERN_SUCCESS); Thread* thread = static_cast(os_thread_->thread()); if (thread == nullptr) { return; } ThreadInterruptScope signal_handler_scope; Profiler::SampleThread(thread, ProcessState(state)); } ~ThreadInterrupterMacOS() { if (res != KERN_SUCCESS) { return; } res = thread_resume(mach_thread_); ASSERT(res == KERN_SUCCESS); } private: static InterruptedThreadState ProcessState(thread_state_flavor_t state) { InterruptedThreadState its; #if defined(HOST_ARCH_X64) its.pc = state.__rip; its.fp = state.__rbp; its.csp = state.__rsp; its.dsp = state.__rsp; its.lr = 0; #elif defined(HOST_ARCH_ARM64) its.pc = state.__pc; its.fp = state.__fp; its.csp = state.__sp; its.dsp = state.__sp; its.lr = state.__lr; #elif defined(HOST_ARCH_ARM) its.pc = state.__pc; its.fp = state.__r[7]; its.csp = state.__sp; its.dsp = state.__sp; its.lr = state.__lr; #endif // HOST_ARCH_... #if defined(TARGET_ARCH_ARM64) && !defined(USING_SIMULATOR) its.dsp = state.__x[SPREG]; #endif return its; } kern_return_t res; OSThread* os_thread_; mach_port_t mach_thread_; }; void ThreadInterrupter::InterruptThread(OSThread* os_thread) { ASSERT(!OSThread::Compare(OSThread::GetCurrentThreadId(), os_thread->id())); if (FLAG_trace_thread_interrupter) { OS::PrintErr("ThreadInterrupter interrupting %p\n", os_thread->id()); } ThreadInterrupterMacOS interrupter(os_thread); interrupter.CollectSample(); } void ThreadInterrupter::InstallSignalHandler() { // Nothing to do on MacOS. } void ThreadInterrupter::RemoveSignalHandler() { // Nothing to do on MacOS. } #endif // !PRODUCT } // namespace dart #endif // defined(DART_HOST_OS_MACOS)