Browse Source
kernel: memory: Add SlabHeap class, for managing memory heaps.
kernel: memory: Add SlabHeap class, for managing memory heaps.
- This will be used for TLS pages, among other things.pull/15/merge
2 changed files with 162 additions and 0 deletions
@ -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 |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue