kernel: memory: Add SlabHeap class, for managing memory heaps.
- This will be used for TLS pages, among other things.
This commit is contained in:
		| @@ -156,6 +156,7 @@ add_library(core STATIC | |||||||
|     hle/kernel/kernel.h |     hle/kernel/kernel.h | ||||||
|     hle/kernel/memory/address_space_info.cpp |     hle/kernel/memory/address_space_info.cpp | ||||||
|     hle/kernel/memory/address_space_info.h |     hle/kernel/memory/address_space_info.h | ||||||
|  |     hle/kernel/memory/slab_heap.h | ||||||
|     hle/kernel/mutex.cpp |     hle/kernel/mutex.cpp | ||||||
|     hle/kernel/mutex.h |     hle/kernel/mutex.h | ||||||
|     hle/kernel/object.cpp |     hle/kernel/object.cpp | ||||||
|   | |||||||
							
								
								
									
										161
									
								
								src/core/hle/kernel/memory/slab_heap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								src/core/hle/kernel/memory/slab_heap.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | |||||||
|  | // Copyright 2020 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <atomic> | ||||||
|  |  | ||||||
|  | #include "common/assert.h" | ||||||
|  | #include "common/common_funcs.h" | ||||||
|  | #include "common/common_types.h" | ||||||
|  |  | ||||||
|  | namespace Kernel::Memory { | ||||||
|  |  | ||||||
|  | namespace impl { | ||||||
|  |  | ||||||
|  | class SlabHeapImpl final : NonCopyable { | ||||||
|  | public: | ||||||
|  |     struct Node { | ||||||
|  |         Node* next{}; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     constexpr SlabHeapImpl() = default; | ||||||
|  |  | ||||||
|  |     void Initialize(std::size_t size) { | ||||||
|  |         ASSERT(head == nullptr); | ||||||
|  |         obj_size = size; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     constexpr std::size_t GetObjectSize() const { | ||||||
|  |         return obj_size; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Node* GetHead() const { | ||||||
|  |         return head; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void* Allocate() { | ||||||
|  |         Node* ret = head.load(); | ||||||
|  |  | ||||||
|  |         do { | ||||||
|  |             if (ret == nullptr) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } while (!head.compare_exchange_weak(ret, ret->next)); | ||||||
|  |  | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Free(void* obj) { | ||||||
|  |         Node* node = reinterpret_cast<Node*>(obj); | ||||||
|  |  | ||||||
|  |         Node* cur_head = head.load(); | ||||||
|  |         do { | ||||||
|  |             node->next = cur_head; | ||||||
|  |         } while (!head.compare_exchange_weak(cur_head, node)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     std::atomic<Node*> head{}; | ||||||
|  |     std::size_t obj_size{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace impl | ||||||
|  |  | ||||||
|  | class SlabHeapBase : NonCopyable { | ||||||
|  | public: | ||||||
|  |     constexpr SlabHeapBase() = default; | ||||||
|  |  | ||||||
|  |     constexpr bool Contains(uintptr_t addr) const { | ||||||
|  |         return start <= addr && addr < end; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     constexpr std::size_t GetSlabHeapSize() const { | ||||||
|  |         return (end - start) / GetObjectSize(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     constexpr std::size_t GetObjectSize() const { | ||||||
|  |         return impl.GetObjectSize(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     constexpr uintptr_t GetSlabHeapAddress() const { | ||||||
|  |         return start; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::size_t GetObjectIndexImpl(const void* obj) const { | ||||||
|  |         return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::size_t GetPeakIndex() const { | ||||||
|  |         return GetObjectIndexImpl(reinterpret_cast<const void*>(peak)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void* AllocateImpl() { | ||||||
|  |         return impl.Allocate(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void FreeImpl(void* obj) { | ||||||
|  |         // Don't allow freeing an object that wasn't allocated from this heap | ||||||
|  |         ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); | ||||||
|  |         impl.Free(obj); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { | ||||||
|  |         // Ensure we don't initialize a slab using null memory | ||||||
|  |         ASSERT(memory != nullptr); | ||||||
|  |  | ||||||
|  |         // Initialize the base allocator | ||||||
|  |         impl.Initialize(obj_size); | ||||||
|  |  | ||||||
|  |         // Set our tracking variables | ||||||
|  |         const std::size_t num_obj = (memory_size / obj_size); | ||||||
|  |         start = reinterpret_cast<uintptr_t>(memory); | ||||||
|  |         end = start + num_obj * obj_size; | ||||||
|  |         peak = start; | ||||||
|  |  | ||||||
|  |         // Free the objects | ||||||
|  |         u8* cur = reinterpret_cast<u8*>(end); | ||||||
|  |  | ||||||
|  |         for (std::size_t i{}; i < num_obj; i++) { | ||||||
|  |             cur -= obj_size; | ||||||
|  |             impl.Free(cur); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     using Impl = impl::SlabHeapImpl; | ||||||
|  |  | ||||||
|  |     Impl impl; | ||||||
|  |     uintptr_t peak{}; | ||||||
|  |     uintptr_t start{}; | ||||||
|  |     uintptr_t end{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | class SlabHeap final : public SlabHeapBase { | ||||||
|  | public: | ||||||
|  |     constexpr SlabHeap() : SlabHeapBase() {} | ||||||
|  |  | ||||||
|  |     void Initialize(void* memory, std::size_t memory_size) { | ||||||
|  |         InitializeImpl(sizeof(T), memory, memory_size); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     T* Allocate() { | ||||||
|  |         T* obj = reinterpret_cast<T*>(AllocateImpl()); | ||||||
|  |         if (obj != nullptr) { | ||||||
|  |             new (obj) T(); | ||||||
|  |         } | ||||||
|  |         return obj; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Free(T* obj) { | ||||||
|  |         FreeImpl(obj); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     constexpr std::size_t GetObjectIndex(const T* obj) const { | ||||||
|  |         return GetObjectIndexImpl(obj); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace Kernel::Memory | ||||||
		Reference in New Issue
	
	Block a user