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/memory/address_space_info.cpp | ||||
|     hle/kernel/memory/address_space_info.h | ||||
|     hle/kernel/memory/slab_heap.h | ||||
|     hle/kernel/mutex.cpp | ||||
|     hle/kernel/mutex.h | ||||
|     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