VirtualBox

source: vbox/trunk/src/VBox/Runtime/alloc/heapsimple.cpp@ 1816

Last change on this file since 1816 was 1816, checked in by vboxsync, 18 years ago

moved magics to a common header to avoid duplicating the same defines all over the place.

  • Property svn:keywords set to Id
File size: 30.0 KB
Line 
1/* $Id: heapsimple.cpp 1816 2007-03-29 18:59:35Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - A Simple Heap.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP RTLOGGROUP_DEFAULT
27#include <iprt/heap.h>
28#include <iprt/assert.h>
29#include <iprt/asm.h>
30#include <iprt/string.h>
31#include <iprt/err.h>
32#include <iprt/log.h>
33#include <iprt/param.h>
34
35#include "internal/magics.h"
36
37
38/*******************************************************************************
39* Structures and Typedefs *
40*******************************************************************************/
41/** Pointer to the heap anchor block. */
42typedef struct RTHEAPSIMPLEINTERNAL *PRTHEAPSIMPLEINTERNAL;
43/** Pointer to a heap block. */
44typedef struct RTHEAPSIMPLEBLOCK *PRTHEAPSIMPLEBLOCK;
45/** Pointer to a free heap block. */
46typedef struct RTHEAPSIMPLEFREE *PRTHEAPSIMPLEFREE;
47
48/**
49 * Structure describing a simple heap block.
50 * If this block is allocated, it is followed by the user user data.
51 * If this block is free, see RTHEAPSIMPLEFREE.
52 */
53typedef struct RTHEAPSIMPLEBLOCK
54{
55 /** The next block in the global block list. */
56 PRTHEAPSIMPLEBLOCK pNext;
57 /** The previous block in the global block list. */
58 PRTHEAPSIMPLEBLOCK pPrev;
59 /** Pointer to the heap anchor block. */
60 PRTHEAPSIMPLEINTERNAL pHeap;
61 /** Flags + magic. */
62 uintptr_t fFlags;
63} RTHEAPSIMPLEBLOCK;
64AssertCompileSizeAlignment(RTHEAPSIMPLEBLOCK, 16);
65
66/** The block is free if this flag is set. When cleared it's allocated. */
67#define RTHEAPSIMPLEBLOCK_FLAGS_FREE ((uintptr_t)BIT(0))
68/** The magic value. */
69#define RTHEAPSIMPLEBLOCK_FLAGS_MAGIC ((uintptr_t)0xabcdef00)
70/** The mask that needs to be applied to RTHEAPSIMPLEBLOCK::fFalgs to obtain the magic value. */
71#define RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK (~(uintptr_t)BIT(0))
72
73/**
74 * Checks if the specified block is valid or not.
75 * @returns boolean answer.
76 * @param pBlock Pointer to a RTHEAPSIMPLEBLOCK structure.
77 */
78#define RTHEAPSIMPLEBLOCK_IS_VALID(pBlock) \
79 ( ((pBlock)->fFlags & RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK) == RTHEAPSIMPLEBLOCK_FLAGS_MAGIC )
80
81/**
82 * Checks if the specified block is valid and in use.
83 * @returns boolean answer.
84 * @param pBlock Pointer to a RTHEAPSIMPLEBLOCK structure.
85 */
86#define RTHEAPSIMPLEBLOCK_IS_VALID_USED(pBlock) \
87 ( ((pBlock)->fFlags & (RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK | RTHEAPSIMPLEBLOCK_FLAGS_FREE)) \
88 == RTHEAPSIMPLEBLOCK_FLAGS_MAGIC )
89
90/**
91 * Checks if the specified block is valid and free.
92 * @returns boolean answer.
93 * @param pBlock Pointer to a RTHEAPSIMPLEBLOCK structure.
94 */
95#define RTHEAPSIMPLEBLOCK_IS_VALID_FREE(pBlock) \
96 ( ((pBlock)->fFlags & (RTHEAPSIMPLEBLOCK_FLAGS_MAGIC_MASK | RTHEAPSIMPLEBLOCK_FLAGS_FREE)) \
97 == (RTHEAPSIMPLEBLOCK_FLAGS_MAGIC | RTHEAPSIMPLEBLOCK_FLAGS_FREE) )
98
99/**
100 * Checks if the specified block is free or not.
101 * @returns boolean answer.
102 * @param pBlock Pointer to a valid RTHEAPSIMPLEBLOCK structure.
103 */
104#define RTHEAPSIMPLEBLOCK_IS_FREE(pBlock) (!!((pBlock)->fFlags & RTHEAPSIMPLEBLOCK_FLAGS_FREE))
105
106/**
107 * A free heap block.
108 * This is an extended version of RTHEAPSIMPLEBLOCK that takes the unused
109 * user data to store free list pointers and a cached size value.
110 */
111typedef struct RTHEAPSIMPLEFREE
112{
113 /** Core stuff. */
114 RTHEAPSIMPLEBLOCK Core;
115 /** Pointer to the next free block. */
116 PRTHEAPSIMPLEFREE pNext;
117 /** Pointer to the previous free block. */
118 PRTHEAPSIMPLEFREE pPrev;
119 /** The size of the block (excluding the RTHEAPSIMPLEBLOCK part). */
120 size_t cb;
121 /** An alignment filler to make it a multiple of (sizeof(void *) * 2). */
122 size_t Alignment;
123} RTHEAPSIMPLEFREE;
124
125
126/**
127 * The heap anchor block.
128 * This structure is placed at the head of the memory block specified to RTHeapSimpleInit(),
129 * which means that the first RTHEAPSIMPLEBLOCK appears immediately after this structure.
130 */
131typedef struct RTHEAPSIMPLEINTERNAL
132{
133 /** The typical magic (RTHEAPSIMPLE_MAGIC). */
134 size_t uMagic;
135 /** The heap size. (This structure is not included!) */
136 size_t cbHeap;
137 /** Pointer to the end of the heap. */
138 void *pvEnd;
139 /** The amount of free memory in the heap. */
140 size_t cbFree;
141 /** Free head pointer. */
142 PRTHEAPSIMPLEFREE pFreeHead;
143 /** Free tail pointer. */
144 PRTHEAPSIMPLEFREE pFreeTail;
145 /** Make the size of this structure is a multiple of 32. */
146 size_t auAlignment[2];
147} RTHEAPSIMPLEINTERNAL;
148AssertCompileSizeAlignment(RTHEAPSIMPLEINTERNAL, 32);
149
150
151/** The minimum allocation size. */
152#define RTHEAPSIMPLE_MIN_BLOCK (sizeof(RTHEAPSIMPLEBLOCK))
153AssertCompile(RTHEAPSIMPLE_MIN_BLOCK >= sizeof(RTHEAPSIMPLEBLOCK));
154AssertCompile(RTHEAPSIMPLE_MIN_BLOCK >= sizeof(RTHEAPSIMPLEFREE) - sizeof(RTHEAPSIMPLEBLOCK));
155
156/** The minimum and default alignment. */
157#define RTHEAPSIMPLE_ALIGNMENT (sizeof(RTHEAPSIMPLEBLOCK))
158
159
160/*******************************************************************************
161* Defined Constants And Macros *
162*******************************************************************************/
163#ifdef RT_STRICT
164# define RTHEAPSIMPLE_STRICT 1
165#endif
166
167#define ASSERT_L(a, b) AssertMsg((uintptr_t)(a) < (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
168#define ASSERT_LE(a, b) AssertMsg((uintptr_t)(a) <= (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
169#define ASSERT_G(a, b) AssertMsg((uintptr_t)(a) > (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
170#define ASSERT_GE(a, b) AssertMsg((uintptr_t)(a) >= (uintptr_t)(b), ("a=%p b=%p\n", (uintptr_t)(a), (uintptr_t)(b)))
171#define ASSERT_ALIGN(a) AssertMsg(!((uintptr_t)(a) & (RTHEAPSIMPLE_ALIGNMENT - 1)), ("a=%p\n", (uintptr_t)(a)))
172
173#define ASSERT_PREV(pHeapInt, pBlock) \
174 do { ASSERT_ALIGN((pBlock)->pPrev); \
175 if ((pBlock)->pPrev) \
176 { \
177 ASSERT_L((pBlock)->pPrev, (pBlock)); \
178 ASSERT_GE((pBlock)->pPrev, (pHeapInt) + 1); \
179 } \
180 else \
181 Assert((pBlock) == (PRTHEAPSIMPLEBLOCK)((pHeapInt) + 1)); \
182 } while (0)
183
184#define ASSERT_NEXT(pHeap, pBlock) \
185 do { ASSERT_ALIGN((pBlock)->pNext); \
186 if ((pBlock)->pNext) \
187 { \
188 ASSERT_L((pBlock)->pNext, (pHeapInt)->pvEnd); \
189 ASSERT_G((pBlock)->pNext, (pBlock)); \
190 } \
191 } while (0)
192
193#define ASSERT_BLOCK(pHeapInt, pBlock) \
194 do { AssertMsg(RTHEAPSIMPLEBLOCK_IS_VALID(pBlock), ("%#x\n", (pBlock)->fFlags)); \
195 AssertMsg((pBlock)->pHeap == (pHeapInt), ("%p != %p\n", (pBlock)->pHeap, (pHeapInt))); \
196 ASSERT_GE((pBlock), (pHeapInt) + 1); \
197 ASSERT_L((pBlock), (pHeapInt)->pvEnd); \
198 ASSERT_NEXT(pHeapInt, pBlock); \
199 ASSERT_PREV(pHeapInt, pBlock); \
200 } while (0)
201
202#define ASSERT_BLOCK_USED(pHeapInt, pBlock) \
203 do { AssertMsg(RTHEAPSIMPLEBLOCK_IS_VALID_USED((pBlock)), ("%#x\n", (pBlock)->fFlags)); \
204 AssertMsg((pBlock)->pHeap == (pHeapInt), ("%p != %p\n", (pBlock)->pHeap, (pHeapInt))); \
205 ASSERT_GE((pBlock), (pHeapInt) + 1); \
206 ASSERT_L((pBlock), (pHeapInt)->pvEnd); \
207 ASSERT_NEXT(pHeapInt, pBlock); \
208 ASSERT_PREV(pHeapInt, pBlock); \
209 } while (0)
210
211#define ASSERT_FREE_PREV(pHeapInt, pBlock) \
212 do { ASSERT_ALIGN((pBlock)->pPrev); \
213 if ((pBlock)->pPrev) \
214 { \
215 ASSERT_GE((pBlock)->pPrev, (pHeapInt)->pFreeHead); \
216 ASSERT_L((pBlock)->pPrev, (pBlock)); \
217 ASSERT_LE((pBlock)->pPrev, (pBlock)->Core.pPrev); \
218 } \
219 else \
220 Assert((pBlock) == (pHeapInt)->pFreeHead); \
221 } while (0)
222
223#define ASSERT_FREE_NEXT(pHeapInt, pBlock) \
224 do { ASSERT_ALIGN((pBlock)->pNext); \
225 if ((pBlock)->pNext) \
226 { \
227 ASSERT_LE((pBlock)->pNext, (pHeapInt)->pFreeTail); \
228 ASSERT_G((pBlock)->pNext, (pBlock)); \
229 ASSERT_GE((pBlock)->pNext, (pBlock)->Core.pNext); \
230 } \
231 else \
232 Assert((pBlock) == (pHeapInt)->pFreeTail); \
233 } while (0)
234
235#ifdef RTHEAPSIMPLE_STRICT
236# define ASSERT_FREE_CB(pHeapInt, pBlock) \
237 do { size_t cbCalc = ((pBlock)->Core.pNext ? (uintptr_t)(pBlock)->Core.pNext : (uintptr_t)(pHeapInt)->pvEnd) \
238 - (uintptr_t)(pBlock) - sizeof(RTHEAPSIMPLEBLOCK); \
239 AssertMsg((pBlock)->cb == cbCalc, ("cb=%#zx cbCalc=%#zx\n", (pBlock)->cb, cbCalc)); \
240 } while (0)
241#else
242# define ASSERT_FREE_CB(pHeapInt, pBlock) do {} while (0)
243#endif
244
245/** Asserts that a free block is valid. */
246#define ASSERT_BLOCK_FREE(pHeapInt, pBlock) \
247 do { ASSERT_BLOCK(pHeapInt, &(pBlock)->Core); \
248 Assert(RTHEAPSIMPLEBLOCK_IS_VALID_FREE(&(pBlock)->Core)); \
249 ASSERT_GE((pBlock), (pHeapInt)->pFreeHead); \
250 ASSERT_LE((pBlock), (pHeapInt)->pFreeTail); \
251 ASSERT_FREE_NEXT(pHeapInt, pBlock); \
252 ASSERT_FREE_PREV(pHeapInt, pBlock); \
253 ASSERT_FREE_CB(pHeapInt, pBlock); \
254 } while (0)
255
256/** Asserts that the heap anchor block is ok. */
257#define ASSERT_ANCHOR(pHeapInt) \
258 do { AssertPtr(pHeapInt);\
259 Assert((pHeapInt)->uMagic == RTHEAPSIMPLE_MAGIC); \
260 } while (0)
261
262
263/*******************************************************************************
264* Internal Functions *
265*******************************************************************************/
266#ifdef RTHEAPSIMPLE_STRICT
267static void rtHeapSimpleAssertAll(PRTHEAPSIMPLEINTERNAL pHeapInt);
268#endif
269static PRTHEAPSIMPLEBLOCK rtHeapSimpleAllocBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, size_t cb, size_t uAlignment);
270static void rtHeapSimpleFreeBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, PRTHEAPSIMPLEBLOCK pBlock);
271
272
273/**
274 * Initializes the heap.
275 *
276 * @returns IPRT status code on success.
277 * @param pHeap Where to store the heap anchor block on success.
278 * @param pvMemory Pointer to the heap memory.
279 * @param cbMemory The size of the heap memory.
280 */
281RTDECL(int) RTHeapSimpleInit(PRTHEAPSIMPLE pHeap, void *pvMemory, size_t cbMemory)
282{
283 /*
284 * Validate input. The imposed minimum heap size is just a convenien value.
285 */
286 AssertReturn(cbMemory >= PAGE_SIZE, VERR_INVALID_PARAMETER);
287 AssertPtrReturn(pvMemory, VERR_INVALID_POINTER);
288 AssertReturn((uintptr_t)pvMemory + (cbMemory - 1) > (uintptr_t)cbMemory, VERR_INVALID_PARAMETER);
289
290 /*
291 * Place the heap anchor block at the start of the heap memory,
292 * enforce 32 byte alignment of it. Also align the heap size correctly.
293 */
294 PRTHEAPSIMPLEINTERNAL pHeapInt = (PRTHEAPSIMPLEINTERNAL)pvMemory;
295 if ((uintptr_t)pvMemory & 31)
296 {
297 const unsigned off = 32 - ((uintptr_t)pvMemory & 31);
298 cbMemory -= off;
299 pHeapInt = (PRTHEAPSIMPLEINTERNAL)((uintptr_t)pvMemory + off);
300 }
301 cbMemory &= ~(RTHEAPSIMPLE_ALIGNMENT - 1);
302
303
304 /* Init the heap anchor block. */
305 pHeapInt->uMagic = RTHEAPSIMPLE_MAGIC;
306 pHeapInt->pvEnd = (uint8_t *)pHeapInt + cbMemory;
307 pHeapInt->cbHeap = cbMemory;
308 pHeapInt->cbFree = cbMemory
309 - sizeof(RTHEAPSIMPLEBLOCK)
310 - sizeof(RTHEAPSIMPLEINTERNAL);
311 pHeapInt->pFreeTail = pHeapInt->pFreeHead = (PRTHEAPSIMPLEFREE)(pHeapInt + 1);
312 unsigned i;
313 for (i = 0; i < ELEMENTS(pHeapInt->auAlignment); i++)
314 pHeapInt->auAlignment[i] = ~(size_t)0;
315
316 /* Init the single free block. */
317 PRTHEAPSIMPLEFREE pFree = pHeapInt->pFreeHead;
318 pFree->Core.pNext = NULL;
319 pFree->Core.pPrev = NULL;
320 pFree->Core.pHeap = pHeapInt;
321 pFree->Core.fFlags = RTHEAPSIMPLEBLOCK_FLAGS_MAGIC | RTHEAPSIMPLEBLOCK_FLAGS_FREE;
322 pFree->pNext = NULL;
323 pFree->pPrev = NULL;
324 pFree->cb = pHeapInt->cbFree;
325
326 *pHeap = pHeapInt;
327
328#ifdef RTHEAPSIMPLE_STRICT
329 rtHeapSimpleAssertAll(pHeapInt);
330#endif
331 return VINF_SUCCESS;
332}
333
334
335
336/**
337 * Allocates memory from the specified simple heap.
338 *
339 * @returns Pointer to the allocated memory block on success.
340 * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.)
341 *
342 * @param Heap The heap to allocate the memory on.
343 * @param cb The requested heap block size.
344 * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment.
345 * Must be a power of 2.
346 */
347RTDECL(void *) RTHeapSimpleAlloc(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment)
348{
349 PRTHEAPSIMPLEINTERNAL pHeapInt = Heap;
350
351 /*
352 * Validate and adjust the input.
353 */
354 AssertPtrReturn(pHeapInt, NULL);
355 if (cb < RTHEAPSIMPLE_MIN_BLOCK)
356 cb = RTHEAPSIMPLE_MIN_BLOCK;
357 else
358 cb = RT_ALIGN_Z(cb, RTHEAPSIMPLE_ALIGNMENT);
359 if (!cbAlignment)
360 cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
361 else
362 {
363 Assert(!(cbAlignment & (cbAlignment - 1)));
364 Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
365 if (cbAlignment < RTHEAPSIMPLE_ALIGNMENT)
366 cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
367 }
368
369 /*
370 * Do the allocation.
371 */
372 PRTHEAPSIMPLEBLOCK pBlock = rtHeapSimpleAllocBlock(pHeapInt, cb, cbAlignment);
373 if (RT_LIKELY(pBlock))
374 {
375 void *pv = pBlock + 1;
376 return pv;
377 }
378 return NULL;
379}
380
381
382/**
383 * Allocates zeroed memory from the specified simple heap.
384 *
385 * @returns Pointer to the allocated memory block on success.
386 * @returns NULL if the request cannot be satisfied. (A VERR_NO_MEMORY condition.)
387 *
388 * @param Heap The heap to allocate the memory on.
389 * @param cb The requested heap block size.
390 * @param cbAlignment The requested heap block alignment. Pass 0 for default alignment.
391 * Must be a power of 2.
392 */
393RTDECL(void *) RTHeapSimpleAllocZ(RTHEAPSIMPLE Heap, size_t cb, size_t cbAlignment)
394{
395 PRTHEAPSIMPLEINTERNAL pHeapInt = Heap;
396
397 /*
398 * Validate and adjust the input.
399 */
400 AssertPtrReturn(pHeapInt, NULL);
401 if (cb < RTHEAPSIMPLE_MIN_BLOCK)
402 cb = RTHEAPSIMPLE_MIN_BLOCK;
403 else
404 cb = RT_ALIGN_Z(cb, RTHEAPSIMPLE_ALIGNMENT);
405 if (!cbAlignment)
406 cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
407 else
408 {
409 Assert(!(cbAlignment & (cbAlignment - 1)));
410 Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
411 if (cbAlignment < RTHEAPSIMPLE_ALIGNMENT)
412 cbAlignment = RTHEAPSIMPLE_ALIGNMENT;
413 }
414
415 /*
416 * Do the allocation.
417 */
418 PRTHEAPSIMPLEBLOCK pBlock = rtHeapSimpleAllocBlock(pHeapInt, cb, cbAlignment);
419 if (RT_LIKELY(pBlock))
420 {
421 void *pv = pBlock + 1;
422 memset(pv, 0, cb);
423 return pv;
424 }
425 return NULL;
426}
427
428
429/**
430 * Allocates a block of memory from the specified heap.
431 *
432 * No parameter validation or adjustment is preformed.
433 *
434 * @returns Pointer to the allocated block.
435 * @returns NULL on failure.
436 * @param pHeap The heap.
437 * @param cb Size of the memory block to allocate.
438 * @param uAlignment The alignment specifications for the allocated block.
439 */
440static PRTHEAPSIMPLEBLOCK rtHeapSimpleAllocBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, size_t cb, size_t uAlignment)
441{
442#ifdef RTHEAPSIMPLE_STRICT
443 rtHeapSimpleAssertAll(pHeapInt);
444#endif
445
446 /*
447 * Search for a fitting block from the lower end of the heap.
448 */
449 PRTHEAPSIMPLEBLOCK pRet = NULL;
450 PRTHEAPSIMPLEFREE pFree;
451 for (pFree = pHeapInt->pFreeHead;
452 pFree;
453 pFree = pFree->pNext)
454 {
455 ASSERT_BLOCK_FREE(pHeapInt, pFree);
456
457 /*
458 * Match for size and alignment.
459 */
460 if (pFree->cb < cb)
461 continue;
462 uintptr_t offAlign = (uintptr_t)(&pFree->Core + 1) & (uAlignment - 1);
463 if (offAlign)
464 {
465 offAlign = uAlignment - offAlign;
466 if (pFree->cb - offAlign < cb)
467 continue;
468
469 /*
470 * Make a stack copy of the free block header and adjust the pointer.
471 */
472 RTHEAPSIMPLEFREE Free = *pFree;
473 pFree = (PRTHEAPSIMPLEFREE)((uintptr_t)pFree + offAlign);
474
475 /*
476 * Donate offAlign bytes to the node in front of us.
477 * If we're the head node, we'll have to create a fake node. We'll
478 * mark it USED for simplicity.
479 *
480 * (Should this policy of donating memory to the guy in front of us
481 * cause big 'leaks', we could create a new free node if there is room
482 * for that.)
483 */
484 PRTHEAPSIMPLEBLOCK pPrev = Free.Core.pPrev;
485 if (pPrev)
486 {
487 AssertMsg(!RTHEAPSIMPLEBLOCK_IS_FREE(pPrev), ("Impossible!\n"));
488 pPrev->pNext = &pFree->Core;
489 }
490 else
491 {
492 pPrev = (PRTHEAPSIMPLEBLOCK)(pHeapInt + 1);
493 Assert(pPrev == &pFree->Core);
494 pPrev->pPrev = NULL;
495 pPrev->pNext = &pFree->Core;
496 pPrev->pHeap = pHeapInt;
497 pPrev->fFlags = RTHEAPSIMPLEBLOCK_FLAGS_MAGIC;
498 }
499 pHeapInt->cbFree -= offAlign;
500
501 /*
502 * Recreate pFree in the new position and adjust the neighbours.
503 */
504 *pFree = Free;
505
506 /* the core */
507 if (pFree->Core.pNext)
508 pFree->Core.pNext->pPrev = &pFree->Core;
509 pFree->Core.pPrev = pPrev;
510
511 /* the free part */
512 pFree->cb -= offAlign;
513 if (pFree->pNext)
514 pFree->pNext->pPrev = pFree;
515 else
516 pHeapInt->pFreeTail = pFree;
517 if (pFree->pPrev)
518 pFree->pPrev->pNext = pFree;
519 else
520 pHeapInt->pFreeHead = pFree;
521 ASSERT_BLOCK_FREE(pHeapInt, pFree);
522 ASSERT_BLOCK_USED(pHeapInt, pPrev);
523 }
524
525 /*
526 * Split off a new FREE block?
527 */
528 if (pFree->cb >= cb + RT_ALIGN_Z(sizeof(RTHEAPSIMPLEFREE), RTHEAPSIMPLE_ALIGNMENT))
529 {
530 /*
531 * Move the FREE block up to make room for the new USED block.
532 */
533 PRTHEAPSIMPLEFREE pNew = (PRTHEAPSIMPLEFREE)((uintptr_t)&pFree->Core + cb + sizeof(RTHEAPSIMPLEBLOCK));
534
535 pNew->Core.pNext = pFree->Core.pNext;
536 if (pFree->Core.pNext)
537 pFree->Core.pNext->pPrev = &pNew->Core;
538 pNew->Core.pPrev = &pFree->Core;
539 pNew->Core.pHeap = pHeapInt;
540 pNew->Core.fFlags = RTHEAPSIMPLEBLOCK_FLAGS_MAGIC | RTHEAPSIMPLEBLOCK_FLAGS_FREE;
541
542 pNew->pNext = pFree->pNext;
543 if (pNew->pNext)
544 pNew->pNext->pPrev = pNew;
545 else
546 pHeapInt->pFreeTail = pNew;
547 pNew->pPrev = pFree->pPrev;
548 if (pNew->pPrev)
549 pNew->pPrev->pNext = pNew;
550 else
551 pHeapInt->pFreeHead = pNew;
552 pNew->cb = (pNew->Core.pNext ? (uintptr_t)pNew->Core.pNext : (uintptr_t)pHeapInt->pvEnd) \
553 - (uintptr_t)pNew - sizeof(RTHEAPSIMPLEBLOCK);
554 ASSERT_BLOCK_FREE(pHeapInt, pNew);
555
556 /*
557 * Update the old FREE node making it a USED node.
558 */
559 pFree->Core.fFlags &= ~RTHEAPSIMPLEBLOCK_FLAGS_FREE;
560 pFree->Core.pNext = &pNew->Core;
561 pHeapInt->cbFree -= pFree->cb;
562 pHeapInt->cbFree += pNew->cb;
563 pRet = &pFree->Core;
564 ASSERT_BLOCK_USED(pHeapInt, pRet);
565 }
566 else
567 {
568 /*
569 * Link it out of the free list.
570 */
571 if (pFree->pNext)
572 pFree->pNext->pPrev = pFree->pPrev;
573 else
574 pHeapInt->pFreeTail = pFree->pPrev;
575 if (pFree->pPrev)
576 pFree->pPrev->pNext = pFree->pNext;
577 else
578 pHeapInt->pFreeHead = pFree->pNext;
579
580 /*
581 * Convert it to a used block.
582 */
583 pHeapInt->cbFree -= pFree->cb;
584 pFree->Core.fFlags &= ~RTHEAPSIMPLEBLOCK_FLAGS_FREE;
585 pRet = &pFree->Core;
586 ASSERT_BLOCK_USED(pHeapInt, pRet);
587 }
588 break;
589 }
590
591#ifdef RTHEAPSIMPLE_STRICT
592 rtHeapSimpleAssertAll(pHeapInt);
593#endif
594 return pRet;
595}
596
597
598
599
600/**
601 * Frees memory allocated from a simple heap.
602 *
603 * @param Heap The heap. This is optional and will only be used for strict assertions.
604 * @param pv The heap block returned by RTHeapSimple
605 */
606RTDECL(void) RTHeapSimpleFree(RTHEAPSIMPLE Heap, void *pv)
607{
608 /*
609 * Validate input.
610 */
611 if (!pv)
612 return;
613 AssertPtr(pv);
614 Assert(RT_ALIGN_P(pv, RTHEAPSIMPLE_ALIGNMENT) == pv);
615
616 /*
617 * Get the block and heap. If in strict mode, validate these.
618 */
619 PRTHEAPSIMPLEBLOCK pBlock = (PRTHEAPSIMPLEBLOCK)pv - 1;
620 PRTHEAPSIMPLEINTERNAL pHeapInt = pBlock->pHeap;
621 ASSERT_BLOCK_USED(pHeapInt, pBlock);
622 ASSERT_ANCHOR(pHeapInt);
623 Assert(pHeapInt == (PRTHEAPSIMPLEINTERNAL)Heap || !Heap);
624
625#ifdef RTHEAPSIMPLE_FREE_POISON
626 /*
627 * Poison the block.
628 */
629 const size_t cbBlock = (pBlock->pNext ? (uintptr_t)pBlock->pNext : (uintptr_t)pHeapInt->pvEnd)
630 - (uintptr_t)pBlock - sizeof(RTHEAPSIMPLEBLOCK);
631 memset(pBlock + 1, RTHEAPSIMPLE_FREE_POISON, cbBlock);
632#endif
633
634 /*
635 * Call worker which does the actual job.
636 */
637 rtHeapSimpleFreeBlock(pHeapInt, pBlock);
638}
639
640
641/**
642 * Free memory a memory block.
643 *
644 * @param pHeapInt The heap.
645 * @param pBlock The memory block to free.
646 */
647static void rtHeapSimpleFreeBlock(PRTHEAPSIMPLEINTERNAL pHeapInt, PRTHEAPSIMPLEBLOCK pBlock)
648{
649 PRTHEAPSIMPLEFREE pFree = (PRTHEAPSIMPLEFREE)pBlock;
650
651#ifdef RTHEAPSIMPLE_STRICT
652 rtHeapSimpleAssertAll(pHeapInt);
653#endif
654
655 /*
656 * Look for the closest free list blocks by walking the blocks right
657 * of us (both list are sorted on address).
658 */
659 PRTHEAPSIMPLEFREE pLeft = NULL;
660 PRTHEAPSIMPLEFREE pRight = NULL;
661 if (pHeapInt->pFreeTail)
662 {
663 pRight = (PRTHEAPSIMPLEFREE)pFree->Core.pNext;
664 while (pRight && !RTHEAPSIMPLEBLOCK_IS_FREE(&pRight->Core))
665 {
666 ASSERT_BLOCK(pHeapInt, &pRight->Core);
667 pRight = (PRTHEAPSIMPLEFREE)pRight->Core.pNext;
668 }
669 if (!pRight)
670 pLeft = pHeapInt->pFreeTail;
671 else
672 {
673 ASSERT_BLOCK_FREE(pHeapInt, pRight);
674 pLeft = pRight->pPrev;
675 }
676 if (pLeft)
677 ASSERT_BLOCK_FREE(pHeapInt, pLeft);
678 }
679 AssertMsgReturnVoid(pLeft != pFree, ("Freed twice! pv=%p (pBlock=%p)\n", pBlock + 1, pBlock));
680 ASSERT_L(pLeft, pFree);
681 Assert(!pRight || (uintptr_t)pRight > (uintptr_t)pFree);
682 Assert(!pLeft || pLeft->pNext == pRight);
683
684 /*
685 * Insert at the head of the free block list?
686 */
687 if (!pLeft)
688 {
689 Assert(pRight == pHeapInt->pFreeHead);
690 pFree->Core.fFlags |= RTHEAPSIMPLEBLOCK_FLAGS_FREE;
691 pFree->pPrev = NULL;
692 pFree->pNext = pRight;
693 if (pRight)
694 pRight->pPrev = pFree;
695 else
696 pHeapInt->pFreeTail = pFree;
697 pHeapInt->pFreeHead = pFree;
698 }
699 else
700 {
701 /*
702 * Can we merge with left hand free block?
703 */
704 if (pLeft->Core.pNext == &pFree->Core)
705 {
706 pLeft->Core.pNext = pFree->Core.pNext;
707 if (pFree->Core.pNext)
708 pFree->Core.pNext->pPrev = &pLeft->Core;
709 pHeapInt->cbFree -= pLeft->cb;
710 pFree = pLeft;
711 }
712 /*
713 * No, just link it into the free list then.
714 */
715 else
716 {
717 pFree->Core.fFlags |= RTHEAPSIMPLEBLOCK_FLAGS_FREE;
718 pFree->pNext = pRight;
719 pFree->pPrev = pLeft;
720 pLeft->pNext = pFree;
721 if (pRight)
722 pRight->pPrev = pFree;
723 else
724 pHeapInt->pFreeTail = pFree;
725 }
726 }
727
728 /*
729 * Can we merge with right hand free block?
730 */
731 if ( pRight
732 && pRight->Core.pPrev == &pFree->Core)
733 {
734 /* core */
735 pFree->Core.pNext = pRight->Core.pNext;
736 if (pRight->Core.pNext)
737 pRight->Core.pNext->pPrev = &pFree->Core;
738
739 /* free */
740 pFree->pNext = pRight->pNext;
741 if (pRight->pNext)
742 pRight->pNext->pPrev = pFree;
743 else
744 pHeapInt->pFreeTail = pFree;
745 pHeapInt->cbFree -= pRight->cb;
746 }
747
748 /*
749 * Calculate the size and update free stats.
750 */
751 pFree->cb = (pFree->Core.pNext ? (uintptr_t)pFree->Core.pNext : (uintptr_t)pHeapInt->pvEnd)
752 - (uintptr_t)pFree - sizeof(RTHEAPSIMPLEBLOCK);
753 pHeapInt->cbFree += pFree->cb;
754 ASSERT_BLOCK_FREE(pHeapInt, pFree);
755
756#ifdef RTHEAPSIMPLE_STRICT
757 rtHeapSimpleAssertAll(pHeapInt);
758#endif
759}
760
761
762#ifdef RTHEAPSIMPLE_STRICT
763/**
764 * Internal consitency check (relying on assertions).
765 * @param pHeapInt
766 */
767static void rtHeapSimpleAssertAll(PRTHEAPSIMPLEINTERNAL pHeapInt)
768{
769 PRTHEAPSIMPLEFREE pPrev = NULL;
770 PRTHEAPSIMPLEFREE pPrevFree = NULL;
771 PRTHEAPSIMPLEFREE pBlock;
772 for (pBlock = (PRTHEAPSIMPLEFREE)(pHeapInt + 1);
773 pBlock;
774 pBlock = (PRTHEAPSIMPLEFREE)pBlock->Core.pNext)
775 {
776 if (RTHEAPSIMPLEBLOCK_IS_FREE(&pBlock->Core))
777 {
778 ASSERT_BLOCK_FREE(pHeapInt, pBlock);
779 Assert(pBlock->pPrev == pPrevFree);
780 Assert(pPrevFree || pHeapInt->pFreeHead == pBlock);
781 pPrevFree = pBlock;
782 }
783 else
784 ASSERT_BLOCK_USED(pHeapInt, &pBlock->Core);
785 Assert(!pPrev || pPrev == (PRTHEAPSIMPLEFREE)pBlock->Core.pPrev);
786 pPrev = pBlock;
787 }
788 Assert(pHeapInt->pFreeTail == pPrevFree);
789}
790#endif
791
792
793/**
794 * Gets the size of the specified heap block.
795 *
796 * @returns The actual size of the heap block.
797 * @returns 0 if \a pv is NULL or it doesn't point to a valid heap block. An invalid \a pv
798 * can also cause traps or trigger assertions.
799 * @param Heap The heap. This is optional and will only be used for strict assertions.
800 * @param pv The heap block returned by RTHeapSimple
801 */
802RTDECL(size_t) RTHeapSimpleSize(RTHEAPSIMPLE Heap, void *pv)
803{
804 /*
805 * Validate input.
806 */
807 if (!pv)
808 return 0;
809 AssertPtrReturn(pv, 0);
810 AssertReturn(RT_ALIGN_P(pv, RTHEAPSIMPLE_ALIGNMENT) == pv, 0);
811
812 /*
813 * Get the block and heap. If in strict mode, validate these.
814 */
815 PRTHEAPSIMPLEBLOCK pBlock = (PRTHEAPSIMPLEBLOCK)pv - 1;
816 PRTHEAPSIMPLEINTERNAL pHeapInt = pBlock->pHeap;
817 ASSERT_BLOCK_USED(pHeapInt, pBlock);
818 ASSERT_ANCHOR(pHeapInt);
819 Assert(pHeapInt == (PRTHEAPSIMPLEINTERNAL)Heap || !Heap);
820
821 /*
822 * Calculate the block size.
823 */
824 const size_t cbBlock = (pBlock->pNext ? (uintptr_t)pBlock->pNext : (uintptr_t)pHeapInt->pvEnd)
825 - (uintptr_t)pBlock- sizeof(RTHEAPSIMPLEBLOCK);
826 return cbBlock;
827}
828
829
830/**
831 * Gets the size of the heap.
832 *
833 * This size includes all the internal heap structures. So, even if the heap is
834 * empty the RTHeapSimpleGetFreeSize() will never reach the heap size returned
835 * by this function.
836 *
837 * @returns The heap size.
838 * @returns 0 if heap was safely detected as being bad.
839 * @param Heap The heap.
840 */
841RTDECL(size_t) RTHeapSimpleGetHeapSize(RTHEAPSIMPLE Heap)
842{
843 if (Heap == NIL_RTHEAPSIMPLE)
844 return 0;
845 PRTHEAPSIMPLEINTERNAL pHeapInt = Heap;
846 AssertPtrReturn(pHeapInt, 0);
847 ASSERT_ANCHOR(pHeapInt);
848 return pHeapInt->cbHeap;
849}
850
851
852/**
853 * Returns the sum of all free heap blocks.
854 *
855 * This is the amount of memory you can theoretically allocate
856 * if you do allocations exactly matching the free blocks.
857 *
858 * @returns The size of the free blocks.
859 * @returns 0 if heap was safely detected as being bad.
860 * @param Heap The heap.
861 */
862RTDECL(size_t) RTHeapSimpleGetFreeSize(RTHEAPSIMPLE Heap)
863{
864 if (Heap == NIL_RTHEAPSIMPLE)
865 return 0;
866 PRTHEAPSIMPLEINTERNAL pHeapInt = Heap;
867 AssertPtrReturn(pHeapInt, 0);
868 ASSERT_ANCHOR(pHeapInt);
869 return pHeapInt->cbFree;
870}
871
872
873/**
874 * Dumps the hypervisor heap.
875 *
876 * @param Heap The heap handle.
877 * @param pfnPrintf Printf like function that groks IPRT formatting.
878 */
879RTDECL(void) RTHeapSimpleDump(RTHEAPSIMPLE Heap, PFNRTHEAPSIMPLEPRINTF pfnPrintf)
880{
881 PRTHEAPSIMPLEINTERNAL pHeapInt = (PRTHEAPSIMPLEINTERNAL)Heap;
882 pfnPrintf("**** Dumping Heap %p - cbHeap=%zx cbFree=%zx ****\n",
883 Heap, pHeapInt->cbHeap, pHeapInt->cbFree);
884
885 PRTHEAPSIMPLEFREE pBlock;
886 for (pBlock = (PRTHEAPSIMPLEFREE)(pHeapInt + 1);
887 pBlock;
888 pBlock = (PRTHEAPSIMPLEFREE)pBlock->Core.pNext)
889 {
890 size_t cb = (pBlock->pNext ? (uintptr_t)pBlock->Core.pNext : (uintptr_t)pHeapInt->pvEnd)
891 - (uintptr_t)pBlock - sizeof(RTHEAPSIMPLEBLOCK);
892 if (RTHEAPSIMPLEBLOCK_IS_FREE(&pBlock->Core))
893 pfnPrintf("%p %06x FREE pNext=%p pPrev=%p fFlags=%#x cb=%#06x : cb=%#06x pNext=%p pPrev=%p\n",
894 pBlock, (uintptr_t)pBlock - (uintptr_t)(pHeapInt + 1), pBlock->Core.pNext, pBlock->Core.pPrev, pBlock->Core.fFlags, cb,
895 pBlock->cb, pBlock->pNext, pBlock->pPrev);
896 else
897 pfnPrintf("%p %06x USED pNext=%p pPrev=%p fFlags=%#x cb=%#06x\n",
898 pBlock, (uintptr_t)pBlock - (uintptr_t)(pHeapInt + 1), pBlock->Core.pNext, pBlock->Core.pPrev, pBlock->Core.fFlags, cb);
899 }
900 pfnPrintf("**** Done dumping Heap %p ****\n", Heap);
901}
902
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette