diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index edce53b0b..52fef5dba 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -358,8 +358,6 @@ bool Emulator::SaveToFile(const std::wstring& path) { } bool Emulator::RestoreFromFile(const std::wstring& path) { - auto lock = global_critical_region::AcquireDirect(); - // Restore the emulator state from a file auto map = MappedMemory::Open(path, MappedMemory::Mode::kReadWrite); if (!map) { @@ -372,6 +370,7 @@ bool Emulator::RestoreFromFile(const std::wstring& path) { Pause(); kernel_state_->TerminateTitle(); + auto lock = global_critical_region::AcquireDirect(); ByteStream stream(map->data(), map->size()); if (stream.Read() != 'XSAV') { return false; diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index 709aa088e..00e93cfff 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -120,6 +120,7 @@ class Emulator { void Pause(); void Resume(); + bool is_paused() const { return paused_; } bool SaveToFile(const std::wstring& path); bool RestoreFromFile(const std::wstring& path); diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 794fb7a3d..8bf404cb4 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -334,6 +334,7 @@ object_ref KernelState::LoadUserModule(const char* raw_name, } void KernelState::TerminateTitle(bool from_guest_thread) { + XELOGD("KernelState::TerminateTitle"); auto global_lock = global_critical_region_.Acquire(); // Call terminate routines. @@ -351,6 +352,8 @@ void KernelState::TerminateTitle(bool from_guest_thread) { */ // Kill all guest threads. + // Need to not be holding the lock to do this. + global_lock.unlock(); for (auto it = threads_by_id_.begin(); it != threads_by_id_.end();) { if (it->second->is_guest_thread()) { auto thread = it->second; @@ -362,10 +365,14 @@ void KernelState::TerminateTitle(bool from_guest_thread) { } if (thread->is_running()) { - // TODO: Need to step the thread to a safe point (returns it to guest - // code so it's guaranteed to not be holding any locks / in host kernel + // Need to step the thread to a safe point (returns it to guest code + // so it's guaranteed to not be holding any locks / in host kernel // code / etc). Can't do that properly if we have the lock. - // thread->StepToSafePoint(); + if (!emulator_->is_paused()) { + thread->thread()->Suspend(); + } + + thread->StepToSafePoint(); thread->Terminate(0); } @@ -375,6 +382,7 @@ void KernelState::TerminateTitle(bool from_guest_thread) { ++it; } } + global_lock.lock(); // Third: Unload all user modules (including the executable) for (int i = 0; i < user_modules_.size(); i++) { @@ -611,6 +619,8 @@ bool KernelState::Save(ByteStream* stream) { stream->Write((uint32_t)object->type()); if (object->is_host_object() || !object->Save(stream)) { + XELOGD("Did not save object of type %d", object->type()); + // Revert backwards and overwrite if a save failed. stream->set_offset(prev_offset); num_objects--; diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index a04a36fb1..f730968c9 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -142,6 +142,7 @@ class KernelState { } // Terminates a title: Unloads all modules, and kills all guest threads. + // This DOES NOT RETURN if called from a guest thread! void TerminateTitle(bool from_guest_thread = false); void RegisterThread(XThread* thread);