VirtualBox

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

Last change on this file since 19014 was 18603, checked in by vboxsync, 16 years ago

heapsimple.cpp: Just convert to C style, plese, do NOT move comments and code around.

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