| // 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 { | 
 |  | 
 | #ifndef PRODUCT | 
 |  | 
 | 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<uintptr_t>(context.Eip); | 
 |       state->fp = static_cast<uintptr_t>(context.Ebp); | 
 |       state->csp = static_cast<uintptr_t>(context.Esp); | 
 |       state->dsp = static_cast<uintptr_t>(context.Esp); | 
 | #elif defined(HOST_ARCH_X64) | 
 |       state->pc = static_cast<uintptr_t>(context.Rip); | 
 |       state->fp = static_cast<uintptr_t>(context.Rbp); | 
 |       state->csp = static_cast<uintptr_t>(context.Rsp); | 
 |       state->dsp = static_cast<uintptr_t>(context.Rsp); | 
 | #elif defined(HOST_ARCH_ARM) | 
 |       state->pc = static_cast<uintptr_t>(context.Pc); | 
 |       state->fp = static_cast<uintptr_t>(context.R11); | 
 |       state->csp = static_cast<uintptr_t>(context.Sp); | 
 |       state->dsp = static_cast<uintptr_t>(context.Sp); | 
 | #elif defined(HOST_ARCH_ARM64) | 
 |       state->pc = static_cast<uintptr_t>(context.Pc); | 
 |       state->fp = static_cast<uintptr_t>(context.Fp); | 
 |       state->csp = static_cast<uintptr_t>(context.Sp); | 
 |       state->dsp = static_cast<uintptr_t>(context.X15); | 
 | #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<void*>(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<void*>(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<Thread*>(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<void*>(thread->id())); | 
 |   } | 
 |   ThreadInterrupterWin::Interrupt(thread); | 
 |   if (FLAG_trace_thread_interrupter) { | 
 |     OS::PrintErr("ThreadInterrupter resuming %p\n", | 
 |                  reinterpret_cast<void*>(thread->id())); | 
 |   } | 
 | } | 
 |  | 
 | void ThreadInterrupter::InstallSignalHandler() { | 
 |   // Nothing to do on Windows. | 
 | } | 
 |  | 
 | void ThreadInterrupter::RemoveSignalHandler() { | 
 |   // Nothing to do on Windows. | 
 | } | 
 |  | 
 | #endif  // !PRODUCT | 
 |  | 
 | }  // namespace dart | 
 |  | 
 | #endif  // defined(DART_HOST_OS_WINDOWS) |