Make KernelState::TerminateTitle try to terminate XThreads safely.

This commit is contained in:
Dr. Chat 2015-12-06 21:02:12 -06:00 committed by Ben Vanik
parent 3007a98d2d
commit 24f8295daa
4 changed files with 16 additions and 5 deletions

View File

@ -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<uint32_t>() != 'XSAV') {
return false;

View File

@ -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);

View File

@ -334,6 +334,7 @@ object_ref<UserModule> 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--;

View File

@ -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);