rtmempage-exec-mmap-heap-posix.cpp revision 4e47bb772df0d04d1ded3e06354de547d52e2d06
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * IPRT - RTMemPage*, POSIX with heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Copyright (C) 2006-2010 Oracle Corporation
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * available from http://www.virtualbox.org. This file is free software;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * you can redistribute it and/or modify it under the terms of the GNU
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * General Public License (GPL) as published by the Free Software
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * The contents of this file may alternatively be used under the terms
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * of the Common Development and Distribution License Version 1.0
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * VirtualBox OSE distribution, in which case the provisions of the
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * CDDL are applicable instead of those of the GPL.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * You may elect to license modified versions of this file under the
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * terms and conditions of either the GPL or the CDDL or both.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/*******************************************************************************
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync* Header Files *
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync*******************************************************************************/
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/*******************************************************************************
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync* Defined Constants And Macros *
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync*******************************************************************************/
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** Threshold at which to we switch to simply calling mmap. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** The size of a heap block (power of two) - in bytes. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncAssertCompile(RTMEMPAGEPOSIX_BLOCK_SIZE == (RTMEMPAGEPOSIX_BLOCK_SIZE / PAGE_SIZE) * PAGE_SIZE);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** The number of pages per heap block. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync#define RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT (RTMEMPAGEPOSIX_BLOCK_SIZE / PAGE_SIZE)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/*******************************************************************************
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync* Structures and Typedefs *
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync*******************************************************************************/
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** Pointer to a page heap block. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * A simple page heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsynctypedef struct RTHEAPPAGE
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Magic number (RTHEAPPAGE_MAGIC). */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** The number of pages in the heap (in BlockTree). */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** The number of currently free pages. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Number of successful calls. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Number of successful free calls. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** The free call number at which we last tried to minimize the heap. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Tree of heap blocks. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Allocation hint no 1 (last freed). */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Allocation hint no 2 (last alloc). */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Critical section protecting the heap. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Set if the memory must allocated with execute access. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** Pointer to a page heap. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Describes a page heap block.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** The AVL tree node core (void pointer range). */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Allocation bitmap. Set bits marks allocated pages. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync uint32_t bmAlloc[RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT / 32];
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Allocation boundrary bitmap. Set bits marks the start of
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * allocations. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync uint32_t bmFirst[RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT / 32];
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** The number of free pages. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Pointer back to the heap. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Argument package for rtHeapPageAllocCallback.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** The number of pages to allocate. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Non-null on success. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** Whether the pages should be zeroed or not. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/*******************************************************************************
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync* Global Variables *
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync*******************************************************************************/
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** Initialize once structure. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncstatic RTONCE g_MemPagePosixInitOnce = RTONCE_INITIALIZER;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** The page heap. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync/** The exec page heap. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Initializes the heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns IPRT status code.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pHeap The page heap to initialize.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param fExec Whether the heap memory should be marked as
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * executable or not.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync * Deletes the heap and all the memory it tracks.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns IPRT status code.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pHeap The page heap to delete.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Avoids some gotos in rtHeapPageAllocFromBlock.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns VINF_SUCCESS.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pBlock The block.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param iPage The page to start allocating at.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cPages The number of pages.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param fZero Whether to clear them.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param ppv Where to return the allocation address.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncDECLINLINE(int) rtHeapPageAllocFromBlockSuccess(PRTHEAPPAGEBLOCK pBlock, uint32_t iPage, size_t cPages, bool fZero, void **ppv)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync if (!pHeap->pHint2 || pHeap->pHint2->cFreePages < pBlock->cFreePages)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync void *pv = (uint8_t *)pBlock->Core.Key + (iPage << PAGE_SHIFT);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Checks if a page range is free in the specified block.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns @c true if the range is free, @c false if not.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pBlock The block.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param iFirst The first page to check.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cPages The number of pages to check.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncDECLINLINE(bool) rtHeapPageIsPageRangeFree(PRTHEAPPAGEBLOCK pBlock, uint32_t iFirst, uint32_t cPages)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync while (i-- > iFirst)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return false;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return true;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Tries to allocate a chunk of pages from a heap block.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @retval VINF_SUCCESS on success.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @retval VERR_NO_MEMORY if the allocation failed.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pBlock The block to allocate from.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cPages The size of the allocation.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param fZero Whether it should be zeroed or not.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param ppv Where to return the allocation address on success.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncDECLINLINE(int) rtHeapPageAllocFromBlock(PRTHEAPPAGEBLOCK pBlock, size_t cPages, bool fZero, void **ppv)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync int iPage = ASMBitFirstClear(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /* special case: single page. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return rtHeapPageAllocFromBlockSuccess(pBlock, iPage, cPages, fZero, ppv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync while ( iPage >= 0
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync && (unsigned)iPage <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT - cPages)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync if (rtHeapPageIsPageRangeFree(pBlock, iPage + 1, cPages - 1))
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync ASMBitSetRange(&pBlock->bmAlloc[0], iPage, iPage + cPages);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return rtHeapPageAllocFromBlockSuccess(pBlock, iPage, cPages, fZero, ppv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync iPage = ASMBitNextSet(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT, iPage);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync if (iPage < 0 || iPage >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT - 1)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync iPage = ASMBitNextClear(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT, iPage);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * RTAvlrPVDoWithAll callback.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns 0 to continue the enum, non-zero to quit it.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pNode The node.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pvUser The user argument.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncstatic DECLCALLBACK(int) rtHeapPageAllocCallback(PAVLRPVNODECORE pNode, void *pvUser)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync PRTHEAPPAGEBLOCK pBlock = RT_FROM_MEMBER(pNode, RTHEAPPAGEBLOCK, Core);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync RTHEAPPAGEALLOCARGS *pArgs = (RTHEAPPAGEALLOCARGS *)pvUser;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync int rc = rtHeapPageAllocFromBlock(pBlock, pArgs->cPages, pArgs->fZero, &pArgs->pvAlloc);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Worker for RTHeapPageAlloc.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns IPRT status code
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pHeap The heap - locked.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cPages The page count.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pszTag The tag.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param fZero Whether to zero the memory.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param ppv Where to return the address of the allocation
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * on success.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncstatic int rtHeapPageAllocLocked(PRTHEAPPAGE pHeap, size_t cPages, const char *pszTag, bool fZero, void **ppv)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Use the hints first.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync rc = rtHeapPageAllocFromBlock(pHeap->pHint1, cPages, fZero, ppv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync rc = rtHeapPageAllocFromBlock(pHeap->pHint2, cPages, fZero, ppv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Search the heap for a block with enough free space.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * N.B. This search algorithm is not optimal at all. What (hopefully) saves
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * it are the two hints above.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync RTAvlrPVDoWithAll(&pHeap->BlockTree, true /*fFromLeft*/, rtHeapPageAllocCallback, &Args);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Didn't find anytyhing, so expand the heap with a new block.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync PROT_READ | PROT_WRITE | (pHeap->fExec ? PROT_EXEC : 0),
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /** @todo Eliminate this rtMemBaseAlloc dependency! */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)rtMemBaseAlloc(sizeof(*pBlock));
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync pBlock->Core.KeyLast = (uint8_t *)pvPages + RTMEMPAGEPOSIX_BLOCK_SIZE - 1;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync pBlock->cFreePages = RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync bool fRc = RTAvlrPVInsert(&pHeap->BlockTree, &pBlock->Core); Assert(fRc); NOREF(fRc);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync pHeap->cFreePages += RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync pHeap->cHeapPages += RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Grab memory from the new block (cannot fail).
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync rc = rtHeapPageAllocFromBlock(pBlock, cPages, fZero, ppv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Allocates one or more pages off the heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns IPRT status code.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pHeap The page heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cPages The number of pages to allocate.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pszTag The allocation tag.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param fZero Set if the pages should be zeroed or not.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param ppv Where to return the pointer to the pages.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncint RTHeapPageAlloc(PRTHEAPPAGE pHeap, size_t cPages, const char *pszTag, bool fZero, void **ppv)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Validate input.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync AssertMsgReturn(cPages < RTMEMPAGEPOSIX_BLOCK_SIZE, ("%#zx\n", cPages), VERR_OUT_OF_RANGE);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Grab the lock and call a worker with many returns.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync rc = rtHeapPageAllocLocked(pHeap, cPages, pszTag, fZero, ppv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * RTAvlrPVDoWithAll callback.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns 0 to continue the enum, non-zero to quit it.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pNode The node.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pvUser Pointer to a block pointer variable. For returning
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * the address of the block to be freed.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncstatic DECLCALLBACK(int) rtHeapPageFindUnusedBlockCallback(PAVLRPVNODECORE pNode, void *pvUser)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync PRTHEAPPAGEBLOCK pBlock = RT_FROM_MEMBER(pNode, RTHEAPPAGEBLOCK, Core);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync if (pBlock->cFreePages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Allocates one or more pages off the heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns IPRT status code.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pHeap The page heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pv Pointer to what RTHeapPageAlloc returned.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cPages The number of pages that was allocated.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncint RTHeapPageFree(PRTHEAPPAGE pHeap, void *pv, size_t cPages)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Validate input.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Grab the lock and look up the page.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)RTAvlrPVRangeGet(&pHeap->BlockTree, pv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Validate the specified address range.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync uint32_t const iPage = (uint32_t)(((uintptr_t)pv - (uintptr_t)pBlock->Core.Key) >> PAGE_SHIFT);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /* Check the range is within the block. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync bool fOk = iPage + cPages <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /* Check that it's the start of an allocation. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync fOk = fOk && ASMBitTest(&pBlock->bmFirst[0], iPage);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /* Check that the range ends at an allocation boundrary. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync fOk = fOk && ( iPage + cPages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync || !ASMBitTest(&pBlock->bmAlloc[0], iPage + cPages));
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync /* Check the other pages. */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync for (uint32_t i = iPage + 1; i < iLastPage && fOk; i++)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Free the memory.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync ASMBitClearRange(&pBlock->bmAlloc[0], iPage, iPage + cPages);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync if (!pHeap->pHint1 || pHeap->pHint1->cFreePages < pBlock->cFreePages)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Shrink the heap. Not very efficient because of the AVL tree.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync if ( pHeap->cFreePages >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT * 3
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync && pHeap->cFreePages >= pHeap->cHeapPages / 2 /* 50% free */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync && pHeap->cFreeCalls - pHeap->uLastMinimizeCall > RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync uint32_t cFreePageTarget = pHeap->cHeapPages / 4; /* 25% free */
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync RTAvlrPVDoWithAll(&pHeap->BlockTree, false /*fFromLeft*/,
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync void *pv2 = RTAvlrPVRemove(&pHeap->BlockTree, pBlock->Core.Key); Assert(pv2); NOREF(pv2);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync pHeap->cHeapPages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync pHeap->cFreePages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync munmap(pBlock->Core.Key, RTMEMPAGEPOSIX_BLOCK_SIZE);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Initializes the heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns IPRT status code
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pvUser1 Unused.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pvUser2 Unused.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncstatic DECLCALLBACK(int) rtMemPagePosixInitOnce(void *pvUser1, void *pvUser2)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync int rc = RTHeapPageInit(&g_MemPagePosixHeap, false /*fExec*/);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync rc = RTHeapPageInit(&g_MemExecPosixHeap, true /*fExec*/);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Allocates memory from the specified heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @returns Address of the allocated memory.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cb The number of bytes to allocate.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pszTag The tag.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param fZero Whether to zero the memory or not.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pHeap The heap to use.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncstatic void *rtMemPagePosixAlloc(size_t cb, const char *pszTag, bool fZero, PRTHEAPPAGE pHeap)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Validate & adjust the input.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * If the allocation is relatively large, we use mmap/munmap directly.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync PROT_READ | PROT_WRITE | (pHeap == &g_MemExecPosixHeap ? PROT_EXEC : 0),
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync int rc = RTOnce(&g_MemPagePosixInitOnce, rtMemPagePosixInitOnce, NULL, NULL);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync rc = RTHeapPageAlloc(pHeap, cb >> PAGE_SHIFT, pszTag, fZero, &pv);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Free memory allocated by rtMemPagePosixAlloc.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pv The address of the memory to free.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param cb The size.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * @param pHeap The heap.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncstatic void rtMemPagePosixFree(void *pv, size_t cb, PRTHEAPPAGE pHeap)
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * Validate & adjust the input.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync * If the allocation is relatively large, we use mmap/munmap directly.
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync AssertMsg(rc == 0, ("rc=%d pv=%p cb=%#zx\n", rc, pv, cb)); NOREF(rc);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync int rc = RTHeapPageFree(pHeap, pv, cb >> PAGE_SHIFT);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncRTDECL(void *) RTMemPageAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return rtMemPagePosixAlloc(cb, pszTag, false /*fZero*/, &g_MemPagePosixHeap);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncRTDECL(void *) RTMemPageAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return rtMemPagePosixAlloc(cb, pszTag, true /*fZero*/, &g_MemPagePosixHeap);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncRTDECL(void) RTMemPageFree(void *pv, size_t cb) RT_NO_THROW
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return rtMemPagePosixFree(pv, cb, &g_MemPagePosixHeap);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncRTDECL(void *) RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsync return rtMemPagePosixAlloc(cb, pszTag, false /*fZero*/, &g_MemExecPosixHeap);
418b9db49fbc652ef9c3f030fdc0f1a322403d95vboxsyncRTDECL(void) RTMemExecFree(void *pv, size_t cb) RT_NO_THROW