mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-06 06:55:09 +00:00
kernel: split context and allocator & initial implementation of process/thread local objects
Some checks are pending
Formatting check / formatting-check (push) Waiting to run
Build RPCSX / build-linux (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.1-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.2-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.4-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.5-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv9-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv9.1-a) (push) Waiting to run
Build RPCSX / build-android (x86_64, x86-64) (push) Waiting to run
Some checks are pending
Formatting check / formatting-check (push) Waiting to run
Build RPCSX / build-linux (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.1-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.2-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.4-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv8.5-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv9-a) (push) Waiting to run
Build RPCSX / build-android (arm64-v8a, armv9.1-a) (push) Waiting to run
Build RPCSX / build-android (x86_64, x86-64) (push) Waiting to run
This commit is contained in:
parent
b358d6b2c9
commit
2589143798
34 changed files with 774 additions and 597 deletions
|
|
@ -1,139 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "rx/LinkedNode.hpp"
|
||||
#include "rx/Serializer.hpp"
|
||||
#include <cassert>
|
||||
|
||||
namespace kernel {
|
||||
|
||||
namespace detail {
|
||||
struct GlobalObjectCtl {
|
||||
void (*construct)();
|
||||
void (*destruct)();
|
||||
void (*serialize)(rx::Serializer &);
|
||||
void (*deserialize)(rx::Deserializer &);
|
||||
};
|
||||
|
||||
template <typename NamespaceT, typename T> struct GlobalKernelObjectInstance {
|
||||
static inline T *instance = nullptr;
|
||||
|
||||
static inline rx::LinkedNode<GlobalObjectCtl> ctl = {
|
||||
.object = {
|
||||
.construct = +[] { instance->construct(); },
|
||||
.destruct = +[] { instance->destruct(); },
|
||||
.serialize = +[](rx::Serializer &s) { instance->serialize(s); },
|
||||
.deserialize = +[](rx::Deserializer &s) { instance->deserialize(s); },
|
||||
},
|
||||
};
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename NamespaceT> struct GlobalKernelObjectStorage {
|
||||
template <typename T> static void AddObject() {
|
||||
auto node = &detail::GlobalKernelObjectInstance<NamespaceT, T>::ctl;
|
||||
auto head = GetHead();
|
||||
if (head) {
|
||||
head->prev = node;
|
||||
node->next = head;
|
||||
}
|
||||
|
||||
*GetHeadPtr() = node;
|
||||
}
|
||||
|
||||
static void ConstructAll() {
|
||||
for (auto it = GetHead(); it != nullptr; it = it->next) {
|
||||
it->object.construct();
|
||||
}
|
||||
}
|
||||
|
||||
static void DestructAll() {
|
||||
for (auto it = GetHead(); it != nullptr; it = it->next) {
|
||||
it->object.destruct();
|
||||
}
|
||||
}
|
||||
|
||||
static void SerializeAll(rx::Serializer &s) {
|
||||
for (auto it = GetHead(); it != nullptr; it = it->next) {
|
||||
it->object.serialize(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void DeserializeAll(rx::Deserializer &s) {
|
||||
for (auto it = GetHead(); it != nullptr; it = it->next) {
|
||||
it->object.deserialize(s);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static rx::LinkedNode<detail::GlobalObjectCtl> *GetHead() {
|
||||
return *GetHeadPtr();
|
||||
}
|
||||
|
||||
static rx::LinkedNode<detail::GlobalObjectCtl> **GetHeadPtr() {
|
||||
static rx::LinkedNode<detail::GlobalObjectCtl> *registry;
|
||||
return ®istry;
|
||||
}
|
||||
};
|
||||
|
||||
template <rx::Serializable T, typename NamespaceT>
|
||||
requires std::is_default_constructible_v<T>
|
||||
class GlobalKernelObject {
|
||||
union U {
|
||||
T object;
|
||||
|
||||
U() {}
|
||||
~U() {}
|
||||
};
|
||||
|
||||
U mHolder;
|
||||
|
||||
public:
|
||||
template <typename = void> GlobalKernelObject() {
|
||||
auto &instance =
|
||||
detail::GlobalKernelObjectInstance<NamespaceT,
|
||||
GlobalKernelObject>::instance;
|
||||
assert(instance == nullptr);
|
||||
instance = this;
|
||||
GlobalKernelObjectStorage<NamespaceT>::template AddObject<
|
||||
GlobalKernelObject>();
|
||||
}
|
||||
|
||||
T *operator->() { return &mHolder.object; }
|
||||
const T *operator->() const { return &mHolder.object; }
|
||||
T &operator*() { return mHolder.object; }
|
||||
const T &operator*() const { return mHolder.object; }
|
||||
operator T &() { return mHolder.object; }
|
||||
operator const T &() const { return mHolder.object; }
|
||||
|
||||
void serialize(rx::Serializer &s)
|
||||
requires rx::Serializable<T>
|
||||
{
|
||||
s.serialize(mHolder.object);
|
||||
}
|
||||
|
||||
void deserialize(rx::Deserializer &s)
|
||||
requires rx::Serializable<T>
|
||||
{
|
||||
std::construct_at(&mHolder.object);
|
||||
s.deserialize(mHolder.object);
|
||||
}
|
||||
|
||||
T &get() { return mHolder.object; }
|
||||
const T &get() const { return mHolder.object; }
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
requires(std::is_constructible_v<T, Args && ...>)
|
||||
void construct(Args &&...args) noexcept(
|
||||
std::is_nothrow_constructible_v<T, Args &&...>) {
|
||||
std::construct_at(&mHolder.object, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void destruct() noexcept(std::is_nothrow_destructible_v<T>) {
|
||||
mHolder.object.~T();
|
||||
}
|
||||
|
||||
friend detail::GlobalKernelObjectInstance<NamespaceT, GlobalKernelObject>;
|
||||
};
|
||||
} // namespace kernel
|
||||
180
kernel/include/kernel/KernelObject.hpp
Normal file
180
kernel/include/kernel/KernelObject.hpp
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
#pragma once
|
||||
|
||||
#include "rx/Rc.hpp"
|
||||
#include "rx/Serializer.hpp"
|
||||
#include "rx/TypeId.hpp"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace kernel {
|
||||
class KernelObjectBase : public rx::RcBase {
|
||||
rx::TypeId mType;
|
||||
|
||||
public:
|
||||
KernelObjectBase(rx::TypeId type) : mType(type) {}
|
||||
[[nodiscard]] rx::TypeId getType() const { return mType; }
|
||||
|
||||
template <typename T> [[nodiscard]] bool isa() const {
|
||||
return mType == rx::TypeId::get<T>();
|
||||
}
|
||||
};
|
||||
|
||||
template <rx::Serializable StateT>
|
||||
struct KernelObject : KernelObjectBase, StateT {
|
||||
template <typename... Args>
|
||||
KernelObject(Args &&...args)
|
||||
: KernelObjectBase(rx::TypeId::get<StateT>()),
|
||||
StateT(std::forward<Args>(args)...) {}
|
||||
|
||||
virtual void serialize(rx::Serializer &s) const {
|
||||
if constexpr (requires(const KernelObject &instance) {
|
||||
instance.lock();
|
||||
instance.unlock();
|
||||
}) {
|
||||
std::lock_guard lock(*this);
|
||||
s.serialize(static_cast<const StateT &>(*this));
|
||||
} else {
|
||||
s.serialize(static_cast<const StateT &>(*this));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void deserialize(rx::Deserializer &s) {
|
||||
s.deserialize(static_cast<StateT &>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
struct StaticObjectCtl {
|
||||
std::size_t offset = -1ull;
|
||||
void (*construct)(void *object);
|
||||
void (*destruct)(void *object);
|
||||
void (*serialize)(void *object, rx::Serializer &);
|
||||
void (*deserialize)(void *object, rx::Deserializer &);
|
||||
|
||||
template <typename T> constexpr static StaticObjectCtl Create() {
|
||||
return {
|
||||
.construct =
|
||||
+[](void *object) {
|
||||
std::construct_at(reinterpret_cast<T *>(object));
|
||||
},
|
||||
.destruct = +[](void *object) { reinterpret_cast<T *>(object)->~T(); },
|
||||
.serialize =
|
||||
+[](void *object, rx::Serializer &serializer) {
|
||||
serializer.serialize(*reinterpret_cast<T *>(object));
|
||||
},
|
||||
.deserialize =
|
||||
+[](void *object, rx::Deserializer &deserializer) {
|
||||
deserializer.deserialize(*reinterpret_cast<T *>(object));
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct GlobalScope;
|
||||
struct ProcessScope;
|
||||
struct ThreadScope;
|
||||
} // namespace detail
|
||||
|
||||
template <typename NamespaceT, typename ScopeT> std::byte *getScopeStorage();
|
||||
|
||||
template <typename NamespaceT, typename ScopeT>
|
||||
struct StaticKernelObjectStorage {
|
||||
template <typename T> static std::uint32_t Allocate() {
|
||||
auto &instance = GetInstance();
|
||||
|
||||
auto object = detail::StaticObjectCtl::Create<T>();
|
||||
instance.m_registry.push_back(object);
|
||||
|
||||
auto offset = instance.m_size;
|
||||
offset = rx::alignUp(offset, alignof(T));
|
||||
instance.m_registry.back().offset = offset;
|
||||
instance.m_size = offset + sizeof(T);
|
||||
instance.m_alignment =
|
||||
std::max<std::size_t>(alignof(T), instance.m_alignment);
|
||||
// std::printf(
|
||||
// "%s::Allocate(%s, %zu, %zu) -> %zu\n",
|
||||
// rx::TypeId::get<StaticKernelObjectStorage<NamespaceT,
|
||||
// ScopeT>>().getName().data(), rx::TypeId::get<T>().getName().data(),
|
||||
// sizeof(T), alignof(T), offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static std::size_t GetSize() { return GetInstance().m_size; }
|
||||
static std::size_t GetAlignment() { return GetInstance().m_alignment; }
|
||||
static std::byte *getScopeStorage() {
|
||||
return kernel::getScopeStorage<NamespaceT, ScopeT>();
|
||||
}
|
||||
|
||||
static void ConstructAll() {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
for (auto objectCtl : instance.m_registry) {
|
||||
objectCtl.construct(storage + objectCtl.offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void DestructAll() {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
for (auto objectCtl : instance.m_registry) {
|
||||
objectCtl.destruct(storage + objectCtl.offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void SerializeAll(rx::Serializer &s) {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
s.serialize(instance.m_size);
|
||||
s.serialize(instance.m_registry.size());
|
||||
|
||||
for (auto objectCtl : instance.m_registry) {
|
||||
objectCtl.serialize(storage + objectCtl.offset, s);
|
||||
}
|
||||
}
|
||||
|
||||
static void DeserializeAll(rx::Deserializer &s) {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
auto size = s.deserialize<std::size_t>();
|
||||
auto registrySize = s.deserialize<std::size_t>();
|
||||
|
||||
if (size != instance.m_size || registrySize != instance.m_registry.size()) {
|
||||
s.setFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto objectCtl : instance.m_registry) {
|
||||
objectCtl.deserialize(storage + objectCtl.offset, s);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static StaticKernelObjectStorage &GetInstance() {
|
||||
static StaticKernelObjectStorage instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::vector<detail::StaticObjectCtl> m_registry;
|
||||
std::size_t m_size = 0;
|
||||
std::size_t m_alignment = 1;
|
||||
};
|
||||
|
||||
template <typename NamespaceT, typename ScopeT, rx::Serializable T>
|
||||
class StaticObjectRef {
|
||||
std::uint32_t mOffset;
|
||||
|
||||
public:
|
||||
explicit StaticObjectRef(std::uint32_t offset) : mOffset(offset) {}
|
||||
|
||||
T *get() {
|
||||
return reinterpret_cast<T *>(getScopeStorage<NamespaceT, ScopeT>() +
|
||||
mOffset);
|
||||
}
|
||||
|
||||
T *operator->() { return get(); }
|
||||
};
|
||||
} // namespace kernel
|
||||
Loading…
Add table
Add a link
Reference in a new issue