From 5517518d36ce8bd43ecf760677b79abe62f2bb93 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Tue, 1 Dec 2015 16:51:15 -0600 Subject: [PATCH] XObject savestate setup (Save/Restore, tracks all handles, tracks if host object) --- src/xenia/kernel/xobject.cc | 82 ++++++++++++++++++++++++++++++++----- src/xenia/kernel/xobject.h | 31 ++++++++++++-- 2 files changed, 99 insertions(+), 14 deletions(-) diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index adfc02ab4..2bff5647b 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -11,12 +11,17 @@ #include +#include "xenia/base/byte_stream.h" #include "xenia/base/clock.h" #include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/notify_listener.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/kernel/xenumerator.h" #include "xenia/kernel/xevent.h" +#include "xenia/kernel/xfile.h" #include "xenia/kernel/xmutant.h" #include "xenia/kernel/xsemaphore.h" +#include "xenia/kernel/xthread.h" namespace xe { namespace kernel { @@ -25,12 +30,11 @@ XObject::XObject(KernelState* kernel_state, Type type) : kernel_state_(kernel_state), pointer_ref_count_(1), type_(type), - handle_(X_INVALID_HANDLE_VALUE), guest_object_ptr_(0), allocated_guest_object_(false) { - // Added pointer check to support usage without a kernel_state - if (kernel_state != nullptr) { - kernel_state->object_table()->AddHandle(this, &handle_); + handles_.reserve(10); + if (kernel_state) { + kernel_state->object_table()->AddHandle(this, &handles_[0]); } } @@ -56,15 +60,13 @@ Memory* XObject::memory() const { return kernel_state_->memory(); } XObject::Type XObject::type() { return type_; } -X_HANDLE XObject::handle() const { return handle_; } - void XObject::RetainHandle() { - kernel_state_->object_table()->RetainHandle(handle_); + kernel_state_->object_table()->RetainHandle(handles_[0]); } bool XObject::ReleaseHandle() { // FIXME: Return true when handle is actually released. - return kernel_state_->object_table()->ReleaseHandle(handle_) == + return kernel_state_->object_table()->ReleaseHandle(handles_[0]) == X_STATUS_SUCCESS; } @@ -84,10 +86,70 @@ X_STATUS XObject::Delete() { if (!name_.empty()) { kernel_state_->object_table()->RemoveNameMapping(name_); } - return kernel_state_->object_table()->RemoveHandle(handle_); + return kernel_state_->object_table()->RemoveHandle(handles_[0]); } } +bool XObject::SaveObject(ByteStream* stream) { + stream->Write(allocated_guest_object_); + stream->Write(guest_object_ptr_); + + stream->Write(uint32_t(handles_.size())); + stream->Write(&handles_[0], handles_.size() * sizeof(X_HANDLE)); + + return true; +} + +bool XObject::RestoreObject(ByteStream* stream) { + allocated_guest_object_ = stream->Read() > 0; + guest_object_ptr_ = stream->Read(); + + handles_.resize(stream->Read()); + stream->Read(&handles_[0], handles_.size() * sizeof(X_HANDLE)); + + // Restore our pointer to our handles in the object table. + for (size_t i = 0; i < handles_.size(); i++) { + kernel_state_->object_table()->RestoreHandle(handles_[i], this); + } + + return true; +} + +object_ref XObject::Restore(KernelState* kernel_state, Type type, + ByteStream* stream) { + switch (type) { + case kTypeEnumerator: + break; + case kTypeEvent: + return XEvent::Restore(kernel_state, stream); + case kTypeFile: + break; + case kTypeIOCompletion: + break; + case kTypeModule: + break; + case kTypeMutant: + break; + case kTypeNotifyListener: + return NotifyListener::Restore(kernel_state, stream); + case kTypeSemaphore: + break; + case kTypeSession: + break; + case kTypeSocket: + break; + case kTypeThread: + return XThread::Restore(kernel_state, stream); + case kTypeTimer: + break; + default: + assert_always("No restore handler exists for this object!"); + return nullptr; + } + + return nullptr; +} + void XObject::SetAttributes(uint32_t obj_attributes_ptr) { if (!obj_attributes_ptr) { return; @@ -97,7 +159,7 @@ void XObject::SetAttributes(uint32_t obj_attributes_ptr) { obj_attributes_ptr + 4); if (!name.empty()) { name_ = std::move(name); - kernel_state_->object_table()->AddNameMapping(name_, handle_); + kernel_state_->object_table()->AddNameMapping(name_, handles_[0]); } } diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index b5cc6d700..f16a77794 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -133,10 +133,22 @@ class XObject { Memory* memory() const; Type type(); - X_HANDLE handle() const; + + // Returns the primary handle of this object. + X_HANDLE handle() const { return handles_[0]; } + + // Returns all associated handles with this object. + std::vector handles() const { return handles_; } + std::vector& handles() { return handles_; } + const std::string& name() const { return name_; } uint32_t guest_object() const { return guest_object_ptr_; } + // Has this object been created for use by the host? + // Host objects are persisted through reloads/etc. + bool host_object() const { return host_object_; } + void set_host_object(bool host_object) { host_object_ = host_object; } + template T* guest_object() { return memory()->TranslateVirtual(guest_object_ptr_); @@ -148,8 +160,9 @@ class XObject { void Release(); X_STATUS Delete(); - virtual bool Save(ByteStream* stream) { return false; }; - virtual bool Restore(ByteStream* stream) { return false; }; + virtual bool Save(ByteStream* stream) { return false; } + static object_ref Restore(KernelState* kernel_state, Type type, + ByteStream* stream); // Reference() // Dereference() @@ -176,6 +189,9 @@ class XObject { virtual xe::threading::WaitHandle* GetWaitHandle() { return nullptr; } protected: + bool SaveObject(ByteStream* stream); + bool RestoreObject(ByteStream* stream); + // Creates the kernel object for guest code to use. Typically not needed. uint8_t* CreateNative(uint32_t size); void SetNativePointer(uint32_t native_ptr, bool uninitialized = false); @@ -197,11 +213,14 @@ class XObject { KernelState* kernel_state_; + // Host objects are persisted through resets/etc. + bool host_object_ = false; + private: std::atomic pointer_ref_count_; Type type_; - X_HANDLE handle_; + std::vector handles_; std::string name_; // May be zero length. // Guest pointer for kernel object. Remember: X_OBJECT_HEADER precedes this @@ -292,6 +311,10 @@ class object_ref { void reset(T* value) noexcept { object_ref(value).swap(*this); } + inline bool operator==(const T* right) noexcept { + return value_ == right; + } + private: T* value_ = nullptr; };