heapoffset.cpp revision 29e82f9045a3d4eb6c3547e48725b671fadaf2ca
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/* $Id$ */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** @file
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * IPRT - An Offset Based Heap.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*
3f1e0eea71cabeb90529e546f16eb7aee513fde9vboxsync * Copyright (C) 2006-2009 Sun Microsystems, Inc.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The contents of this file may alternatively be used under the terms
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of the Common Development and Distribution License Version 1.0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VirtualBox OSE distribution, in which case the provisions of the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * CDDL are applicable instead of those of the GPL.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * You may elect to license modified versions of this file under the
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * terms and conditions of either the GPL or the CDDL or both.
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync *
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * additional information or have any questions.
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync */
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync/*******************************************************************************
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync* Header Files *
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define LOG_GROUP RTLOGGROUP_DEFAULT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/heap.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include "internal/iprt.h"
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/assert.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/asm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/string.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/err.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/log.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/param.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include "internal/magics.h"
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Structures and Typedefs *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to the heap anchor block. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct RTHEAPOFFSETINTERNAL *PRTHEAPOFFSETINTERNAL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a heap block. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct RTHEAPOFFSETBLOCK *PRTHEAPOFFSETBLOCK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a free heap block. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct RTHEAPOFFSETFREE *PRTHEAPOFFSETFREE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Structure describing a block in an offset based heap.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If this block is allocated, it is followed by the user data.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If this block is free, see RTHEAPOFFSETFREE.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct RTHEAPOFFSETBLOCK
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The next block in the global block list. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t /*PRTHEAPOFFSETBLOCK*/ offNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The previous block in the global block list. */
cfb3a8ae5e9668de4506cf5c053b8009bcc89dafvboxsync uint32_t /*PRTHEAPOFFSETBLOCK*/ offPrev;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Offset into the heap of this block. Used to locate the anchor block. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t /*PRTHEAPOFFSETINTERNAL*/ offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Flags + magic. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t fFlags;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync} RTHEAPOFFSETBLOCK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncAssertCompileSize(RTHEAPOFFSETBLOCK, 16);
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** The block is free if this flag is set. When cleared it's allocated. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define RTHEAPOFFSETBLOCK_FLAGS_FREE (RT_BIT_32(0))
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync/** The magic value. */
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync#define RTHEAPOFFSETBLOCK_FLAGS_MAGIC (UINT32_C(0xabcdef00))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** The mask that needs to be applied to RTHEAPOFFSETBLOCK::fFlags to obtain the magic value. */
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync#define RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK (~RT_BIT_32(0))
3242fe628b2306c050fb28c489d50bc63118f0c5vboxsync
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync/**
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * Checks if the specified block is valid or not.
3242fe628b2306c050fb28c489d50bc63118f0c5vboxsync * @returns boolean answer.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync * @param pBlock Pointer to a RTHEAPOFFSETBLOCK structure.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync */
3242fe628b2306c050fb28c489d50bc63118f0c5vboxsync#define RTHEAPOFFSETBLOCK_IS_VALID(pBlock) \
3242fe628b2306c050fb28c489d50bc63118f0c5vboxsync ( ((pBlock)->fFlags & RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK) == RTHEAPOFFSETBLOCK_FLAGS_MAGIC )
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Checks if the specified block is valid and in use.
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * @returns boolean answer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pBlock Pointer to a RTHEAPOFFSETBLOCK structure.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define RTHEAPOFFSETBLOCK_IS_VALID_USED(pBlock) \
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync ( ((pBlock)->fFlags & (RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK | RTHEAPOFFSETBLOCK_FLAGS_FREE)) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync == RTHEAPOFFSETBLOCK_FLAGS_MAGIC )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync/**
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync * Checks if the specified block is valid and free.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync * @returns boolean answer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pBlock Pointer to a RTHEAPOFFSETBLOCK structure.
3242fe628b2306c050fb28c489d50bc63118f0c5vboxsync */
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync#define RTHEAPOFFSETBLOCK_IS_VALID_FREE(pBlock) \
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync ( ((pBlock)->fFlags & (RTHEAPOFFSETBLOCK_FLAGS_MAGIC_MASK | RTHEAPOFFSETBLOCK_FLAGS_FREE)) \
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync == (RTHEAPOFFSETBLOCK_FLAGS_MAGIC | RTHEAPOFFSETBLOCK_FLAGS_FREE) )
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync/**
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync * Checks if the specified block is free or not.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync * @returns boolean answer.
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync * @param pBlock Pointer to a valid RTHEAPOFFSETBLOCK structure.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync */
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync#define RTHEAPOFFSETBLOCK_IS_FREE(pBlock) (!!((pBlock)->fFlags & RTHEAPOFFSETBLOCK_FLAGS_FREE))
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync/**
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync * A free heap block.
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync * This is an extended version of RTHEAPOFFSETBLOCK that takes the unused
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync * user data to store free list pointers and a cached size value.
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync */
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsynctypedef struct RTHEAPOFFSETFREE
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync{
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync /** Core stuff. */
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync RTHEAPOFFSETBLOCK Core;
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync /** Pointer to the next free block. */
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync uint32_t /*PRTHEAPOFFSETFREE*/ offNext;
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync /** Pointer to the previous free block. */
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync uint32_t /*PRTHEAPOFFSETFREE*/ offPrev;
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync /** The size of the block (excluding the RTHEAPOFFSETBLOCK part). */
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync uint32_t cb;
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync /** An alignment filler to make it a multiple of 16 bytes. */
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync uint32_t Alignment;
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync} RTHEAPOFFSETFREE;
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsyncAssertCompileSize(RTHEAPOFFSETFREE, 16+16);
1db6afc370c2fa84144478dffa9c1ed3c28c7158vboxsync
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The heap anchor block.
3242fe628b2306c050fb28c489d50bc63118f0c5vboxsync * This structure is placed at the head of the memory block specified to RTHeapOffsetInit(),
3242fe628b2306c050fb28c489d50bc63118f0c5vboxsync * which means that the first RTHEAPOFFSETBLOCK appears immediately after this structure.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct RTHEAPOFFSETINTERNAL
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync /** The typical magic (RTHEAPOFFSET_MAGIC). */
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync uint32_t u32Magic;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The heap size. (This structure is included!) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t cbHeap;
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync /** The amount of free memory in the heap. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t cbFree;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Free head pointer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t /*PRTHEAPOFFSETFREE*/ offFreeHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Free tail pointer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t /*PRTHEAPOFFSETFREE*/ offFreeTail;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync /** Make the size of this structure 32 bytes. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t au32Alignment[3];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync} RTHEAPOFFSETINTERNAL;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsyncAssertCompileSize(RTHEAPOFFSETINTERNAL, 32);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync/** The minimum allocation size. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define RTHEAPOFFSET_MIN_BLOCK (sizeof(RTHEAPOFFSETBLOCK))
23de3d76e5d27015e334e6ff763ab08de5969363vboxsyncAssertCompile(RTHEAPOFFSET_MIN_BLOCK >= sizeof(RTHEAPOFFSETBLOCK));
323b78bf4831666c95416edf3b6e54657a769e5dvboxsyncAssertCompile(RTHEAPOFFSET_MIN_BLOCK >= sizeof(RTHEAPOFFSETFREE) - sizeof(RTHEAPOFFSETBLOCK));
23de3d76e5d27015e334e6ff763ab08de5969363vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** The minimum and default alignment. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define RTHEAPOFFSET_ALIGNMENT (sizeof(RTHEAPOFFSETBLOCK))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Defined Constants And Macros *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RT_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# define RTHEAPOFFSET_STRICT 1
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Converts RTHEAPOFFSETBLOCK::offSelf into a heap anchor block pointer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Pointer of given type.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pBlock The block to find the heap anchor block for.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define RTHEAPOFF_GET_ANCHOR(pBlock) ( (PRTHEAPOFFSETINTERNAL)((uint8_t *)(pBlock) - (pBlock)->offSelf ) )
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Converts an offset to a pointer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * All offsets are relative to the heap to make life simple.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Pointer of given type.
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * @param pHeapInt Pointer to the heap anchor block.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param off The offset to convert.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param type The desired type.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# define RTHEAPOFF_TO_PTR(pHeapInt, off, type) ( (type)rtHeapOffCheckedOffToPtr(pHeapInt, off) )
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync#else
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync# define RTHEAPOFF_TO_PTR(pHeapInt, off, type) ( (type)((off) ? (uint8_t *)(pHeapInt) + (off) : NULL) )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Converts a pointer to an offset.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * All offsets are relative to the heap to make life simple.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Offset into the heap.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pHeapInt Pointer to the heap anchor block.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param ptr The pointer to convert.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# define RTHEAPOFF_TO_OFF(pHeapInt, ptr) rtHeapOffCheckedPtrToOff(pHeapInt, ptr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync# define RTHEAPOFF_TO_OFF(pHeapInt, ptr) ( (uint32_t)((ptr) ? (uintptr_t)(ptr) - (uintptr_t)(pHeapInt) : UINT32_C(0)) )
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_L(a, b) AssertMsg((a) < (b), ("a=%08x b=%08x\n", (a), (b)))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_LE(a, b) AssertMsg((a) <= (b), ("a=%08x b=%08x\n", (a), (b)))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_G(a, b) AssertMsg((a) > (b), ("a=%08x b=%08x\n", (a), (b)))
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync#define ASSERT_GE(a, b) AssertMsg((a) >= (b), ("a=%08x b=%08x\n", (a), (b)))
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync#define ASSERT_ALIGN(a) AssertMsg(!((uintptr_t)(a) & (RTHEAPOFFSET_ALIGNMENT - 1)), ("a=%p\n", (uintptr_t)(a)))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_PREV(pHeapInt, pBlock) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync do { ASSERT_ALIGN((pBlock)->offPrev); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ((pBlock)->offPrev) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_L((pBlock)->offPrev, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync ASSERT_GE((pBlock)->offPrev, sizeof(RTHEAPOFFSETINTERNAL)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert((pBlock) == (PRTHEAPOFFSETBLOCK)((pHeapInt) + 1)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (0)
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_NEXT(pHeap, pBlock) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync do { ASSERT_ALIGN((pBlock)->offNext); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ((pBlock)->offNext) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_L((pBlock)->offNext, (pHeapInt)->cbHeap); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_G((pBlock)->offNext, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync#define ASSERT_BLOCK(pHeapInt, pBlock) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync do { AssertMsg(RTHEAPOFFSETBLOCK_IS_VALID(pBlock), ("%#x\n", (pBlock)->fFlags)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RTHEAPOFF_GET_ANCHOR(pBlock) == (pHeapInt), ("%p != %p\n", RTHEAPOFF_GET_ANCHOR(pBlock), (pHeapInt))); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_GE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), sizeof(RTHEAPOFFSETINTERNAL)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_L( RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->cbHeap); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_NEXT(pHeapInt, pBlock); \
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync ASSERT_PREV(pHeapInt, pBlock); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (0)
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_BLOCK_USED(pHeapInt, pBlock) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync do { AssertMsg(RTHEAPOFFSETBLOCK_IS_VALID_USED((pBlock)), ("%#x\n", (pBlock)->fFlags)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RTHEAPOFF_GET_ANCHOR(pBlock) == (pHeapInt), ("%p != %p\n", RTHEAPOFF_GET_ANCHOR(pBlock), (pHeapInt))); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_GE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), sizeof(RTHEAPOFFSETINTERNAL)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_L( RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->cbHeap); \
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync ASSERT_NEXT(pHeapInt, pBlock); \
be9bc9b4ba510c4b4159c193f783d024633ef8e9vboxsync ASSERT_PREV(pHeapInt, pBlock); \
be9bc9b4ba510c4b4159c193f783d024633ef8e9vboxsync } while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_FREE_PREV(pHeapInt, pBlock) \
be9bc9b4ba510c4b4159c193f783d024633ef8e9vboxsync do { ASSERT_ALIGN((pBlock)->offPrev); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ((pBlock)->offPrev) \
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync { \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_GE((pBlock)->offPrev, (pHeapInt)->offFreeHead); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_L((pBlock)->offPrev, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_LE((pBlock)->offPrev, (pBlock)->Core.offPrev); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } \
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync else \
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync Assert((pBlock) == RTHEAPOFF_TO_PTR(pHeapInt, (pHeapInt)->offFreeHead, PRTHEAPOFFSETFREE) ); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (0)
090f6abdd6282f48527b83162b8b441425f05e36vboxsync
090f6abdd6282f48527b83162b8b441425f05e36vboxsync#define ASSERT_FREE_NEXT(pHeapInt, pBlock) \
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync do { ASSERT_ALIGN((pBlock)->offNext); \
698f914c9d8da3932ce1e1f8f170e19bd151560evboxsync if ((pBlock)->offNext) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { \
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync ASSERT_LE((pBlock)->offNext, (pHeapInt)->offFreeTail); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_G((pBlock)->offNext, RTHEAPOFF_TO_OFF(pHeapInt, pBlock)); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_GE((pBlock)->offNext, (pBlock)->Core.offNext); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } \
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync else \
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync Assert((pBlock) == RTHEAPOFF_TO_PTR(pHeapInt, (pHeapInt)->offFreeTail, PRTHEAPOFFSETFREE)); \
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync } while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
090f6abdd6282f48527b83162b8b441425f05e36vboxsync#ifdef RTHEAPOFFSET_STRICT
090f6abdd6282f48527b83162b8b441425f05e36vboxsync# define ASSERT_FREE_CB(pHeapInt, pBlock) \
090f6abdd6282f48527b83162b8b441425f05e36vboxsync do { size_t cbCalc = ((pBlock)->Core.offNext ? (pBlock)->Core.offNext : (pHeapInt)->cbHeap) \
090f6abdd6282f48527b83162b8b441425f05e36vboxsync - RTHEAPOFF_TO_OFF((pHeapInt), (pBlock)) - sizeof(RTHEAPOFFSETBLOCK); \
118e1c3f853f78b4aec64afdcb8379981f41314fvboxsync AssertMsg((pBlock)->cb == cbCalc, ("cb=%#zx cbCalc=%#zx\n", (pBlock)->cb, cbCalc)); \
118e1c3f853f78b4aec64afdcb8379981f41314fvboxsync } while (0)
118e1c3f853f78b4aec64afdcb8379981f41314fvboxsync#else
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync# define ASSERT_FREE_CB(pHeapInt, pBlock) do {} while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
090f6abdd6282f48527b83162b8b441425f05e36vboxsync
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync/** Asserts that a free block is valid. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_BLOCK_FREE(pHeapInt, pBlock) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync do { ASSERT_BLOCK(pHeapInt, &(pBlock)->Core); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(RTHEAPOFFSETBLOCK_IS_VALID_FREE(&(pBlock)->Core)); \
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync ASSERT_GE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->offFreeHead); \
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync ASSERT_LE(RTHEAPOFF_TO_OFF(pHeapInt, pBlock), (pHeapInt)->offFreeTail); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_FREE_NEXT(pHeapInt, pBlock); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_FREE_PREV(pHeapInt, pBlock); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_FREE_CB(pHeapInt, pBlock); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Asserts that the heap anchor block is ok. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define ASSERT_ANCHOR(pHeapInt) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync do { AssertPtr(pHeapInt);\
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert((pHeapInt)->u32Magic == RTHEAPOFFSET_MAGIC); \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (0)
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Internal Functions *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTHEAPOFFSET_STRICT
323b78bf4831666c95416edf3b6e54657a769e5dvboxsyncstatic void rtHeapOffsetAssertAll(PRTHEAPOFFSETINTERNAL pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
3f1e0eea71cabeb90529e546f16eb7aee513fde9vboxsyncstatic PRTHEAPOFFSETBLOCK rtHeapOffsetAllocBlock(PRTHEAPOFFSETINTERNAL pHeapInt, size_t cb, size_t uAlignment);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void rtHeapOffsetFreeBlock(PRTHEAPOFFSETINTERNAL pHeapInt, PRTHEAPOFFSETBLOCK pBlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Checked version of RTHEAPOFF_TO_PTR. */
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsyncDECLINLINE(void *) rtHeapOffCheckedOffToPtr(PRTHEAPOFFSETINTERNAL pHeapInt, uint32_t off)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
0b65654be767b9fb7677181ddb434d8467f608e3vboxsync if (!off)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(off < pHeapInt->cbHeap, ("%#x %#x\n", off, pHeapInt->cbHeap));
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync AssertMsg(off >= sizeof(*pHeapInt), ("%#x %#x\n", off, sizeof(*pHeapInt)));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return (uint8_t *)pHeapInt + off;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Checked version of RTHEAPOFF_TO_OFF. */
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsyncDECLINLINE(uint32_t) rtHeapOffCheckedPtrToOff(PRTHEAPOFFSETINTERNAL pHeapInt, void *pv)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync{
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync if (!pv)
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync return 0;
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync uintptr_t off = (uintptr_t)pv - (uintptr_t)pHeapInt;
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync AssertMsg(off < pHeapInt->cbHeap, ("%#x %#x\n", off, pHeapInt->cbHeap));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(off >= sizeof(*pHeapInt), ("%#x %#x\n", off, sizeof(*pHeapInt)));
f5395a2af3050ddd694b0ad505975f7b717ab4f1vboxsync return (uint32_t)off;
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsync}
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif /* RTHEAPOFFSET_STRICT */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(int) RTHeapOffsetInit(PRTHEAPOFFSET phHeap, void *pvMemory, size_t cbMemory)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETINTERNAL pHeapInt;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETFREE pFree;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync unsigned i;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /*
332ccb6ac6feb4b50ec24d63ff029119164182ffvboxsync * Validate input. The imposed minimum heap size is just a convenient value.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertReturn(cbMemory >= PAGE_SIZE, VERR_INVALID_PARAMETER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pvMemory, VERR_INVALID_POINTER);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync AssertReturn((uintptr_t)pvMemory + (cbMemory - 1) > (uintptr_t)cbMemory, VERR_INVALID_PARAMETER);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Place the heap anchor block at the start of the heap memory,
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * enforce 32 byte alignment of it. Also align the heap size correctly.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt = (PRTHEAPOFFSETINTERNAL)pvMemory;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ((uintptr_t)pvMemory & 31)
3f1e0eea71cabeb90529e546f16eb7aee513fde9vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync const uintptr_t off = 32 - ((uintptr_t)pvMemory & 31);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbMemory -= off;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt = (PRTHEAPOFFSETINTERNAL)((uintptr_t)pvMemory + off);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbMemory &= ~(RTHEAPOFFSET_ALIGNMENT - 1);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Init the heap anchor block. */
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync pHeapInt->u32Magic = RTHEAPOFFSET_MAGIC;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->cbHeap = cbMemory;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->cbFree = cbMemory
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync - sizeof(RTHEAPOFFSETBLOCK)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync - sizeof(RTHEAPOFFSETINTERNAL);
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync pHeapInt->offFreeTail = pHeapInt->offFreeHead = sizeof(*pHeapInt);
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync for (i = 0; i < RT_ELEMENTS(pHeapInt->au32Alignment); i++)
a64bf60e92e5cb8a76aa6c8e92193932d88a906fvboxsync pHeapInt->au32Alignment[i] = UINT32_MAX;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Init the single free block. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree = RTHEAPOFF_TO_PTR(pHeapInt, pHeapInt->offFreeHead, PRTHEAPOFFSETFREE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.offNext = 0;
d45f7f7fe0c28b500b45b2dc88d7a04f4c0be6b8vboxsync pFree->Core.offPrev = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.offSelf = pHeapInt->offFreeHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.fFlags = RTHEAPOFFSETBLOCK_FLAGS_MAGIC | RTHEAPOFFSETBLOCK_FLAGS_FREE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->offNext = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->offPrev = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->cb = pHeapInt->cbFree;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync *phHeap = pHeapInt;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtHeapOffsetAssertAll(pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetInit);
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(void *) RTHeapOffsetAlloc(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment)
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETINTERNAL pHeapInt = hHeap;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETBLOCK pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate and adjust the input.
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync */
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync AssertPtrReturn(pHeapInt, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cb < RTHEAPOFFSET_MIN_BLOCK)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cb = RTHEAPOFFSET_MIN_BLOCK;
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cb = RT_ALIGN_Z(cb, RTHEAPOFFSET_ALIGNMENT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!cbAlignment)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbAlignment = RTHEAPOFFSET_ALIGNMENT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!(cbAlignment & (cbAlignment - 1)));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cbAlignment < RTHEAPOFFSET_ALIGNMENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbAlignment = RTHEAPOFFSET_ALIGNMENT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Do the allocation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBlock = rtHeapOffsetAllocBlock(pHeapInt, cb, cbAlignment);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync if (RT_LIKELY(pBlock))
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync void *pv = pBlock + 1;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync return pv;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetAlloc);
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync
a64bf60e92e5cb8a76aa6c8e92193932d88a906fvboxsync
a64bf60e92e5cb8a76aa6c8e92193932d88a906fvboxsyncRTDECL(void *) RTHeapOffsetAllocZ(RTHEAPOFFSET hHeap, size_t cb, size_t cbAlignment)
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync{
04a471b98d492ee51b1f40424c7f90ddf44a90f0vboxsync PRTHEAPOFFSETINTERNAL pHeapInt = hHeap;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETBLOCK pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate and adjust the input.
bee1a7d4b183cab9654f247b3ea8cf680842bed5vboxsync */
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync AssertPtrReturn(pHeapInt, NULL);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync if (cb < RTHEAPOFFSET_MIN_BLOCK)
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync cb = RTHEAPOFFSET_MIN_BLOCK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
96dce0123cc032388e78766d08f9ee5a66b80facvboxsync cb = RT_ALIGN_Z(cb, RTHEAPOFFSET_ALIGNMENT);
96dce0123cc032388e78766d08f9ee5a66b80facvboxsync if (!cbAlignment)
96dce0123cc032388e78766d08f9ee5a66b80facvboxsync cbAlignment = RTHEAPOFFSET_ALIGNMENT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!(cbAlignment & (cbAlignment - 1)));
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync Assert((cbAlignment & ~(cbAlignment - 1)) == cbAlignment);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync if (cbAlignment < RTHEAPOFFSET_ALIGNMENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbAlignment = RTHEAPOFFSET_ALIGNMENT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Do the allocation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync pBlock = rtHeapOffsetAllocBlock(pHeapInt, cb, cbAlignment);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_LIKELY(pBlock))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync void *pv = pBlock + 1;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memset(pv, 0, cb);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pv;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetAllocZ);
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Allocates a block of memory from the specified heap.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * No parameter validation or adjustment is performed.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Pointer to the allocated block.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns NULL on failure.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d45f7f7fe0c28b500b45b2dc88d7a04f4c0be6b8vboxsync * @param pHeapInt The heap.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cb Size of the memory block to allocate.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param uAlignment The alignment specifications for the allocated block.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PRTHEAPOFFSETBLOCK rtHeapOffsetAllocBlock(PRTHEAPOFFSETINTERNAL pHeapInt, size_t cb, size_t uAlignment)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETBLOCK pRet = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETFREE pFree;
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertReturn((pHeapInt)->u32Magic == RTHEAPOFFSET_MAGIC, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtHeapOffsetAssertAll(pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Search for a fitting block from the lower end of the heap.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync for (pFree = RTHEAPOFF_TO_PTR(pHeapInt, pHeapInt->offFreeHead, PRTHEAPOFFSETFREE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree = RTHEAPOFF_TO_PTR(pHeapInt, pFree->offNext, PRTHEAPOFFSETFREE))
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uintptr_t offAlign;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_FREE(pHeapInt, pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Match for size and alignment.
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync */
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync if (pFree->cb < cb)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync continue;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync offAlign = (uintptr_t)(&pFree->Core + 1) & (uAlignment - 1);
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync if (offAlign)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHEAPOFFSETFREE Free;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETBLOCK pPrev;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync offAlign = uAlignment - offAlign;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pFree->cb - offAlign < cb)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync continue;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Make a stack copy of the free block header and adjust the pointer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync Free = *pFree;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync pFree = (PRTHEAPOFFSETFREE)((uintptr_t)pFree + offAlign);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * Donate offAlign bytes to the node in front of us.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If we're the head node, we'll have to create a fake node. We'll
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * mark it USED for simplicity.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * (Should this policy of donating memory to the guy in front of us
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * cause big 'leaks', we could create a new free node if there is room
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * for that.)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev = RTHEAPOFF_TO_PTR(pHeapInt, Free.Core.offPrev, PRTHEAPOFFSETBLOCK);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPrev)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(!RTHEAPOFFSETBLOCK_IS_FREE(pPrev), ("Impossible!\n"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
ebe05ec36d1fcd24d62e7066dedcb4eb2e691358vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev = (PRTHEAPOFFSETBLOCK)(pHeapInt + 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPrev == &pFree->Core);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev->offPrev = 0;
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync pPrev->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev->offSelf = RTHEAPOFF_TO_OFF(pHeapInt, pPrev);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev->fFlags = RTHEAPOFFSETBLOCK_FLAGS_MAGIC;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->cbFree -= offAlign;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Recreate pFree in the new position and adjust the neighbors.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *pFree = Free;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.offSelf = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* the core */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pFree->Core.offNext)
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = pFree->Core.offSelf;
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync pFree->Core.offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pPrev);
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync /* the free part */
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync pFree->cb -= offAlign;
0ebb1ef53864eb9cc97580f722288c9b29bc5d03vboxsync if (pFree->offNext)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pFree->offNext, PRTHEAPOFFSETFREE)->offPrev = pFree->Core.offSelf;
f5395a2af3050ddd694b0ad505975f7b717ab4f1vboxsync else
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsync pHeapInt->offFreeTail = pFree->Core.offSelf;
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsync if (pFree->offPrev)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pFree->offPrev, PRTHEAPOFFSETFREE)->offNext = pFree->Core.offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->offFreeHead = pFree->Core.offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_FREE(pHeapInt, pFree);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync ASSERT_BLOCK_USED(pHeapInt, pPrev);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Split off a new FREE block?
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync */
332ccb6ac6feb4b50ec24d63ff029119164182ffvboxsync if (pFree->cb >= cb + RT_ALIGN_Z(sizeof(RTHEAPOFFSETFREE), RTHEAPOFFSET_ALIGNMENT))
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Move the FREE block up to make room for the new USED block.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync */
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync PRTHEAPOFFSETFREE pNew = (PRTHEAPOFFSETFREE)((uintptr_t)&pFree->Core + cb + sizeof(RTHEAPOFFSETBLOCK));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pNew->Core.offSelf = RTHEAPOFF_TO_OFF(pHeapInt, pNew);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pNew->Core.offNext = pFree->Core.offNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pFree->Core.offNext)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = pNew->Core.offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pNew->Core.offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync pNew->Core.fFlags = RTHEAPOFFSETBLOCK_FLAGS_MAGIC | RTHEAPOFFSETBLOCK_FLAGS_FREE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pNew->offNext = pFree->offNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pNew->offNext)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pNew->offNext, PRTHEAPOFFSETFREE)->offPrev = pNew->Core.offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->offFreeTail = pNew->Core.offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pNew->offPrev = pFree->offPrev;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pNew->offPrev)
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pNew->offPrev, PRTHEAPOFFSETFREE)->offNext = pNew->Core.offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->offFreeHead = pNew->Core.offSelf;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pNew->cb = (pNew->Core.offNext ? pNew->Core.offNext : pHeapInt->cbHeap) \
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync - pNew->Core.offSelf - sizeof(RTHEAPOFFSETBLOCK);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_FREE(pHeapInt, pNew);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Update the old FREE node making it a USED node.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.fFlags &= ~RTHEAPOFFSETBLOCK_FLAGS_FREE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.offNext = pNew->Core.offSelf;
0b18f6591d3f4784e090c22452248f1118b0b6aavboxsync pHeapInt->cbFree -= pFree->cb;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->cbFree += pNew->cb;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pRet = &pFree->Core;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_USED(pHeapInt, pRet);
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Link it out of the free list.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pFree->offNext)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pFree->offNext, PRTHEAPOFFSETFREE)->offPrev = pFree->offPrev;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->offFreeTail = pFree->offPrev;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pFree->offPrev)
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pFree->offPrev, PRTHEAPOFFSETFREE)->offNext = pFree->offNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->offFreeHead = pFree->offNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * Convert it to a used block.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->cbFree -= pFree->cb;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.fFlags &= ~RTHEAPOFFSETBLOCK_FLAGS_FREE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pRet = &pFree->Core;
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync ASSERT_BLOCK_USED(pHeapInt, pRet);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtHeapOffsetAssertAll(pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pRet;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(void) RTHeapOffsetFree(RTHEAPOFFSET hHeap, void *pv)
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETINTERNAL pHeapInt;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETBLOCK pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pv)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtr(pv);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(RT_ALIGN_P(pv, RTHEAPOFFSET_ALIGNMENT) == pv);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Get the block and heap. If in strict mode, validate these.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync pBlock = (PRTHEAPOFFSETBLOCK)pv - 1;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt = RTHEAPOFF_GET_ANCHOR(pBlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_USED(pHeapInt, pBlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_ANCHOR(pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pHeapInt == (PRTHEAPOFFSETINTERNAL)hHeap || !hHeap);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync#ifdef RTHEAPOFFSET_FREE_POISON
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * Poison the block.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync const size_t cbBlock = (pBlock->pNext ? (uintptr_t)pBlock->pNext : (uintptr_t)pHeapInt->pvEnd)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync - (uintptr_t)pBlock - sizeof(RTHEAPOFFSETBLOCK);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memset(pBlock + 1, RTHEAPOFFSET_FREE_POISON, cbBlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Call worker which does the actual job.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtHeapOffsetFreeBlock(pHeapInt, pBlock);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync}
1df4b0cdc5ec23d817014f9347ef28222b51e3fbvboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetFree);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Free a memory block.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
1df4b0cdc5ec23d817014f9347ef28222b51e3fbvboxsync * @param pHeapInt The heap.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pBlock The memory block to free.
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void rtHeapOffsetFreeBlock(PRTHEAPOFFSETINTERNAL pHeapInt, PRTHEAPOFFSETBLOCK pBlock)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETFREE pFree = (PRTHEAPOFFSETFREE)pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETFREE pLeft;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETFREE pRight;
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtHeapOffsetAssertAll(pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Look for the closest free list blocks by walking the blocks right
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of us (both lists are sorted by address).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pLeft = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pRight = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pHeapInt->offFreeTail)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pRight = RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETFREE);
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync while (pRight && !RTHEAPOFFSETBLOCK_IS_FREE(&pRight->Core))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK(pHeapInt, &pRight->Core);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pRight = RTHEAPOFF_TO_PTR(pHeapInt, pRight->Core.offNext, PRTHEAPOFFSETFREE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pRight)
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync pLeft = RTHEAPOFF_TO_PTR(pHeapInt, pHeapInt->offFreeTail, PRTHEAPOFFSETFREE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_FREE(pHeapInt, pRight);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pLeft = RTHEAPOFF_TO_PTR(pHeapInt, pRight->offPrev, PRTHEAPOFFSETFREE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pLeft)
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync ASSERT_BLOCK_FREE(pHeapInt, pLeft);
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync }
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync AssertMsgReturnVoid(pLeft != pFree, ("Freed twice! pv=%p (pBlock=%p)\n", pBlock + 1, pBlock));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_L(RTHEAPOFF_TO_OFF(pHeapInt, pLeft), RTHEAPOFF_TO_OFF(pHeapInt, pFree));
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync Assert(!pRight || (uintptr_t)pRight > (uintptr_t)pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!pLeft || RTHEAPOFF_TO_PTR(pHeapInt, pLeft->offNext, PRTHEAPOFFSETFREE) == pRight);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Insert at the head of the free block list?
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pLeft)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pRight == RTHEAPOFF_TO_PTR(pHeapInt, pHeapInt->offFreeHead, PRTHEAPOFFSETFREE));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.fFlags |= RTHEAPOFFSETBLOCK_FLAGS_FREE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->offPrev = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pRight);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pRight)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pRight->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync else
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync pHeapInt->offFreeHead = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync }
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Can we merge with left hand free block?
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync if (pLeft->Core.offNext == RTHEAPOFF_TO_OFF(pHeapInt, pFree))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pLeft->Core.offNext = pFree->Core.offNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pFree->Core.offNext)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHEAPOFF_TO_PTR(pHeapInt, pFree->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pLeft);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->cbFree -= pLeft->cb;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree = pLeft;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * No, just link it into the free list then.
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync */
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.fFlags |= RTHEAPOFFSETBLOCK_FLAGS_FREE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pRight);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pLeft);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pLeft->offNext = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pRight)
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync pRight->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
ab0130d1627b2b214952b929de71b89e4ba41eb1vboxsync * Can we merge with right hand free block?
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync if ( pRight
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync && pRight->Core.offPrev == RTHEAPOFF_TO_OFF(pHeapInt, pFree))
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* core */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->Core.offNext = pRight->Core.offNext;
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync if (pRight->Core.offNext)
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync RTHEAPOFF_TO_PTR(pHeapInt, pRight->Core.offNext, PRTHEAPOFFSETBLOCK)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync /* free */
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pFree->offNext = pRight->offNext;
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync if (pRight->offNext)
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync RTHEAPOFF_TO_PTR(pHeapInt, pRight->offNext, PRTHEAPOFFSETFREE)->offPrev = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync else
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pHeapInt->offFreeTail = RTHEAPOFF_TO_OFF(pHeapInt, pFree);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pHeapInt->cbFree -= pRight->cb;
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync }
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync /*
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * Calculate the size and update free stats.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFree->cb = (pFree->Core.offNext ? pFree->Core.offNext : pHeapInt->cbHeap)
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync - RTHEAPOFF_TO_OFF(pHeapInt, pFree) - sizeof(RTHEAPOFFSETBLOCK);
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync pHeapInt->cbFree += pFree->cb;
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync ASSERT_BLOCK_FREE(pHeapInt, pFree);
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtHeapOffsetAssertAll(pHeapInt);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync#ifdef RTHEAPOFFSET_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync * Internal consistency check (relying on assertions).
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync * @param pHeapInt
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync */
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsyncstatic void rtHeapOffsetAssertAll(PRTHEAPOFFSETINTERNAL pHeapInt)
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETFREE pPrev = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETFREE pPrevFree = NULL;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync PRTHEAPOFFSETFREE pBlock;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync for (pBlock = (PRTHEAPOFFSETFREE)(pHeapInt + 1);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBlock = RTHEAPOFF_TO_PTR(pHeapInt, pBlock->Core.offNext, PRTHEAPOFFSETFREE))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RTHEAPOFFSETBLOCK_IS_FREE(&pBlock->Core))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_FREE(pHeapInt, pBlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pBlock->offPrev == RTHEAPOFF_TO_OFF(pHeapInt, pPrevFree));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPrevFree || pHeapInt->offFreeHead == RTHEAPOFF_TO_OFF(pHeapInt, pBlock));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrevFree = pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_USED(pHeapInt, &pBlock->Core);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!pPrev || RTHEAPOFF_TO_OFF(pHeapInt, pPrev) == pBlock->Core.offPrev);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pPrev = pBlock;
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync }
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync Assert(pHeapInt->offFreeTail == RTHEAPOFF_TO_OFF(pHeapInt, pPrevFree));
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(size_t) RTHeapOffsetSize(RTHEAPOFFSET hHeap, void *pv)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETINTERNAL pHeapInt;
61283d6341bac43f73cf33c9ec754a59f674fa19vboxsync PRTHEAPOFFSETBLOCK pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync size_t cbBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pv)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return 0;
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync AssertPtrReturn(pv, 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertReturn(RT_ALIGN_P(pv, RTHEAPOFFSET_ALIGNMENT) == pv, 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Get the block and heap. If in strict mode, validate these.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBlock = (PRTHEAPOFFSETBLOCK)pv - 1;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync pHeapInt = RTHEAPOFF_GET_ANCHOR(pBlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_BLOCK_USED(pHeapInt, pBlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_ANCHOR(pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pHeapInt == (PRTHEAPOFFSETINTERNAL)hHeap || !hHeap);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Calculate the block size.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbBlock = (pBlock->offNext ? pBlock->offNext : pHeapInt->cbHeap)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync - RTHEAPOFF_TO_OFF(pHeapInt, pBlock) - sizeof(RTHEAPOFFSETBLOCK);
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync return cbBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetSize);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(size_t) RTHeapOffsetGetHeapSize(RTHEAPOFFSET hHeap)
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETINTERNAL pHeapInt;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (hHeap == NIL_RTHEAPOFFSET)
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync return 0;
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync pHeapInt = hHeap;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pHeapInt, 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_ANCHOR(pHeapInt);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync return pHeapInt->cbHeap;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetGetHeapSize);
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsyncRTDECL(size_t) RTHeapOffsetGetFreeSize(RTHEAPOFFSET hHeap)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTHEAPOFFSETINTERNAL pHeapInt;
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (hHeap == NIL_RTHEAPOFFSET)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHeapInt = hHeap;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pHeapInt, 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASSERT_ANCHOR(pHeapInt);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pHeapInt->cbFree;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetGetFreeSize);
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsyncRTDECL(void) RTHeapOffsetDump(RTHEAPOFFSET hHeap, PFNRTHEAPOFFSETPRINTF pfnPrintf)
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync{
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync PRTHEAPOFFSETINTERNAL pHeapInt = (PRTHEAPOFFSETINTERNAL)hHeap;
0f8b9243304469cd1e58d6986931bbfed5ba359evboxsync PRTHEAPOFFSETFREE pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
be9bc9b4ba510c4b4159c193f783d024633ef8e9vboxsync pfnPrintf("**** Dumping Heap %p - cbHeap=%x cbFree=%x ****\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync hHeap, pHeapInt->cbHeap, pHeapInt->cbFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync for (pBlock = (PRTHEAPOFFSETFREE)(pHeapInt + 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBlock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBlock = RTHEAPOFF_TO_PTR(pHeapInt, pBlock->Core.offNext, PRTHEAPOFFSETFREE))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync size_t cb = (pBlock->offNext ? pBlock->Core.offNext : pHeapInt->cbHeap)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync - RTHEAPOFF_TO_OFF(pHeapInt, pBlock) - sizeof(RTHEAPOFFSETBLOCK);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync if (RTHEAPOFFSETBLOCK_IS_FREE(&pBlock->Core))
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pfnPrintf("%p %06x FREE offNext=%06x offPrev=%06x fFlags=%#x cb=%#06x : cb=%#06x offNext=%06x offPrev=%06x\n",
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pBlock, pBlock->Core.offSelf, pBlock->Core.offNext, pBlock->Core.offPrev, pBlock->Core.fFlags, cb,
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pBlock->cb, pBlock->offNext, pBlock->offPrev);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync else
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pfnPrintf("%p %06x USED offNext=%06x offPrev=%06x fFlags=%#x cb=%#06x\n",
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pBlock, pBlock->Core.offSelf, pBlock->Core.offNext, pBlock->Core.offPrev, pBlock->Core.fFlags, cb);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync }
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync pfnPrintf("**** Done dumping Heap %p ****\n", hHeap);
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync}
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsyncRT_EXPORT_SYMBOL(RTHeapOffsetDump);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync