// 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_WINDOWS) #include "vm/flags.h" #include "vm/os.h" #include "vm/profiler.h" #include "vm/thread_interrupter.h" namespace dart { #if defined(DART_INCLUDE_PROFILER) DECLARE_FLAG(bool, trace_thread_interrupter); #define kThreadError -1 class ThreadInterrupterWin : public AllStatic { public: static bool GrabRegisters(HANDLE handle, InterruptedThreadState* state) { CONTEXT context; memset(&context, 0, sizeof(context)); #if defined(HOST_ARCH_IA32) // On IA32, CONTEXT_CONTROL includes Eip, Ebp, and Esp. context.ContextFlags = CONTEXT_CONTROL; #elif defined(HOST_ARCH_X64) || defined(HOST_ARCH_ARM) || \ defined(HOST_ARCH_ARM64) // On X64, CONTEXT_CONTROL includes Rip and Rsp. Rbp is classified // as an "integer" register. context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; #else #error Unsupported architecture. #endif if (GetThreadContext(handle, &context) != 0) { #if defined(HOST_ARCH_IA32) state->pc = static_cast(context.Eip); state->fp = static_cast(context.Ebp); state->csp = static_cast(context.Esp); state->dsp = static_cast(context.Esp); state->lr = 0; #elif defined(HOST_ARCH_X64) state->pc = static_cast(context.Rip); state->fp = static_cast(context.Rbp); state->csp = static_cast(context.Rsp); state->dsp = static_cast(context.Rsp); state->lr = 0; #elif defined(HOST_ARCH_ARM) state->pc = static_cast(context.Pc); state->fp = static_cast(context.R11); state->csp = static_cast(context.Sp); state->dsp = static_cast(context.Sp); state->lr = static_cast(context.R14); #elif defined(HOST_ARCH_ARM64) state->pc = static_cast(context.Pc); state->fp = static_cast(context.Fp); state->csp = static_cast(context.Sp); state->dsp = static_cast(context.X15); state->lr = static_cast(context.Lr); #else #error Unsupported architecture. #endif return true; } return false; } static void Interrupt(OSThread* os_thread) { ASSERT(!OSThread::Compare(GetCurrentThreadId(), os_thread->id())); HANDLE handle = OpenThread( THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME, false, os_thread->id()); ASSERT(handle != nullptr); DWORD result = SuspendThread(handle); if (result == kThreadError) { if (FLAG_trace_thread_interrupter) { OS::PrintErr("ThreadInterrupter failed to suspend thread %p\n", reinterpret_cast(os_thread->id())); } CloseHandle(handle); return; } InterruptedThreadState its; if (!GrabRegisters(handle, &its)) { // Failed to get thread registers. ResumeThread(handle); if (FLAG_trace_thread_interrupter) { OS::PrintErr("ThreadInterrupter failed to get registers for %p\n", reinterpret_cast(os_thread->id())); } CloseHandle(handle); return; } // Currently we sample only threads that are associated // with an isolate. It is safe to call 'os_thread->thread()' // here as the thread which is being queried is suspended. Thread* thread = static_cast(os_thread->thread()); if (thread != nullptr) { ThreadInterruptScope signal_handler_scope; Profiler::SampleThread(thread, its); } ResumeThread(handle); CloseHandle(handle); } }; void ThreadInterrupter::InterruptThread(OSThread* thread) { if (FLAG_trace_thread_interrupter) { OS::PrintErr("ThreadInterrupter suspending %p\n", reinterpret_cast(thread->id())); } ThreadInterrupterWin::Interrupt(thread); if (FLAG_trace_thread_interrupter) { OS::PrintErr("ThreadInterrupter resuming %p\n", reinterpret_cast(thread->id())); } } void ThreadInterrupter::InstallSignalHandler() { // Nothing to do on Windows. } void ThreadInterrupter::RemoveSignalHandler() { // Nothing to do on Windows. } #endif // defined(DART_INCLUDE_PROFILER) } // namespace dart #endif // defined(DART_HOST_OS_WINDOWS)