1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(HOST_OS_WINDOWS)
7
8#include "vm/flags.h"
9#include "vm/os.h"
10#include "vm/profiler.h"
11#include "vm/thread_interrupter.h"
12
13namespace dart {
14
15#ifndef PRODUCT
16
17DECLARE_FLAG(bool, trace_thread_interrupter);
18
19#define kThreadError -1
20
21class ThreadInterrupterWin : public AllStatic {
22 public:
23 static bool GrabRegisters(HANDLE handle, InterruptedThreadState* state) {
24 CONTEXT context;
25 memset(&context, 0, sizeof(context));
26#if defined(HOST_ARCH_IA32)
27 // On IA32, CONTEXT_CONTROL includes Eip, Ebp, and Esp.
28 context.ContextFlags = CONTEXT_CONTROL;
29#elif defined(HOST_ARCH_X64)
30 // On X64, CONTEXT_CONTROL includes Rip and Rsp. Rbp is classified
31 // as an "integer" register.
32 context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
33#else
34#error Unsupported architecture.
35#endif
36 if (GetThreadContext(handle, &context) != 0) {
37#if defined(HOST_ARCH_IA32)
38 state->pc = static_cast<uintptr_t>(context.Eip);
39 state->fp = static_cast<uintptr_t>(context.Ebp);
40 state->csp = static_cast<uintptr_t>(context.Esp);
41 state->dsp = static_cast<uintptr_t>(context.Esp);
42#elif defined(HOST_ARCH_X64)
43 state->pc = static_cast<uintptr_t>(context.Rip);
44 state->fp = static_cast<uintptr_t>(context.Rbp);
45 state->csp = static_cast<uintptr_t>(context.Rsp);
46 state->dsp = static_cast<uintptr_t>(context.Rsp);
47#else
48#error Unsupported architecture.
49#endif
50 return true;
51 }
52 return false;
53 }
54
55 static void Interrupt(OSThread* os_thread) {
56 ASSERT(!OSThread::Compare(GetCurrentThreadId(), os_thread->id()));
57 HANDLE handle = OpenThread(
58 THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME,
59 false, os_thread->id());
60 ASSERT(handle != NULL);
61 DWORD result = SuspendThread(handle);
62 if (result == kThreadError) {
63 if (FLAG_trace_thread_interrupter) {
64 OS::PrintErr("ThreadInterrupter failed to suspend thread %p\n",
65 reinterpret_cast<void*>(os_thread->id()));
66 }
67 CloseHandle(handle);
68 return;
69 }
70 InterruptedThreadState its;
71 if (!GrabRegisters(handle, &its)) {
72 // Failed to get thread registers.
73 ResumeThread(handle);
74 if (FLAG_trace_thread_interrupter) {
75 OS::PrintErr("ThreadInterrupter failed to get registers for %p\n",
76 reinterpret_cast<void*>(os_thread->id()));
77 }
78 CloseHandle(handle);
79 return;
80 }
81 // Currently we sample only threads that are associated
82 // with an isolate. It is safe to call 'os_thread->thread()'
83 // here as the thread which is being queried is suspended.
84 Thread* thread = static_cast<Thread*>(os_thread->thread());
85 if (thread != NULL) {
86 Profiler::SampleThread(thread, its);
87 }
88 ResumeThread(handle);
89 CloseHandle(handle);
90 }
91};
92
93bool ThreadInterrupter::IsDebuggerAttached() {
94 return false;
95}
96
97void ThreadInterrupter::InterruptThread(OSThread* thread) {
98 if (FLAG_trace_thread_interrupter) {
99 OS::PrintErr("ThreadInterrupter suspending %p\n",
100 reinterpret_cast<void*>(thread->id()));
101 }
102 ThreadInterrupterWin::Interrupt(thread);
103 if (FLAG_trace_thread_interrupter) {
104 OS::PrintErr("ThreadInterrupter resuming %p\n",
105 reinterpret_cast<void*>(thread->id()));
106 }
107}
108
109void ThreadInterrupter::InstallSignalHandler() {
110 // Nothing to do on Windows.
111}
112
113void ThreadInterrupter::RemoveSignalHandler() {
114 // Nothing to do on Windows.
115}
116
117#endif // !PRODUCT
118
119} // namespace dart
120
121#endif // defined(HOST_OS_WINDOWS)
122