6#if defined(DART_HOST_OS_FUCHSIA)
10#include <zircon/process.h>
11#include <zircon/status.h>
12#include <zircon/syscalls.h>
13#include <zircon/syscalls/debug.h>
14#include <zircon/syscalls/object.h>
15#include <zircon/types.h>
36class ThreadSuspendScope {
38 explicit ThreadSuspendScope(zx_handle_t thread_handle)
39 : thread_handle_(thread_handle), suspend_token_(ZX_HANDLE_INVALID) {
40 zx_status_t status = zx_task_suspend_token(thread_handle, &suspend_token_);
43 if (status != ZX_OK) {
44 if (FLAG_trace_thread_interrupter) {
45 OS::PrintErr(
"ThreadInterrupter: zx_task_suspend failed: %s\n",
46 zx_status_get_string(status));
51 ~ThreadSuspendScope() {
52 if (suspend_token_ != ZX_HANDLE_INVALID) {
53 zx_handle_close(suspend_token_);
55 zx_handle_close(thread_handle_);
58 bool suspended()
const {
return suspend_token_ != ZX_HANDLE_INVALID; }
61 zx_handle_t thread_handle_;
62 zx_handle_t suspend_token_;
68class ThreadInterrupterFuchsia :
public AllStatic {
70 static bool GrabRegisters(zx_handle_t thread, InterruptedThreadState*
state) {
71 zx_thread_state_general_regs_t regs;
72 zx_status_t status = zx_thread_read_state(
73 thread, ZX_THREAD_STATE_GENERAL_REGS, ®s,
sizeof(regs));
74 if (status != ZX_OK) {
75 if (FLAG_trace_thread_interrupter) {
76 OS::PrintErr(
"ThreadInterrupter failed to get registers: %s\n",
77 zx_status_get_string(status));
81#if defined(TARGET_ARCH_X64)
82 state->pc =
static_cast<uintptr_t
>(regs.rip);
83 state->fp =
static_cast<uintptr_t
>(regs.rbp);
84 state->csp =
static_cast<uintptr_t
>(regs.rsp);
85 state->dsp =
static_cast<uintptr_t
>(regs.rsp);
87#elif defined(TARGET_ARCH_ARM64)
88 state->pc =
static_cast<uintptr_t
>(regs.pc);
89 state->fp =
static_cast<uintptr_t
>(regs.r[
FPREG]);
90 state->csp =
static_cast<uintptr_t
>(regs.sp);
91 state->dsp =
static_cast<uintptr_t
>(regs.r[
SPREG]);
92 state->lr =
static_cast<uintptr_t
>(regs.lr);
93#elif defined(TARGET_ARCH_RISCV64)
94 state->pc =
static_cast<uintptr_t
>(regs.pc);
95 state->fp =
static_cast<uintptr_t
>(regs.r[
FPREG]);
96 state->csp =
static_cast<uintptr_t
>(regs.r[
SPREG]);
97 state->dsp =
static_cast<uintptr_t
>(regs.r[
SPREG]);
100#error "Unsupported architecture"
105 static void Interrupt(OSThread* os_thread) {
106 ASSERT(os_thread->id() != ZX_KOID_INVALID);
111 const zx_koid_t target_thread_koid = os_thread->id();
112 if (FLAG_trace_thread_interrupter) {
113 OS::PrintErr(
"ThreadInterrupter: interrupting thread with koid=%ld\n",
116 zx_handle_t target_thread_handle;
117 status = zx_object_get_child(zx_process_self(), target_thread_koid,
118 ZX_RIGHT_SAME_RIGHTS, &target_thread_handle);
119 if (status != ZX_OK) {
120 if (FLAG_trace_thread_interrupter) {
121 OS::PrintErr(
"ThreadInterrupter: zx_object_get_child failed: %s\n",
122 zx_status_get_string(status));
126 if (target_thread_handle == ZX_HANDLE_INVALID) {
127 if (FLAG_trace_thread_interrupter) {
129 "ThreadInterrupter: zx_object_get_child gave an invalid "
137 ThreadSuspendScope tss(target_thread_handle);
138 if (!tss.suspended()) {
143 status = PollThreadUntilSuspended(target_thread_handle);
144 if (status != ZX_OK) {
149 InterruptedThreadState its;
150 if (!GrabRegisters(target_thread_handle, &its)) {
156 Thread* thread =
static_cast<Thread*
>(os_thread->thread());
157 if (thread !=
nullptr) {
158 ThreadInterruptScope signal_handler_scope;
164 static const char* ThreadStateGetString(uint32_t
state) {
167#ifdef ZX_THREAD_STATE_BASIC
171 case ZX_THREAD_STATE_NEW:
172 return "ZX_THREAD_STATE_NEW";
173 case ZX_THREAD_STATE_RUNNING:
174 return "ZX_THREAD_STATE_RUNNING";
175 case ZX_THREAD_STATE_SUSPENDED:
176 return "ZX_THREAD_STATE_SUSPENDED";
177 case ZX_THREAD_STATE_BLOCKED:
178 return "ZX_THREAD_STATE_BLOCKED";
179 case ZX_THREAD_STATE_DYING:
180 return "ZX_THREAD_STATE_DYING";
181 case ZX_THREAD_STATE_DEAD:
182 return "ZX_THREAD_STATE_DEAD";
188 static zx_status_t PollThreadUntilSuspended(zx_handle_t thread_handle) {
189 const intptr_t kMaxPollAttempts = 10;
190 intptr_t poll_tries = 0;
191 while (poll_tries < kMaxPollAttempts) {
192 zx_info_thread_t thread_info;
194 zx_object_get_info(thread_handle, ZX_INFO_THREAD, &thread_info,
195 sizeof(thread_info),
nullptr,
nullptr);
197 if (status != ZX_OK) {
198 if (FLAG_trace_thread_interrupter) {
199 OS::PrintErr(
"ThreadInterrupter: zx_object_get_info failed: %s\n",
200 zx_status_get_string(status));
204 if (thread_info.state == ZX_THREAD_STATE_SUSPENDED) {
208 if (thread_info.state == ZX_THREAD_STATE_RUNNING) {
212 if (FLAG_trace_thread_interrupter) {
213 OS::PrintErr(
"ThreadInterrupter: Thread is not suspended: %s\n",
214 ThreadStateGetString(thread_info.state));
216 return ZX_ERR_BAD_STATE;
218 if (FLAG_trace_thread_interrupter) {
219 OS::PrintErr(
"ThreadInterrupter: Exceeded max suspend poll tries\n");
221 return ZX_ERR_BAD_STATE;
226 if (FLAG_trace_thread_interrupter) {
228 reinterpret_cast<void*
>(thread->id()));
230 ThreadInterrupterFuchsia::Interrupt(thread);
231 if (FLAG_trace_thread_interrupter) {
233 reinterpret_cast<void*
>(thread->id()));
237void ThreadInterrupter::InstallSignalHandler() {
241void ThreadInterrupter::RemoveSignalHandler() {
static ThreadId GetCurrentThreadId()
static bool Compare(ThreadId a, ThreadId b)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void SampleThread(Thread *thread, const InterruptedThreadState &state)
static void InterruptThread(OSThread *thread)
DECLARE_FLAG(bool, show_invisible_frames)