blob: e9243a24973c2de5f9ac5b0aa85c2a52f94aaf8b [file] [log] [blame]
// 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;
}
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)