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

This commit is contained in:
DH 2025-10-10 19:56:11 +03:00
parent b358d6b2c9
commit 2589143798
34 changed files with 774 additions and 597 deletions

View file

@ -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 &registry;
}
};
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

View 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