summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/hle/kernel/memory/slab_heap.h161
2 files changed, 162 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e98091cba..82efb9e21 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -156,6 +156,7 @@ add_library(core STATIC
156 hle/kernel/kernel.h 156 hle/kernel/kernel.h
157 hle/kernel/memory/address_space_info.cpp 157 hle/kernel/memory/address_space_info.cpp
158 hle/kernel/memory/address_space_info.h 158 hle/kernel/memory/address_space_info.h
159 hle/kernel/memory/slab_heap.h
159 hle/kernel/mutex.cpp 160 hle/kernel/mutex.cpp
160 hle/kernel/mutex.h 161 hle/kernel/mutex.h
161 hle/kernel/object.cpp 162 hle/kernel/object.cpp
diff --git a/src/core/hle/kernel/memory/slab_heap.h b/src/core/hle/kernel/memory/slab_heap.h
new file mode 100644
index 000000000..ca334384b
--- /dev/null
+++ b/src/core/hle/kernel/memory/slab_heap.h
@@ -0,0 +1,161 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8
9#include "common/assert.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12
13namespace Kernel::Memory {
14
15namespace impl {
16
17class SlabHeapImpl final : NonCopyable {
18public:
19 struct Node {
20 Node* next{};
21 };
22
23 constexpr SlabHeapImpl() = default;
24
25 void Initialize(std::size_t size) {
26 ASSERT(head == nullptr);
27 obj_size = size;
28 }
29
30 constexpr std::size_t GetObjectSize() const {
31 return obj_size;
32 }
33
34 Node* GetHead() const {
35 return head;
36 }
37
38 void* Allocate() {
39 Node* ret = head.load();
40
41 do {
42 if (ret == nullptr) {
43 break;
44 }
45 } while (!head.compare_exchange_weak(ret, ret->next));
46
47 return ret;
48 }
49
50 void Free(void* obj) {
51 Node* node = reinterpret_cast<Node*>(obj);
52
53 Node* cur_head = head.load();
54 do {
55 node->next = cur_head;
56 } while (!head.compare_exchange_weak(cur_head, node));
57 }
58
59private:
60 std::atomic<Node*> head{};
61 std::size_t obj_size{};
62};
63
64} // namespace impl
65
66class SlabHeapBase : NonCopyable {
67public:
68 constexpr SlabHeapBase() = default;
69
70 constexpr bool Contains(uintptr_t addr) const {
71 return start <= addr && addr < end;
72 }
73
74 constexpr std::size_t GetSlabHeapSize() const {
75 return (end - start) / GetObjectSize();
76 }
77
78 constexpr std::size_t GetObjectSize() const {
79 return impl.GetObjectSize();
80 }
81
82 constexpr uintptr_t GetSlabHeapAddress() const {
83 return start;
84 }
85
86 std::size_t GetObjectIndexImpl(const void* obj) const {
87 return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize();
88 }
89
90 std::size_t GetPeakIndex() const {
91 return GetObjectIndexImpl(reinterpret_cast<const void*>(peak));
92 }
93
94 void* AllocateImpl() {
95 return impl.Allocate();
96 }
97
98 void FreeImpl(void* obj) {
99 // Don't allow freeing an object that wasn't allocated from this heap
100 ASSERT(Contains(reinterpret_cast<uintptr_t>(obj)));
101 impl.Free(obj);
102 }
103
104 void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) {
105 // Ensure we don't initialize a slab using null memory
106 ASSERT(memory != nullptr);
107
108 // Initialize the base allocator
109 impl.Initialize(obj_size);
110
111 // Set our tracking variables
112 const std::size_t num_obj = (memory_size / obj_size);
113 start = reinterpret_cast<uintptr_t>(memory);
114 end = start + num_obj * obj_size;
115 peak = start;
116
117 // Free the objects
118 u8* cur = reinterpret_cast<u8*>(end);
119
120 for (std::size_t i{}; i < num_obj; i++) {
121 cur -= obj_size;
122 impl.Free(cur);
123 }
124 }
125
126private:
127 using Impl = impl::SlabHeapImpl;
128
129 Impl impl;
130 uintptr_t peak{};
131 uintptr_t start{};
132 uintptr_t end{};
133};
134
135template <typename T>
136class SlabHeap final : public SlabHeapBase {
137public:
138 constexpr SlabHeap() : SlabHeapBase() {}
139
140 void Initialize(void* memory, std::size_t memory_size) {
141 InitializeImpl(sizeof(T), memory, memory_size);
142 }
143
144 T* Allocate() {
145 T* obj = reinterpret_cast<T*>(AllocateImpl());
146 if (obj != nullptr) {
147 new (obj) T();
148 }
149 return obj;
150 }
151
152 void Free(T* obj) {
153 FreeImpl(obj);
154 }
155
156 constexpr std::size_t GetObjectIndex(const T* obj) const {
157 return GetObjectIndexImpl(obj);
158 }
159};
160
161} // namespace Kernel::Memory