XObject savestate setup (Save/Restore, tracks all handles, tracks if host object)
This commit is contained in:
parent
1ce6a7580b
commit
5517518d36
|
@ -11,12 +11,17 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/base/byte_stream.h"
|
||||||
#include "xenia/base/clock.h"
|
#include "xenia/base/clock.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
|
#include "xenia/kernel/notify_listener.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||||
|
#include "xenia/kernel/xenumerator.h"
|
||||||
#include "xenia/kernel/xevent.h"
|
#include "xenia/kernel/xevent.h"
|
||||||
|
#include "xenia/kernel/xfile.h"
|
||||||
#include "xenia/kernel/xmutant.h"
|
#include "xenia/kernel/xmutant.h"
|
||||||
#include "xenia/kernel/xsemaphore.h"
|
#include "xenia/kernel/xsemaphore.h"
|
||||||
|
#include "xenia/kernel/xthread.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
@ -25,12 +30,11 @@ XObject::XObject(KernelState* kernel_state, Type type)
|
||||||
: kernel_state_(kernel_state),
|
: kernel_state_(kernel_state),
|
||||||
pointer_ref_count_(1),
|
pointer_ref_count_(1),
|
||||||
type_(type),
|
type_(type),
|
||||||
handle_(X_INVALID_HANDLE_VALUE),
|
|
||||||
guest_object_ptr_(0),
|
guest_object_ptr_(0),
|
||||||
allocated_guest_object_(false) {
|
allocated_guest_object_(false) {
|
||||||
// Added pointer check to support usage without a kernel_state
|
handles_.reserve(10);
|
||||||
if (kernel_state != nullptr) {
|
if (kernel_state) {
|
||||||
kernel_state->object_table()->AddHandle(this, &handle_);
|
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_; }
|
XObject::Type XObject::type() { return type_; }
|
||||||
|
|
||||||
X_HANDLE XObject::handle() const { return handle_; }
|
|
||||||
|
|
||||||
void XObject::RetainHandle() {
|
void XObject::RetainHandle() {
|
||||||
kernel_state_->object_table()->RetainHandle(handle_);
|
kernel_state_->object_table()->RetainHandle(handles_[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XObject::ReleaseHandle() {
|
bool XObject::ReleaseHandle() {
|
||||||
// FIXME: Return true when handle is actually released.
|
// 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;
|
X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,10 +86,70 @@ X_STATUS XObject::Delete() {
|
||||||
if (!name_.empty()) {
|
if (!name_.empty()) {
|
||||||
kernel_state_->object_table()->RemoveNameMapping(name_);
|
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<uint32_t>(allocated_guest_object_);
|
||||||
|
stream->Write<uint32_t>(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<uint32_t>() > 0;
|
||||||
|
guest_object_ptr_ = stream->Read<uint32_t>();
|
||||||
|
|
||||||
|
handles_.resize(stream->Read<uint32_t>());
|
||||||
|
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> 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) {
|
void XObject::SetAttributes(uint32_t obj_attributes_ptr) {
|
||||||
if (!obj_attributes_ptr) {
|
if (!obj_attributes_ptr) {
|
||||||
return;
|
return;
|
||||||
|
@ -97,7 +159,7 @@ void XObject::SetAttributes(uint32_t obj_attributes_ptr) {
|
||||||
obj_attributes_ptr + 4);
|
obj_attributes_ptr + 4);
|
||||||
if (!name.empty()) {
|
if (!name.empty()) {
|
||||||
name_ = std::move(name);
|
name_ = std::move(name);
|
||||||
kernel_state_->object_table()->AddNameMapping(name_, handle_);
|
kernel_state_->object_table()->AddNameMapping(name_, handles_[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,10 +133,22 @@ class XObject {
|
||||||
Memory* memory() const;
|
Memory* memory() const;
|
||||||
|
|
||||||
Type type();
|
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<X_HANDLE> handles() const { return handles_; }
|
||||||
|
std::vector<X_HANDLE>& handles() { return handles_; }
|
||||||
|
|
||||||
const std::string& name() const { return name_; }
|
const std::string& name() const { return name_; }
|
||||||
uint32_t guest_object() const { return guest_object_ptr_; }
|
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 <typename T>
|
template <typename T>
|
||||||
T* guest_object() {
|
T* guest_object() {
|
||||||
return memory()->TranslateVirtual<T*>(guest_object_ptr_);
|
return memory()->TranslateVirtual<T*>(guest_object_ptr_);
|
||||||
|
@ -148,8 +160,9 @@ class XObject {
|
||||||
void Release();
|
void Release();
|
||||||
X_STATUS Delete();
|
X_STATUS Delete();
|
||||||
|
|
||||||
virtual bool Save(ByteStream* stream) { return false; };
|
virtual bool Save(ByteStream* stream) { return false; }
|
||||||
virtual bool Restore(ByteStream* stream) { return false; };
|
static object_ref<XObject> Restore(KernelState* kernel_state, Type type,
|
||||||
|
ByteStream* stream);
|
||||||
|
|
||||||
// Reference()
|
// Reference()
|
||||||
// Dereference()
|
// Dereference()
|
||||||
|
@ -176,6 +189,9 @@ class XObject {
|
||||||
virtual xe::threading::WaitHandle* GetWaitHandle() { return nullptr; }
|
virtual xe::threading::WaitHandle* GetWaitHandle() { return nullptr; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool SaveObject(ByteStream* stream);
|
||||||
|
bool RestoreObject(ByteStream* stream);
|
||||||
|
|
||||||
// Creates the kernel object for guest code to use. Typically not needed.
|
// Creates the kernel object for guest code to use. Typically not needed.
|
||||||
uint8_t* CreateNative(uint32_t size);
|
uint8_t* CreateNative(uint32_t size);
|
||||||
void SetNativePointer(uint32_t native_ptr, bool uninitialized = false);
|
void SetNativePointer(uint32_t native_ptr, bool uninitialized = false);
|
||||||
|
@ -197,11 +213,14 @@ class XObject {
|
||||||
|
|
||||||
KernelState* kernel_state_;
|
KernelState* kernel_state_;
|
||||||
|
|
||||||
|
// Host objects are persisted through resets/etc.
|
||||||
|
bool host_object_ = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<int32_t> pointer_ref_count_;
|
std::atomic<int32_t> pointer_ref_count_;
|
||||||
|
|
||||||
Type type_;
|
Type type_;
|
||||||
X_HANDLE handle_;
|
std::vector<X_HANDLE> handles_;
|
||||||
std::string name_; // May be zero length.
|
std::string name_; // May be zero length.
|
||||||
|
|
||||||
// Guest pointer for kernel object. Remember: X_OBJECT_HEADER precedes this
|
// 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); }
|
void reset(T* value) noexcept { object_ref(value).swap(*this); }
|
||||||
|
|
||||||
|
inline bool operator==(const T* right) noexcept {
|
||||||
|
return value_ == right;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* value_ = nullptr;
|
T* value_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue