diff --git a/src/xenia/kernel/xmutant.cc b/src/xenia/kernel/xmutant.cc index 5bb03cc9a..0e950c32b 100644 --- a/src/xenia/kernel/xmutant.cc +++ b/src/xenia/kernel/xmutant.cc @@ -54,12 +54,14 @@ X_STATUS XMutant::ReleaseMutant(uint32_t priority_increment, bool abandon, } bool XMutant::Save(ByteStream* stream) { - XELOGD("XMutant %.8X", handle()); if (!SaveObject(stream)) { return false; } - stream->Write(owning_thread_->handle()); + uint32_t owning_thread_handle = owning_thread_ ? owning_thread_->handle() : 0; + stream->Write(owning_thread_handle); + XELOGD("XMutant %.8X (owner: %.8X)", handle(), owning_thread_handle); + return true; } @@ -75,11 +77,13 @@ object_ref XMutant::Restore(KernelState* kernel_state, mutant->Initialize(false); - // TODO: Make the thread acquire this mutex... Somehow. auto owning_thread_handle = stream->Read(); - mutant->owning_thread_ = kernel_state->object_table() - ->LookupObject(owning_thread_handle) - .get(); + if (owning_thread_handle) { + mutant->owning_thread_ = kernel_state->object_table() + ->LookupObject(owning_thread_handle) + .get(); + mutant->owning_thread_->AcquireMutantOnStartup(retain_object(mutant)); + } return object_ref(mutant); } diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index 72e7c9e74..6e996455f 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -27,6 +27,7 @@ #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/user_module.h" #include "xenia/kernel/xevent.h" +#include "xenia/kernel/xmutant.h" DEFINE_bool(ignore_thread_priorities, true, "Ignores game-specified thread priorities."); @@ -1218,13 +1219,21 @@ object_ref XThread::Restore(KernelState* kernel_state, Clock::SetGuestTickCount(state.tick_count_); Clock::SetGuestSystemTime(state.system_time_); - // Execute user code. - thread->running_ = true; current_thread_tls_ = thread; + // Acquire any mutants + for (auto mutant : thread->pending_mutant_acquires_) { + uint64_t timeout = 0; + auto status = mutant->Wait(0, 0, 0, &timeout); + assert_true(status == X_STATUS_SUCCESS); + } + thread->pending_mutant_acquires_.clear(); + + // Execute user code. + thread->running_ = true; + uint32_t pc = state.context.pc; - thread->kernel_state()->processor()->ExecuteRaw(thread->thread_state_, - pc); + thread->kernel_state_->processor()->ExecuteRaw(thread->thread_state_, pc); current_thread_tls_ = nullptr; diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index a8a137702..63a9087a7 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -18,6 +18,7 @@ #include "xenia/cpu/thread_state.h" #include "xenia/kernel/util/native_list.h" #include "xenia/kernel/xobject.h" +#include "xenia/kernel/xmutant.h" #include "xenia/xbox.h" namespace xe { @@ -190,6 +191,11 @@ class XThread : public XObject { static object_ref Restore(KernelState* kernel_state, ByteStream* stream); + // Internal - do not use. + void AcquireMutantOnStartup(object_ref mutant) { + pending_mutant_acquires_.push_back(mutant); + } + // Steps the thread to a point where it's safe to terminate or read its // context. Returns the PC after we've finished stepping. // Pass true for ignore_host if you've stopped the thread yourself @@ -210,6 +216,8 @@ class XThread : public XObject { CreationParams creation_params_ = {0}; + std::vector> pending_mutant_acquires_; + uint32_t thread_id_ = 0; std::unique_ptr thread_; uint32_t scratch_address_ = 0;