mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-11 11:10:04 +01:00
kernel: avoid global storage usage for process/thread local variables
enables multiple guest processes emulation in single host process
This commit is contained in:
parent
05dee2c8e3
commit
aee92cce57
|
|
@ -3,6 +3,7 @@
|
|||
#include "rx/Rc.hpp"
|
||||
#include "rx/Serializer.hpp"
|
||||
#include "rx/TypeId.hpp"
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
|
|
@ -75,8 +76,6 @@ 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() {
|
||||
|
|
@ -91,41 +90,30 @@ struct StaticKernelObjectStorage {
|
|||
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() {
|
||||
static void ConstructAll(std::byte *storage) {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
for (auto objectCtl : instance.m_registry) {
|
||||
objectCtl.construct(storage + objectCtl.offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void DestructAll() {
|
||||
static void DestructAll(std::byte *storage) {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
for (auto objectCtl : instance.m_registry) {
|
||||
objectCtl.destruct(storage + objectCtl.offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void SerializeAll(rx::Serializer &s) {
|
||||
static void SerializeAll(std::byte *storage, rx::Serializer &s) {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
s.serialize(instance.m_size);
|
||||
s.serialize(instance.m_registry.size());
|
||||
|
|
@ -135,9 +123,8 @@ struct StaticKernelObjectStorage {
|
|||
}
|
||||
}
|
||||
|
||||
static void DeserializeAll(rx::Deserializer &s) {
|
||||
static void DeserializeAll(std::byte *storage, rx::Deserializer &s) {
|
||||
auto &instance = GetInstance();
|
||||
auto storage = getScopeStorage();
|
||||
|
||||
auto size = s.deserialize<std::size_t>();
|
||||
auto registrySize = s.deserialize<std::size_t>();
|
||||
|
|
@ -163,18 +150,11 @@ private:
|
|||
std::size_t m_alignment = 1;
|
||||
};
|
||||
|
||||
template <typename NamespaceT, typename ScopeT, rx::Serializable T>
|
||||
class StaticObjectRef {
|
||||
std::uint32_t mOffset;
|
||||
template <typename Namespace, typename Scope, rx::Serializable T>
|
||||
struct StaticObjectRef {
|
||||
std::uint32_t offset;
|
||||
|
||||
public:
|
||||
explicit StaticObjectRef(std::uint32_t offset) : mOffset(offset) {}
|
||||
|
||||
T *get() {
|
||||
return reinterpret_cast<T *>(getScopeStorage<NamespaceT, ScopeT>() +
|
||||
mOffset);
|
||||
}
|
||||
|
||||
T *operator->() { return get(); }
|
||||
T *get(std::byte *storage) { return reinterpret_cast<T *>(storage + offset); }
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ struct RcAppInfo : rx::RcBase, AppInfoEx {
|
|||
orbis::uint32_t appState = 0;
|
||||
};
|
||||
|
||||
class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final {
|
||||
class KernelContext final {
|
||||
public:
|
||||
KernelContext();
|
||||
~KernelContext();
|
||||
|
|
|
|||
|
|
@ -1,23 +1,21 @@
|
|||
#pragma once
|
||||
#include "rx/Serializer.hpp"
|
||||
#include <cstddef>
|
||||
#include <kernel/KernelObject.hpp>
|
||||
|
||||
namespace orbis {
|
||||
struct OrbisNamespace;
|
||||
|
||||
template <rx::Serializable StateT>
|
||||
using GlobalObjectRef =
|
||||
kernel::StaticObjectRef<OrbisNamespace, kernel::detail::GlobalScope,
|
||||
StateT>;
|
||||
extern std::byte *g_globalStorage;
|
||||
|
||||
template <rx::Serializable StateT>
|
||||
using ProcessLocalObjectRef =
|
||||
kernel::StaticObjectRef<OrbisNamespace, kernel::detail::ProcessScope,
|
||||
StateT>;
|
||||
template <rx::Serializable T> class GlobalObjectRef {
|
||||
std::uint32_t mOffset;
|
||||
|
||||
template <rx::Serializable StateT>
|
||||
using ThreadLocalObjectRef =
|
||||
kernel::StaticObjectRef<OrbisNamespace, kernel::detail::ThreadScope,
|
||||
StateT>;
|
||||
public:
|
||||
explicit GlobalObjectRef(std::uint32_t offset) : mOffset(offset) {}
|
||||
T *get() { return reinterpret_cast<T *>(g_globalStorage + mOffset); }
|
||||
T *operator->() { return get(); }
|
||||
};
|
||||
|
||||
template <rx::Serializable StateT>
|
||||
GlobalObjectRef<StateT> createGlobalObject() {
|
||||
|
|
@ -33,8 +31,7 @@ createProcessLocalObject() {
|
|||
auto layoutOffset = kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace,
|
||||
kernel::detail::ProcessScope>::template Allocate<StateT>();
|
||||
return kernel::StaticObjectRef<OrbisNamespace, kernel::detail::ProcessScope,
|
||||
StateT>(layoutOffset);
|
||||
return {layoutOffset};
|
||||
}
|
||||
|
||||
template <rx::Serializable StateT>
|
||||
|
|
@ -42,67 +39,30 @@ kernel::StaticObjectRef<OrbisNamespace, kernel::detail::ThreadScope, StateT>
|
|||
createThreadLocalObject() {
|
||||
auto layoutOffset = kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ThreadScope>::template Allocate<StateT>();
|
||||
return kernel::StaticObjectRef<OrbisNamespace, kernel::detail::ThreadScope,
|
||||
StateT>(layoutOffset);
|
||||
return {layoutOffset};
|
||||
}
|
||||
|
||||
inline void constructAllGlobals() {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::GlobalScope>::ConstructAll();
|
||||
}
|
||||
|
||||
inline void constructAllProcessLocals() {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ProcessScope>::ConstructAll();
|
||||
}
|
||||
|
||||
inline void constructAllThreadLocals() {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ThreadScope>::ConstructAll();
|
||||
OrbisNamespace,
|
||||
kernel::detail::GlobalScope>::ConstructAll(g_globalStorage);
|
||||
}
|
||||
|
||||
inline void destructAllGlobals() {
|
||||
kernel::StaticKernelObjectStorage<OrbisNamespace,
|
||||
kernel::detail::GlobalScope>::DestructAll();
|
||||
}
|
||||
|
||||
inline void destructAllProcessLocals() {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ProcessScope>::DestructAll();
|
||||
}
|
||||
|
||||
inline void destructAllThreadLocals() {
|
||||
kernel::StaticKernelObjectStorage<OrbisNamespace,
|
||||
kernel::detail::ThreadScope>::DestructAll();
|
||||
OrbisNamespace,
|
||||
kernel::detail::GlobalScope>::DestructAll(g_globalStorage);
|
||||
}
|
||||
|
||||
inline void serializeAllGlobals(rx::Serializer &s) {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::GlobalScope>::SerializeAll(s);
|
||||
}
|
||||
|
||||
inline void serializeAllProcessLocals(rx::Serializer &s) {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ProcessScope>::SerializeAll(s);
|
||||
}
|
||||
|
||||
inline void serializeAllThreadLocals(rx::Serializer &s) {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ThreadScope>::SerializeAll(s);
|
||||
OrbisNamespace,
|
||||
kernel::detail::GlobalScope>::SerializeAll(g_globalStorage, s);
|
||||
}
|
||||
|
||||
inline void deserializeAllGlobals(rx::Deserializer &s) {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::GlobalScope>::DeserializeAll(s);
|
||||
}
|
||||
|
||||
inline void deserializeAllProcessLocals(rx::Deserializer &s) {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ProcessScope>::DeserializeAll(s);
|
||||
}
|
||||
|
||||
inline void deserializeAllThreadLocals(rx::Deserializer &s) {
|
||||
kernel::StaticKernelObjectStorage<
|
||||
OrbisNamespace, kernel::detail::ThreadScope>::DeserializeAll(s);
|
||||
OrbisNamespace,
|
||||
kernel::detail::GlobalScope>::DeserializeAll(g_globalStorage, s);
|
||||
}
|
||||
} // namespace orbis
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
#pragma once
|
||||
#include "KernelAllocator.hpp"
|
||||
#include "KernelObject.hpp"
|
||||
#include "kernel/KernelObject.hpp"
|
||||
#include "orbis-config.hpp"
|
||||
|
||||
#include "../event.hpp"
|
||||
|
|
@ -15,6 +18,7 @@
|
|||
#include "orbis/file.hpp"
|
||||
#include "orbis/module/Module.hpp"
|
||||
#include "rx/IdMap.hpp"
|
||||
#include "rx/Serializer.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include <optional>
|
||||
|
||||
|
|
@ -52,7 +56,13 @@ enum class ProcessType : std::uint8_t {
|
|||
};
|
||||
|
||||
struct Process final {
|
||||
using Storage =
|
||||
kernel::StaticKernelObjectStorage<OrbisNamespace,
|
||||
kernel::detail::ProcessScope>;
|
||||
|
||||
KernelContext *context = nullptr;
|
||||
std::byte *storage = nullptr;
|
||||
|
||||
pid_t pid = -1;
|
||||
int gfxRing = 0;
|
||||
std::uint64_t hostPid = -1;
|
||||
|
|
@ -101,5 +111,29 @@ struct Process final {
|
|||
// Named memory ranges for debugging
|
||||
rx::shared_mutex namedMemMutex;
|
||||
kmap<NamedMemoryRange, kstring> namedMem;
|
||||
|
||||
// FIXME: implement process destruction
|
||||
void incRef() {}
|
||||
void decRef() {}
|
||||
|
||||
void allocate() {
|
||||
if (auto size = Storage::GetSize()) {
|
||||
storage = (std::byte *)kalloc(size, Storage::GetAlignment());
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate() {
|
||||
if (auto size = Storage::GetSize()) {
|
||||
kfree(storage, size);
|
||||
storage = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <rx::Serializable T>
|
||||
T *get(
|
||||
kernel::StaticObjectRef<OrbisNamespace, kernel::detail::ProcessScope, T>
|
||||
ref) {
|
||||
return ref.get(storage);
|
||||
}
|
||||
};
|
||||
} // namespace orbis
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "KernelObject.hpp"
|
||||
#include "ThreadState.hpp"
|
||||
#include "cpuset.hpp"
|
||||
#include "orbis-config.hpp"
|
||||
#include "rx/Serializer.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include "../KernelAllocator.hpp"
|
||||
|
|
@ -16,9 +18,14 @@ namespace orbis {
|
|||
struct Process;
|
||||
|
||||
static constexpr std::uint32_t kThreadSuspendFlag = 1 << 31;
|
||||
struct Thread {
|
||||
struct Thread final {
|
||||
using Storage =
|
||||
kernel::StaticKernelObjectStorage<OrbisNamespace,
|
||||
kernel::detail::ThreadScope>;
|
||||
|
||||
rx::shared_mutex mtx;
|
||||
Process *tproc = nullptr;
|
||||
std::byte *storage = nullptr;
|
||||
uint64_t retval[2]{};
|
||||
void *context{};
|
||||
kvector<void *> altStack;
|
||||
|
|
@ -75,6 +82,25 @@ struct Thread {
|
|||
void notifyUnblockedSignal(int signo);
|
||||
void setSigMask(SigSet newSigMask);
|
||||
|
||||
void allocate() {
|
||||
if (auto size = Storage::GetSize()) {
|
||||
storage = (std::byte *)kalloc(size, Storage::GetAlignment());
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate() {
|
||||
if (auto size = Storage::GetSize()) {
|
||||
kfree(storage, size);
|
||||
storage = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <rx::Serializable T>
|
||||
T *get(kernel::StaticObjectRef<OrbisNamespace, kernel::detail::ThreadScope, T>
|
||||
ref) {
|
||||
return ref.get(storage);
|
||||
}
|
||||
|
||||
// FIXME: implement thread destruction
|
||||
void incRef() {}
|
||||
void decRef() {}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ struct KernelMemoryResource {
|
|||
};
|
||||
|
||||
static KernelMemoryResource *sMemoryResource;
|
||||
static std::byte *sGlobalStorage;
|
||||
std::byte *g_globalStorage;
|
||||
|
||||
using GlobalStorage =
|
||||
kernel::StaticKernelObjectStorage<OrbisNamespace,
|
||||
kernel::detail::GlobalScope>;
|
||||
|
|
@ -69,15 +70,15 @@ void initializeAllocator() {
|
|||
rx::print(stderr, "global: size {}, alignment {}\n", GlobalStorage::GetSize(),
|
||||
GlobalStorage::GetAlignment());
|
||||
// allocate whole global storage
|
||||
sGlobalStorage = (std::byte *)sMemoryResource->kalloc(
|
||||
g_globalStorage = (std::byte *)sMemoryResource->kalloc(
|
||||
GlobalStorage::GetSize(), GlobalStorage::GetAlignment());
|
||||
}
|
||||
|
||||
void deinitializeAllocator() {
|
||||
sMemoryResource->kfree(sGlobalStorage, GlobalStorage::GetSize());
|
||||
sMemoryResource->kfree(g_globalStorage, GlobalStorage::GetSize());
|
||||
delete sMemoryResource;
|
||||
sMemoryResource = nullptr;
|
||||
sGlobalStorage = nullptr;
|
||||
g_globalStorage = nullptr;
|
||||
}
|
||||
|
||||
void *KernelMemoryResource::kalloc(std::size_t size, std::size_t align) {
|
||||
|
|
@ -213,9 +214,3 @@ void *kalloc(std::size_t size, std::size_t align) {
|
|||
return sMemoryResource->kalloc(size, align);
|
||||
}
|
||||
} // namespace orbis
|
||||
|
||||
template <>
|
||||
std::byte *
|
||||
kernel::getScopeStorage<orbis::OrbisNamespace, kernel::detail::GlobalScope>() {
|
||||
return orbis::sGlobalStorage;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue