| OLD | NEW | 
|---|
| 1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "platform/globals.h" | 5 #include "platform/globals.h" | 
| 6 #if defined(HOST_OS_FUCHSIA) | 6 #if defined(HOST_OS_FUCHSIA) | 
| 7 | 7 | 
| 8 #include "vm/thread_interrupter.h" | 8 #include "vm/thread_interrupter.h" | 
| 9 | 9 | 
| 10 #include "platform/assert.h" | 10 #include <magenta/process.h> | 
|  | 11 #include <magenta/status.h> | 
|  | 12 #include <magenta/syscalls.h> | 
|  | 13 #include <magenta/syscalls/debug.h> | 
|  | 14 #include <magenta/types.h> | 
|  | 15 | 
|  | 16 #include "vm/flags.h" | 
|  | 17 #include "vm/instructions.h" | 
|  | 18 #include "vm/os.h" | 
|  | 19 #include "vm/profiler.h" | 
| 11 | 20 | 
| 12 namespace dart { | 21 namespace dart { | 
| 13 | 22 | 
|  | 23 #ifndef PRODUCT | 
|  | 24 | 
|  | 25 DECLARE_FLAG(bool, thread_interrupter); | 
|  | 26 DECLARE_FLAG(bool, trace_thread_interrupter); | 
|  | 27 | 
|  | 28 // TODO(MG-430): Currently, CPU profiling for Fuchsia is arranged very similarly | 
|  | 29 // to our Windows profiling. That is, the interrupter thread iterates over | 
|  | 30 // all threads, suspends them, samples various things, and then resumes them. | 
|  | 31 // When MG-430 is resolved, the code below should be rewritten to use whatever | 
|  | 32 // feature is added for it. | 
|  | 33 | 
|  | 34 // TODO(zra): The profiler is currently off by default on Fuchsia because | 
|  | 35 // suspending a thread that is in a call to pthread_cond_wait() causes | 
|  | 36 // pthread_cond_wait() to return ETIMEDOUT. | 
|  | 37 | 
|  | 38 class ThreadInterrupterFuchsia : public AllStatic { | 
|  | 39  public: | 
|  | 40   static bool GrabRegisters(mx_handle_t thread, InterruptedThreadState* state) { | 
|  | 41     // TODO(zra): Enable this when mx_thread_read_state() works on suspended | 
|  | 42     // threads. | 
|  | 43     while (false) { | 
|  | 44       char buf[MX_MAX_THREAD_STATE_SIZE]; | 
|  | 45       uint32_t regset_size = MX_MAX_THREAD_STATE_SIZE; | 
|  | 46       mx_status_t status = mx_thread_read_state( | 
|  | 47           thread, MX_THREAD_STATE_REGSET0, &buf[0], regset_size, ®set_size); | 
|  | 48       if (status != NO_ERROR) { | 
|  | 49         OS::PrintErr("ThreadInterrupter failed to get registers: %s\n", | 
|  | 50                      mx_status_get_string(status)); | 
|  | 51         return false; | 
|  | 52       } | 
|  | 53 #if defined(TARGET_ARCH_X64) | 
|  | 54       mx_x86_64_general_regs_t* regs = | 
|  | 55           reinterpret_cast<mx_x86_64_general_regs_t*>(&buf[0]); | 
|  | 56       state->pc = static_cast<uintptr_t>(regs->rip); | 
|  | 57       state->fp = static_cast<uintptr_t>(regs->rbp); | 
|  | 58       state->csp = static_cast<uintptr_t>(regs->rsp); | 
|  | 59       state->dsp = static_cast<uintptr_t>(regs->rsp); | 
|  | 60 #elif defined(TARGET_ARCH_ARM64) | 
|  | 61       mx_aarch64_general_regs_t* regs = | 
|  | 62           reinterpret_cast<mx_aarch64_general_regs_t*>(&buf[0]); | 
|  | 63       state->pc = static_cast<uintptr_t>(regs->pc); | 
|  | 64       state->fp = static_cast<uintptr_t>(regs->r[FPREG]); | 
|  | 65       state->csp = static_cast<uintptr_t>(regs->sp); | 
|  | 66       state->dsp = static_cast<uintptr_t>(regs->r[SPREG]); | 
|  | 67       state->lr = static_cast<uintptr_t>(regs->lr); | 
|  | 68 #else | 
|  | 69 #error "Unsupported architecture" | 
|  | 70 #endif | 
|  | 71     } | 
|  | 72     return true; | 
|  | 73   } | 
|  | 74 | 
|  | 75 | 
|  | 76   static void Interrupt(OSThread* os_thread) { | 
|  | 77     ASSERT(!OSThread::Compare(OSThread::GetCurrentThreadId(), os_thread->id())); | 
|  | 78     mx_status_t status; | 
|  | 79 | 
|  | 80     // Get a handle on the target thread. | 
|  | 81     mx_koid_t target_thread_koid = os_thread->id(); | 
|  | 82     if (FLAG_trace_thread_interrupter) { | 
|  | 83       OS::Print("ThreadInterrupter: interrupting thread with koid=%d\n", | 
|  | 84                 target_thread_koid); | 
|  | 85     } | 
|  | 86     mx_handle_t target_thread_handle; | 
|  | 87     status = mx_object_get_child(mx_process_self(), target_thread_koid, | 
|  | 88                                  MX_RIGHT_SAME_RIGHTS, &target_thread_handle); | 
|  | 89     if (status != NO_ERROR) { | 
|  | 90       if (FLAG_trace_thread_interrupter) { | 
|  | 91         OS::Print("ThreadInterrupter failed to get the thread handle: %s\n", | 
|  | 92                   mx_status_get_string(status)); | 
|  | 93       } | 
|  | 94       FATAL1("mx_object_get_child failed: %s", mx_status_get_string(status)); | 
|  | 95     } | 
|  | 96     if (target_thread_handle == MX_HANDLE_INVALID) { | 
|  | 97       FATAL("ThreadInterrupter got an invalid target thread handle!"); | 
|  | 98     } | 
|  | 99 | 
|  | 100     // Pause the target thread. | 
|  | 101     status = mx_task_suspend(target_thread_handle); | 
|  | 102     if (status != NO_ERROR) { | 
|  | 103       if (FLAG_trace_thread_interrupter) { | 
|  | 104         OS::Print("ThreadInterrupter failed to suspend thread %ld: %s\n", | 
|  | 105                   static_cast<intptr_t>(os_thread->id()), | 
|  | 106                   mx_status_get_string(status)); | 
|  | 107       } | 
|  | 108       mx_handle_close(target_thread_handle); | 
|  | 109       FATAL1("mx_task_suspend failed: %s", mx_status_get_string(status)); | 
|  | 110     } | 
|  | 111 | 
|  | 112     // TODO(zra): Enable this when mx_thread_read_state() works on suspended | 
|  | 113     // threads. | 
|  | 114     while (false) { | 
|  | 115       // Grab the target thread's registers. | 
|  | 116       InterruptedThreadState its; | 
|  | 117       if (!GrabRegisters(target_thread_handle, &its)) { | 
|  | 118         // Failed to get thread registers. | 
|  | 119         status = mx_task_resume(target_thread_handle, 0); | 
|  | 120         if (status != NO_ERROR) { | 
|  | 121           FATAL1("mx_task_resume failed: %s", mx_status_get_string(status)); | 
|  | 122         } | 
|  | 123         mx_handle_close(target_thread_handle); | 
|  | 124         return; | 
|  | 125       } | 
|  | 126       // Currently we sample only threads that are associated | 
|  | 127       // with an isolate. It is safe to call 'os_thread->thread()' | 
|  | 128       // here as the thread which is being queried is suspended. | 
|  | 129       Thread* thread = os_thread->thread(); | 
|  | 130       if (thread != NULL) { | 
|  | 131         Profiler::SampleThread(thread, its); | 
|  | 132       } | 
|  | 133     } | 
|  | 134 | 
|  | 135     // Resume the target thread. | 
|  | 136     status = mx_task_resume(target_thread_handle, 0); | 
|  | 137     if (status != NO_ERROR) { | 
|  | 138       FATAL1("mx_task_resume failed: %s", mx_status_get_string(status)); | 
|  | 139     } | 
|  | 140     mx_handle_close(target_thread_handle); | 
|  | 141   } | 
|  | 142 }; | 
|  | 143 | 
|  | 144 | 
| 14 bool ThreadInterrupter::IsDebuggerAttached() { | 145 bool ThreadInterrupter::IsDebuggerAttached() { | 
| 15   return false; | 146   return false; | 
| 16 } | 147 } | 
| 17 | 148 | 
|  | 149 | 
| 18 void ThreadInterrupter::InterruptThread(OSThread* thread) { | 150 void ThreadInterrupter::InterruptThread(OSThread* thread) { | 
| 19   UNIMPLEMENTED(); | 151   if (FLAG_trace_thread_interrupter) { | 
|  | 152     OS::Print("ThreadInterrupter suspending %p\n", | 
|  | 153               reinterpret_cast<void*>(thread->id())); | 
|  | 154   } | 
|  | 155   ThreadInterrupterFuchsia::Interrupt(thread); | 
|  | 156   if (FLAG_trace_thread_interrupter) { | 
|  | 157     OS::Print("ThreadInterrupter resuming %p\n", | 
|  | 158               reinterpret_cast<void*>(thread->id())); | 
|  | 159   } | 
| 20 } | 160 } | 
| 21 | 161 | 
| 22 | 162 | 
| 23 void ThreadInterrupter::InstallSignalHandler() { | 163 void ThreadInterrupter::InstallSignalHandler() { | 
| 24   UNIMPLEMENTED(); | 164   // Nothing to do on Fuchsia. | 
| 25 } | 165 } | 
| 26 | 166 | 
| 27 | 167 | 
| 28 void ThreadInterrupter::RemoveSignalHandler() { | 168 void ThreadInterrupter::RemoveSignalHandler() { | 
| 29   UNIMPLEMENTED(); | 169   // Nothing to do on Fuchsia. | 
| 30 } | 170 } | 
| 31 | 171 | 
|  | 172 #endif  // !PRODUCT | 
|  | 173 | 
| 32 }  // namespace dart | 174 }  // namespace dart | 
| 33 | 175 | 
| 34 #endif  // defined(HOST_OS_FUCHSIA) | 176 #endif  // defined(HOST_OS_FUCHSIA) | 
| OLD | NEW | 
|---|