| // 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 <assert.h> // NOLINT |
| #include <errno.h> // NOLINT |
| #include <mach/kern_return.h> // NOLINT |
| #include <mach/mach.h> // NOLINT |
| #include <mach/thread_act.h> // NOLINT |
| #include <stdbool.h> // NOLINT |
| #include <sys/sysctl.h> // NOLINT |
| #include <sys/types.h> // NOLINT |
| #include <unistd.h> // 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<void*>(mach_thread_) != nullptr); |
| res = thread_suspend(mach_thread_); |
| } |
| |
| void CollectSample() { |
| if (res != KERN_SUCCESS) { |
| return; |
| } |
| auto count = static_cast<mach_msg_type_number_t>(THREAD_STATE_FLAVOR_SIZE); |
| thread_state_flavor_t state; |
| kern_return_t res = |
| thread_get_state(mach_thread_, THREAD_STATE_FLAVOR, |
| reinterpret_cast<thread_state_t>(&state), &count); |
| ASSERT(res == KERN_SUCCESS); |
| Thread* thread = static_cast<Thread*>(os_thread_->thread()); |
| if (thread == nullptr) { |
| return; |
| } |
| 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()); |
| } |
| |
| ThreadInterrupter::SampleBufferWriterScope scope; |
| if (!scope.CanSample()) { |
| return; |
| } |
| 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) |