XThread: Special case save/restore for threads no longer running.

This commit is contained in:
Dr. Chat 2015-12-14 14:32:55 -06:00 committed by Ben Vanik
parent b58e9afbf1
commit 07d31862f1
1 changed files with 107 additions and 84 deletions

View File

@ -775,7 +775,12 @@ bool XThread::StepToAddress(uint32_t pc) {
fence.Signal(); fence.Signal();
}); });
if (bp.Install()) { if (bp.Install()) {
thread_->Resume(); // HACK
uint32_t suspend_count = 1;
while (suspend_count) {
thread_->Resume(&suspend_count);
}
fence.Wait(); fence.Wait();
bp.Uninstall(); bp.Uninstall();
} else { } else {
@ -859,7 +864,12 @@ uint32_t XThread::StepIntoBranch(uint32_t pc) {
return 0; return 0;
} }
thread_->Resume(); // HACK
uint32_t suspend_count = 1;
while (suspend_count) {
thread_->Resume(&suspend_count);
}
fence.Wait(); fence.Wait();
bpt.Uninstall(); bpt.Uninstall();
bpf.Uninstall(); bpf.Uninstall();
@ -1005,9 +1015,10 @@ uint32_t XThread::StepToSafePoint(bool ignore_host) {
struct ThreadSavedState { struct ThreadSavedState {
uint32_t thread_id; uint32_t thread_id;
bool main_thread; bool is_main_thread; // Is this the main thread?
bool is_running;
// Clock settings // Clock settings (invalid if not running)
uint64_t tick_count_; uint64_t tick_count_;
uint64_t system_time_; uint64_t system_time_;
@ -1018,6 +1029,8 @@ struct ThreadSavedState {
uint32_t stack_limit; // Low address uint32_t stack_limit; // Low address
uint32_t stack_alloc_base; // Allocation address uint32_t stack_alloc_base; // Allocation address
uint32_t stack_alloc_size; // Allocation size uint32_t stack_alloc_size; // Allocation size
// Context (invalid if not running)
struct { struct {
uint64_t lr; uint64_t lr;
uint64_t ctr; uint64_t ctr;
@ -1042,12 +1055,15 @@ bool XThread::Save(ByteStream* stream) {
XELOGD("XThread %.8X serializing...", handle()); XELOGD("XThread %.8X serializing...", handle());
uint32_t pc = StepToSafePoint(); uint32_t pc = 0;
if (!pc) { if (running_) {
XELOGE("XThread %.8X failed to save: could not step to a safe point!", pc = StepToSafePoint();
handle()); if (!pc) {
assert_always(); XELOGE("XThread %.8X failed to save: could not step to a safe point!",
return false; handle());
assert_always();
return false;
}
} }
if (!SaveObject(stream)) { if (!SaveObject(stream)) {
@ -1059,7 +1075,8 @@ bool XThread::Save(ByteStream* stream) {
ThreadSavedState state; ThreadSavedState state;
state.thread_id = thread_id_; state.thread_id = thread_id_;
state.main_thread = main_thread_; state.is_main_thread = main_thread_;
state.is_running = running_;
state.apc_head = apc_list_.head(); state.apc_head = apc_list_.head();
state.tls_address = tls_address_; state.tls_address = tls_address_;
state.pcr_address = pcr_address_; state.pcr_address = pcr_address_;
@ -1068,31 +1085,33 @@ bool XThread::Save(ByteStream* stream) {
state.stack_alloc_base = stack_alloc_base_; state.stack_alloc_base = stack_alloc_base_;
state.stack_alloc_size = stack_alloc_size_; state.stack_alloc_size = stack_alloc_size_;
state.tick_count_ = Clock::QueryGuestTickCount(); if (running_) {
state.system_time_ = state.tick_count_ = Clock::QueryGuestTickCount();
Clock::QueryGuestSystemTime() - Clock::guest_system_time_base(); state.system_time_ =
Clock::QueryGuestSystemTime() - Clock::guest_system_time_base();
// Context information // Context information
auto context = thread_state_->context(); auto context = thread_state_->context();
state.context.lr = context->lr; state.context.lr = context->lr;
state.context.ctr = context->ctr; state.context.ctr = context->ctr;
std::memcpy(state.context.r, context->r, 32 * 8); std::memcpy(state.context.r, context->r, 32 * 8);
std::memcpy(state.context.f, context->f, 32 * 8); std::memcpy(state.context.f, context->f, 32 * 8);
std::memcpy(state.context.v, context->v, 128 * 16); std::memcpy(state.context.v, context->v, 128 * 16);
state.context.cr[0] = context->cr0.value; state.context.cr[0] = context->cr0.value;
state.context.cr[1] = context->cr1.value; state.context.cr[1] = context->cr1.value;
state.context.cr[2] = context->cr2.value; state.context.cr[2] = context->cr2.value;
state.context.cr[3] = context->cr3.value; state.context.cr[3] = context->cr3.value;
state.context.cr[4] = context->cr4.value; state.context.cr[4] = context->cr4.value;
state.context.cr[5] = context->cr5.value; state.context.cr[5] = context->cr5.value;
state.context.cr[6] = context->cr6.value; state.context.cr[6] = context->cr6.value;
state.context.cr[7] = context->cr7.value; state.context.cr[7] = context->cr7.value;
state.context.fpscr = context->fpscr.value; state.context.fpscr = context->fpscr.value;
state.context.xer_ca = context->xer_ca; state.context.xer_ca = context->xer_ca;
state.context.xer_ov = context->xer_ov; state.context.xer_ov = context->xer_ov;
state.context.xer_so = context->xer_so; state.context.xer_so = context->xer_so;
state.context.vscr_sat = context->vscr_sat; state.context.vscr_sat = context->vscr_sat;
state.context.pc = pc; state.context.pc = pc;
}
stream->Write(&state, sizeof(ThreadSavedState)); stream->Write(&state, sizeof(ThreadSavedState));
return true; return true;
@ -1121,7 +1140,7 @@ object_ref<XThread> XThread::Restore(KernelState* kernel_state,
ThreadSavedState state; ThreadSavedState state;
stream->Read(&state, sizeof(ThreadSavedState)); stream->Read(&state, sizeof(ThreadSavedState));
thread->thread_id_ = state.thread_id; thread->thread_id_ = state.thread_id;
thread->main_thread_ = state.main_thread; thread->main_thread_ = state.is_main_thread;
thread->apc_list_.set_head(state.apc_head); thread->apc_list_.set_head(state.apc_head);
thread->tls_address_ = state.tls_address; thread->tls_address_ = state.tls_address;
thread->pcr_address_ = state.pcr_address; thread->pcr_address_ = state.pcr_address;
@ -1138,65 +1157,69 @@ object_ref<XThread> XThread::Restore(KernelState* kernel_state,
thread->thread_state_ = thread->thread_state_ =
new cpu::ThreadState(kernel_state->processor(), thread->thread_id_, new cpu::ThreadState(kernel_state->processor(), thread->thread_id_,
thread->stack_base_, thread->pcr_address_); thread->stack_base_, thread->pcr_address_);
auto context = thread->thread_state_->context();
context->kernel_state = kernel_state;
context->lr = state.context.lr;
context->ctr = state.context.ctr;
std::memcpy(context->r, state.context.r, 32 * 8);
std::memcpy(context->f, state.context.f, 32 * 8);
std::memcpy(context->v, state.context.v, 128 * 16);
context->cr0.value = state.context.cr[0];
context->cr1.value = state.context.cr[1];
context->cr2.value = state.context.cr[2];
context->cr3.value = state.context.cr[3];
context->cr4.value = state.context.cr[4];
context->cr5.value = state.context.cr[5];
context->cr6.value = state.context.cr[6];
context->cr7.value = state.context.cr[7];
context->fpscr.value = state.context.fpscr;
context->xer_ca = state.context.xer_ca;
context->xer_ov = state.context.xer_ov;
context->xer_so = state.context.xer_so;
context->vscr_sat = state.context.vscr_sat;
// Always retain when starting - the thread owns itself until exited. if (state.is_running) {
thread->Retain(); auto context = thread->thread_state_->context();
thread->RetainHandle(); context->kernel_state = kernel_state;
context->lr = state.context.lr;
context->ctr = state.context.ctr;
std::memcpy(context->r, state.context.r, 32 * 8);
std::memcpy(context->f, state.context.f, 32 * 8);
std::memcpy(context->v, state.context.v, 128 * 16);
context->cr0.value = state.context.cr[0];
context->cr1.value = state.context.cr[1];
context->cr2.value = state.context.cr[2];
context->cr3.value = state.context.cr[3];
context->cr4.value = state.context.cr[4];
context->cr5.value = state.context.cr[5];
context->cr6.value = state.context.cr[6];
context->cr7.value = state.context.cr[7];
context->fpscr.value = state.context.fpscr;
context->xer_ca = state.context.xer_ca;
context->xer_ov = state.context.xer_ov;
context->xer_so = state.context.xer_so;
context->vscr_sat = state.context.vscr_sat;
xe::threading::Thread::CreationParameters params; // Always retain when starting - the thread owns itself until exited.
params.create_suspended = true; // Not done restoring yet. thread->Retain();
params.stack_size = 16 * 1024 * 1024; thread->RetainHandle();
thread->thread_ = xe::threading::Thread::Create(params, [thread, state]() {
// Set thread ID override. This is used by logging.
xe::threading::set_current_thread_id(thread->handle());
// Set name immediately, if we have one. xe::threading::Thread::CreationParameters params;
thread->thread_->set_name(thread->name()); params.create_suspended = true; // Not done restoring yet.
params.stack_size = 16 * 1024 * 1024;
thread->thread_ = xe::threading::Thread::Create(params, [thread, state]() {
// Set thread ID override. This is used by logging.
xe::threading::set_current_thread_id(thread->handle());
// Profiler needs to know about the thread. // Set name immediately, if we have one.
xe::Profiler::ThreadEnter(thread->name().c_str()); thread->thread_->set_name(thread->name());
// Setup the time now that we're in the thread. // Profiler needs to know about the thread.
Clock::SetGuestTickCount(state.tick_count_); xe::Profiler::ThreadEnter(thread->name().c_str());
Clock::SetGuestSystemTime(state.system_time_);
// Execute user code. // Setup the time now that we're in the thread.
thread->running_ = true; Clock::SetGuestTickCount(state.tick_count_);
current_thread_tls_ = thread; Clock::SetGuestSystemTime(state.system_time_);
uint32_t pc = state.context.pc; // Execute user code.
thread->kernel_state()->processor()->ExecuteRaw(thread->thread_state_, pc); thread->running_ = true;
current_thread_tls_ = thread;
current_thread_tls_ = nullptr; uint32_t pc = state.context.pc;
thread->kernel_state()->processor()->ExecuteRaw(thread->thread_state_,
pc);
xe::Profiler::ThreadExit(); current_thread_tls_ = nullptr;
// Release the self-reference to the thread. xe::Profiler::ThreadExit();
thread->Release();
});
if (thread->emulator()->debugger()) { // Release the self-reference to the thread.
thread->emulator()->debugger()->OnThreadCreated(thread); thread->Release();
});
if (thread->emulator()->debugger()) {
thread->emulator()->debugger()->OnThreadCreated(thread);
}
} }
return object_ref<XThread>(thread); return object_ref<XThread>(thread);