The Pedigree Project 0.1
SlamAllocator.h
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef SLAM_ALLOCATOR_H
21#define SLAM_ALLOCATOR_H
22#include <config.h>
23
30#include "pedigree/kernel/Spinlock.h"
31#include "pedigree/kernel/TargetInfo.h"
32#include "pedigree/kernel/compiler.h"
33#include "pedigree/kernel/core/SlamBitmap.h"
34#include "pedigree/kernel/processor/types.h"
35#include "pedigree/kernel/utilities/utility.h"
36
37#if PEDIGREE_BENCHMARK
38namespace SlamSupport {
39uintptr_t getHeapBase();
40uintptr_t getHeapEnd();
41void getPageAt(void* addr);
42void unmapPage(void* page);
43void unmapAll();
44} // namespace SlamSupport
45#endif
46
47class SlamAllocator;
48#if PEDIGREE_CONCURRENCY_SMOKE_TESTS
49class EXPORTED_PUBLIC SlamCache;
50#else
51class SlamCache;
52#endif
53
55#define SLAB_SIZE 1
56
58#define SLAB_MINIMUM_SIZE (TargetInfo::getPageSize() * SLAB_SIZE)
59
65#define USING_MAGIC 1
66
68#define MAGIC_TYPE uintptr_t
69
71#define MAGIC_VALUE 0xb00b1e55ULL
72
74#define ABSOLUTE_MINIMUM_SIZE 64
75#define ALL_HEADERS_SIZE \
76 (sizeof(SlamCache::Node) + sizeof(SlamAllocator::AllocHeader) + \
77 sizeof(SlamAllocator::AllocFooter))
78#define OBJECT_MINIMUM_SIZE \
79 (ALL_HEADERS_SIZE < ABSOLUTE_MINIMUM_SIZE ? ABSOLUTE_MINIMUM_SIZE : ALL_HEADERS_SIZE)
80
82#define DEBUGGING_SLAB_ALLOCATOR 0
83
85#define TEMP_MAGIC 0x67845753
86
89#if USE_DEBUG_ALLOCATOR
90#define OVERRUN_CHECK 0
91#else
92#define OVERRUN_CHECK 1
93#endif
94
97#define VIGILANT_OVERRUN_CHECK 0
98
99#define VIGILANT_MAGIC 0x1337cafe
100
103#define CRIPPLINGLY_VIGILANT 0
104
109#define BOCHS_MAGIC_WATCHPOINTS 0
110
114#define SCRIBBLE_FREED_BLOCKS 0
115
117#define WARN_PAGE_SIZE_OR_LARGER 0
118
123#define SLABS_FOR_HUGE_ALLOCS 0
124
126#define VERBOSE_ISPOINTERVALID 0
127
132#define EVERY_ALLOCATION_IS_A_SLAB 0
133
134#ifndef SLAM_USE_DEBUG_ALLOCATOR
136#define SLAM_USE_DEBUG_ALLOCATOR 0
137#endif
138
141#define SLAM_LOCKED SLAM_USE_DEBUG_ALLOCATOR ? 1 : 0 // need the lock for the debug allocator only
142
143#ifndef SLAM_BT_FRAMES
145#define SLAM_BT_FRAMES 3
146#endif
147
149#if PEDIGREE_CONCURRENCY_SMOKE_TESTS
150class EXPORTED_PUBLIC SlamCache {
151#else
153#endif
154 // struct Node must be public so that sizeof(SlamCache::Node) is available.
155 public:
157 struct Node {
158 Node* next;
159#if USING_MAGIC
160 MAGIC_TYPE magic;
161#endif
162 } __attribute__((aligned(16)));
163
165 SlamCache();
168 virtual ~SlamCache();
169
171 void initialise(SlamAllocator* parent, size_t objectSize);
172
174 uintptr_t allocate();
175
177 void free(uintptr_t object);
178
180 size_t recovery(size_t maxSlabs);
181
182 bool isPointerValid(uintptr_t object) const;
183
184#if defined(PEDIGREE_BUILDUTILS)
186 void setListForTest(size_t list);
187#endif
188
189 inline size_t objectSize() const {
190 return m_ObjectSize;
191 }
192
193 inline size_t slabSize() const {
194 return m_SlabSize;
195 }
196
197 inline size_t slabObjectCount() const {
198 return m_SlabObjectCount;
199 }
200
201 void trackSlab(uintptr_t slab);
202 void check();
203
204 private:
205 SlamCache(const SlamCache&);
206 const SlamCache& operator=(const SlamCache&);
207
208 struct Slab {
209 Node* freeHead;
210 Slab* next;
211 Slab* previous;
212 SlamCache* cache;
213 size_t freeObjects;
214 size_t objectCount;
215 size_t list;
216 bool onList;
217 };
218
219 static constexpr const int NUM_LISTS =
220#if defined(PEDIGREE_BUILDUTILS)
221 4;
222#else
223 MULTIPROCESSOR ? 256 : 1;
224#endif
225
226 Slab* m_PartialLists[NUM_LISTS];
227 Slab* m_FastSlabs[NUM_LISTS];
228 Node* m_LargeFreeList;
229
230 void addSlab(Slab* slab, size_t list);
231 void removeSlab(Slab* slab);
232 bool beginFastPath();
233 void endFastPath();
234 Node* popFreeObject(Slab* slab);
235 void pushFreeObject(Slab* slab, Node* node);
236 Node* objectAt(uintptr_t slab, size_t index) const;
237 Slab* slabForObject(uintptr_t object) const;
238
239 uintptr_t getSlab();
240 void freeSlab(uintptr_t slab);
241
242 Node* initialiseSlab(uintptr_t slab);
243 size_t currentList() const;
244
245 size_t m_ObjectSize;
246 size_t m_SlabSize;
247 size_t m_SlabObjectOffset;
248 size_t m_SlabObjectCount;
249
250 // This version of the allocator doesn't have a free list, instead
251 // the reap() function returns memory directly to the VMM. This
252 // avoids needing to lock the free list on MP systems.
253
254 uintptr_t m_FirstSlab;
255 size_t m_FastPathState;
256
262#if BITS_32
263 Spinlock m_FreeLock;
264#endif
265
268
269#if defined(PEDIGREE_BUILDUTILS)
270 size_t m_TestList = 0;
271#endif
272};
273
275 public:
277 virtual ~SlamAllocator();
278
279 void initialise();
280
281 // quickly clear all allocations from the allocator
282 void clearAll();
283
284 uintptr_t allocate(size_t nBytes);
285 void free(uintptr_t mem);
286
287#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
289 static EXPORTED_PUBLIC uintptr_t guardedAllocateForTest(size_t nBytes);
290 static EXPORTED_PUBLIC void guardedFreeForTest(uintptr_t mem);
291#endif
292
293 size_t recovery(size_t maxSlabs = 1);
294
295 bool isPointerValid(uintptr_t mem)
296#if !SLAM_LOCKED
297 const
298#endif
299 ;
300 bool isWithinHeap(uintptr_t mem) const;
301
302 size_t allocSize(uintptr_t mem);
303
304 static EXPORTED_PUBLIC SlamAllocator& instance();
305
306 size_t heapPageCount() const {
307 return m_HeapPageCount;
308 }
309
310 uintptr_t getSlab(size_t fullSize);
311 void freeSlab(uintptr_t address, size_t length);
312
313#if defined(PEDIGREE_BUILDUTILS)
314 enum class SlabTransitionForTest { Reserved, Mapped, Unmapped };
315 using SlabTransitionHookForTest = void (*)(SlabTransitionForTest transition, uintptr_t address,
316 void* context);
317
319 void setSlabTransitionHookForTest(SlabTransitionHookForTest hook, void* context);
320#endif
321
322 private:
325 void freeSlabUnlocked(uintptr_t address, size_t length);
326
327 public:
328 size_t headerSize() const {
329 return sizeof(AllocHeader);
330 }
331 size_t footerSize() const {
332 return sizeof(AllocFooter);
333 }
334
335 void setVigilance(bool b) {
336 m_bVigilant = b;
337 }
338 bool getVigilance() const {
339 return m_bVigilant;
340 }
341
342 private:
343 friend class SlamCache;
344
346 const SlamAllocator& operator=(const SlamAllocator&);
347
348 static SlamAllocator m_Instance;
349
351 void wipe();
352
354 bool isAllocatedPage(uintptr_t address) const;
355
357 void markSlabReady(uintptr_t address, size_t length);
358
359 SlamCache m_Caches[32];
360
361 public:
364 uintptr_t backtrace[SLAM_BT_FRAMES];
365 size_t requested;
366 };
367
370 : pedigree_std::conditional<VIGILANT_OVERRUN_CHECK, AllocHeader_VigilantOverrunCheck,
371 AllocHeader_VigilantOverrunCheck_Empty>::type {
372 size_t magic;
373 };
374
377 struct AllocHeader : pedigree_std::conditional<OVERRUN_CHECK, OverrunCheck_Magic,
378 OverrunCheck_Magic_Empty>::type {
379 // Already-present and embedded Node fields.
380 SlamCache::Node node;
381 SlamCache* cache;
382 } __attribute__((aligned(16)));
383
384 struct AllocFooter : pedigree_std::conditional<OVERRUN_CHECK, OverrunCheck_Magic,
385 OverrunCheck_Magic_Empty>::type {
386 } __attribute__((aligned(16)));
387
388 private:
389 bool m_bInitialised;
390
391 bool m_bVigilant;
392
393 mutable Spinlock m_SlabRegionLock;
394
395 size_t m_HeapPageCount;
396
397 SlamBitmap m_SlabRegionBitmap;
398 size_t m_SlabRegionBitmapEntries;
399 size_t m_SlabRegionPages;
400
401 uintptr_t m_Base;
402
403#if defined(PEDIGREE_BUILDUTILS)
404 SlabTransitionHookForTest m_SlabTransitionHook = nullptr;
405 void* m_SlabTransitionHookContext = nullptr;
406#endif
407
408 Spinlock m_Lock;
409};
410
411#endif
Spinlock m_RecoveryLock
SlamAllocator * m_pParentAllocator
Definition mem.c:283