From ccf29a1302b7db6cf55581a6fb99eb683ee029d3 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 7 Dec 2021 13:35:45 -0800 Subject: [PATCH] fssystem: revise allocator logic for latest semantics --- .../fssystem/fssystem_allocator_utility.hpp | 100 ++++++++++++----- .../fssystem/fssystem_allocator_utility.cpp | 106 ++++++++++++++++-- .../fssystem_file_system_proxy_api.cpp | 1 + 3 files changed, 173 insertions(+), 34 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_allocator_utility.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_allocator_utility.hpp index 2222aa99a..a0d3cfb4e 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_allocator_utility.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_allocator_utility.hpp @@ -16,50 +16,100 @@ #pragma once #include +/* Forward declare ams::fs allocate shared. */ +namespace ams::fs::impl { + + template class AllocatorTemplateT, typename Impl, typename... Args> + std::shared_ptr AllocateSharedImpl(Args &&... args); + +} + namespace ams::fssystem { using AllocateFunction = void *(*)(size_t size); using DeallocateFunction = void (*)(void *ptr, size_t size); void InitializeAllocator(AllocateFunction allocate_func, DeallocateFunction deallocate_func); + void InitializeAllocatorForSystem(AllocateFunction allocate_func, DeallocateFunction deallocate_func); void *Allocate(size_t size); void Deallocate(void *ptr, size_t size); - template - class StdAllocator : public std::allocator { - public: - StdAllocator() = default; - StdAllocator(const StdAllocator &) = default; - template - StdAllocator(const StdAllocator &) : std::allocator() { /* ... */ }; + namespace impl { - template - struct rebind { - using other = StdAllocator; - }; + template + class AllocatorFunctionSet { + public: + static void *Allocate(size_t size); + static void *AllocateUnsafe(size_t size); - T *Allocate(size_t size, const T *hint = nullptr) { - AMS_UNUSED(hint); - return static_cast(::ams::fssystem::Allocate(sizeof(T) * size)); - } + static void Deallocate(void *ptr, size_t size); + static void DeallocateUnsafe(void *ptr, size_t size); - void Deallocate(T *ptr, size_t size) { - return ::ams::fssystem::Deallocate(ptr, sizeof(T) * size); - } + static void LockAllocatorMutex(); + static void UnlockAllocatorMutex(); + }; - ALWAYS_INLINE T *allocate(size_t size, const T *hint = nullptr) { return this->Allocate(size, hint); } - ALWAYS_INLINE void deallocate(T *ptr, size_t size) { return this->Deallocate(ptr, size); } - }; + using AllocatorFunctionSetForNormal = AllocatorFunctionSet; + using AllocatorFunctionSetForSystem = AllocatorFunctionSet; + + template + class AllocatorTemplate : public std::allocator { + public: + template + struct rebind { + using other = AllocatorTemplate; + }; + private: + static ALWAYS_INLINE T *AllocateImpl(::std::size_t n) { + if constexpr (AllocateWhileLocked) { + auto * const p = Impl::AllocateUnsafe(sizeof(T) * n); + Impl::UnlockAllocatorMutex(); + return static_cast(p); + } else { + return static_cast(Impl::Allocate(sizeof(T) * n)); + } + } + public: + AllocatorTemplate() { /* ... */ } + + template + AllocatorTemplate(const AllocatorTemplate &) { /* ... */ } + + [[nodiscard]] T *allocate(::std::size_t n) { + auto * const p = AllocateImpl(n); + if constexpr (RequireNonNull) { + AMS_ABORT_UNLESS(p != nullptr); + } + return p; + } + + void deallocate(T *p, ::std::size_t n) { + Impl::Deallocate(p, sizeof(T) * n); + } + }; + + template + using AllocatorTemplateForAllocateShared = AllocatorTemplate; - template - std::shared_ptr AllocateShared() { - return std::allocate_shared(StdAllocator{}); } template std::shared_ptr AllocateShared(Args &&... args) { - return std::allocate_shared(StdAllocator{}, std::forward(args)...); + return ::ams::fs::impl::AllocateSharedImpl(std::forward(args)...); + } + + template + Result AllocateSharedForSystem(std::shared_ptr *out, Args &&... args) { + /* Allocate the object. */ + auto p = ::ams::fs::impl::AllocateSharedImpl(std::forward(args)...); + + /* Check that allocation succeeded. */ + R_UNLESS(p != nullptr, ErrorResult()); + + /* Return the allocated object. */ + *out = std::move(p); + return ResultSuccess(); } } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_allocator_utility.cpp b/libraries/libstratosphere/source/fssystem/fssystem_allocator_utility.cpp index cb93483c2..bb9ca6f2b 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_allocator_utility.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_allocator_utility.cpp @@ -21,37 +21,110 @@ namespace ams::fssystem { constexpr bool UseDefaultAllocators = false; - bool g_used_default_allocator; + constinit bool g_used_default_allocator = false; void *DefaultAllocate(size_t size) { g_used_default_allocator = true; - return std::malloc(size); + return ams::Malloc(size); } void DefaultDeallocate(void *ptr, size_t size) { AMS_UNUSED(size); - std::free(ptr); + ams::Free(ptr); } - AllocateFunction g_allocate_func = UseDefaultAllocators ? DefaultAllocate : nullptr; - DeallocateFunction g_deallocate_func = UseDefaultAllocators ? DefaultDeallocate : nullptr; + constinit os::SdkMutex g_allocate_mutex; + constinit os::SdkMutex g_allocate_mutex_for_system; + + constinit AllocateFunction g_allocate_func = UseDefaultAllocators ? DefaultAllocate : nullptr; + constinit DeallocateFunction g_deallocate_func = UseDefaultAllocators ? DefaultDeallocate : nullptr; + + constinit AllocateFunction g_allocate_func_for_system = nullptr; + constinit DeallocateFunction g_deallocate_func_for_system = nullptr; + + void *AllocateUnsafe(size_t size) { + /* Check pre-conditions. */ + AMS_ASSERT(g_allocate_mutex.IsLockedByCurrentThread()); + AMS_ASSERT(g_allocate_func != nullptr); + + /* Allocate memory. */ + return g_allocate_func(size); + } + + void DeallocateUnsafe(void *ptr, size_t size) { + /* Check pre-conditions. */ + AMS_ASSERT(g_allocate_mutex.IsLockedByCurrentThread()); + AMS_ASSERT(g_deallocate_func != nullptr); + + /* Deallocate the pointer. */ + g_deallocate_func(ptr, size); + } + + + } + + namespace impl { + + /* Normal allocator set. */ + template<> void *AllocatorFunctionSet::Allocate(size_t size) { return ::ams::fssystem::Allocate(size); } + template<> void *AllocatorFunctionSet::AllocateUnsafe(size_t size) { return ::ams::fssystem::AllocateUnsafe(size); } + + template<> void AllocatorFunctionSet::Deallocate(void *ptr, size_t size) { return ::ams::fssystem::Deallocate(ptr, size); } + template<> void AllocatorFunctionSet::DeallocateUnsafe(void *ptr, size_t size) { return ::ams::fssystem::DeallocateUnsafe(ptr, size); } + + template<> void AllocatorFunctionSet::LockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex.Lock(); } + template<> void AllocatorFunctionSet::UnlockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex.Unlock(); } + + /* System allocator set. */ + template<> void *AllocatorFunctionSet::AllocateUnsafe(size_t size) { + /* Check pre-conditions. */ + AMS_ASSERT(::ams::fssystem::g_allocate_mutex_for_system.IsLockedByCurrentThread()); + AMS_ASSERT(::ams::fssystem::g_allocate_func_for_system != nullptr); + + /* Allocate memory. */ + return g_allocate_func_for_system(size); + } + + template<> void AllocatorFunctionSet::DeallocateUnsafe(void *ptr, size_t size) { + /* Check pre-conditions. */ + AMS_ASSERT(::ams::fssystem::g_allocate_mutex_for_system.IsLockedByCurrentThread()); + AMS_ASSERT(::ams::fssystem::g_deallocate_func_for_system != nullptr); + + /* Deallocate the pointer. */ + ::ams::fssystem::g_deallocate_func_for_system(ptr, size); + } + + template<> void *AllocatorFunctionSet::Allocate(size_t size) { + std::scoped_lock lk(::ams::fssystem::g_allocate_mutex_for_system); + return ::ams::fssystem::impl::AllocatorFunctionSet::AllocateUnsafe(size); + } + + template<> void AllocatorFunctionSet::Deallocate(void *ptr, size_t size) { + std::scoped_lock lk(::ams::fssystem::g_allocate_mutex_for_system); + return ::ams::fssystem::impl::AllocatorFunctionSet::DeallocateUnsafe(ptr, size); + } + + template<> void AllocatorFunctionSet::LockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex_for_system.Lock(); } + template<> void AllocatorFunctionSet::UnlockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex_for_system.Unlock(); } } void *Allocate(size_t size) { - AMS_ASSERT(g_allocate_func != nullptr); - return g_allocate_func(size); + std::scoped_lock lk(g_allocate_mutex); + return AllocateUnsafe(size); } void Deallocate(void *ptr, size_t size) { - AMS_ASSERT(g_deallocate_func != nullptr); - return g_deallocate_func(ptr, size); + std::scoped_lock lk(g_allocate_mutex); + return DeallocateUnsafe(ptr, size); } void InitializeAllocator(AllocateFunction allocate_func, DeallocateFunction deallocate_func) { + /* Check pre-conditions. */ AMS_ASSERT(allocate_func != nullptr); AMS_ASSERT(deallocate_func != nullptr); + /* Check that we can initialize. */ if constexpr (UseDefaultAllocators) { AMS_ASSERT(g_used_default_allocator == false); } else { @@ -59,8 +132,23 @@ namespace ams::fssystem { AMS_ASSERT(g_deallocate_func == nullptr); } + /* Set the allocator functions. */ g_allocate_func = allocate_func; g_deallocate_func = deallocate_func; } + void InitializeAllocatorForSystem(AllocateFunction allocate_func, DeallocateFunction deallocate_func) { + /* Check pre-conditions. */ + AMS_ASSERT(allocate_func != nullptr); + AMS_ASSERT(deallocate_func != nullptr); + + /* Check that we can initialize. */ + AMS_ASSERT(g_allocate_func_for_system == nullptr); + AMS_ASSERT(g_deallocate_func_for_system == nullptr); + + /* Set the system allocator functions. */ + g_allocate_func_for_system = allocate_func; + g_deallocate_func_for_system = deallocate_func; + } + } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp b/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp index 3aafb281d..92517982a 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp @@ -124,6 +124,7 @@ namespace ams::fssystem { /* TODO FS-REIMPL: sf::SetGlobalDefaultMemoryResource() */ fs::SetAllocator(AllocateForFileSystemProxy, DeallocateForFileSystemProxy); fssystem::InitializeAllocator(AllocateForFileSystemProxy, DeallocateForFileSystemProxy); + fssystem::InitializeAllocatorForSystem(AllocateForFileSystemProxy, DeallocateForFileSystemProxy); /* Initialize the buffer manager. */ /* TODO FS-REIMPL: os::AllocateMemoryBlock(...); */