rtmempage-exec-mmap-heap-posix.cpp revision 418b9db49fbc652ef9c3f030fdc0f1a322403d95
/* $Id$ */
/** @file
* IPRT - RTMemPage*, POSIX with heap.
*/
/*
* Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/critsect.h>
#include <stdlib.h>
#include <errno.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Threshold at which to we switch to simply calling mmap. */
#define RTMEMPAGEPOSIX_MMAP_THRESHOLD _128K
/** The size of a heap block (power of two) - in bytes. */
#define RTMEMPAGEPOSIX_BLOCK_SIZE _2M
/** The number of pages per heap block. */
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/** Pointer to a page heap block. */
typedef struct RTHEAPPAGEBLOCK *PRTHEAPPAGEBLOCK;
/**
* A simple page heap.
*/
typedef struct RTHEAPPAGE
{
/** Magic number (RTHEAPPAGE_MAGIC). */
/** The number of pages in the heap (in BlockTree). */
/** The number of currently free pages. */
/** Number of successful calls. */
/** Number of successful free calls. */
/** The free call number at which we last tried to minimize the heap. */
/** Tree of heap blocks. */
/** Allocation hint no 1 (last freed). */
/** Allocation hint no 2 (last alloc). */
/** Critical section protecting the heap. */
/** Set if the memory must allocated with execute access. */
bool fExec;
} RTHEAPPAGE;
/** Pointer to a page heap. */
typedef RTHEAPPAGE *PRTHEAPPAGE;
/**
* Describes a page heap block.
*/
typedef struct RTHEAPPAGEBLOCK
{
/** The AVL tree node core (void pointer range). */
/** Allocation bitmap. Set bits marks allocated pages. */
/** Allocation boundrary bitmap. Set bits marks the start of
* allocations. */
/** The number of free pages. */
/** Pointer back to the heap. */
/**
* Argument package for rtHeapPageAllocCallback.
*/
typedef struct RTHEAPPAGEALLOCARGS
{
/** The number of pages to allocate. */
/** Non-null on success. */
void *pvAlloc;
/** Whether the pages should be zeroed or not. */
bool fZero;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Initialize once structure. */
/** The page heap. */
static RTHEAPPAGE g_MemPagePosixHeap;
/** The exec page heap. */
static RTHEAPPAGE g_MemExecPosixHeap;
/**
* Initializes the heap.
*
* @returns IPRT status code.
* @param pHeap The page heap to initialize.
* @param fExec Whether the heap memory should be marked as
* executable or not.
*/
{
if (RT_SUCCESS(rc))
{
pHeap->cHeapPages = 0;
pHeap->cFreePages = 0;
pHeap->cAllocCalls = 0;
pHeap->cFreeCalls = 0;
pHeap->uLastMinimizeCall = 0;
}
return rc;
}
/**
* Deletes the heap an all the memory it tracks.
*
* @returns IPRT status code.
* @param pHeap The page heap to delete.
*/
{
return VERR_NOT_IMPLEMENTED;
}
/**
* Avoids some gotos in rtHeapPageAllocFromBlock.
*
* @returns VINF_SUCCESS.
* @param pBlock The block.
* @param iPage The page to start allocating at.
* @param cPages The number of pages.
* @param fZero Whether to clear them.
* @param ppv Where to return the allocation address.
*/
DECLINLINE(int) rtHeapPageAllocFromBlockSuccess(PRTHEAPPAGEBLOCK pBlock, uint32_t iPage, size_t cPages, bool fZero, void **ppv)
{
pHeap->cAllocCalls++;
if (fZero)
return VINF_SUCCESS;
}
/**
* Checks if a page range is free in the specified block.
*
* @returns @c true if the range is free, @c false if not.
* @param pBlock The block.
* @param iFirst The first page to check.
* @param cPages The number of pages to check.
*/
DECLINLINE(bool) rtHeapPageIsPageRangeFree(PRTHEAPPAGEBLOCK pBlock, uint32_t iFirst, uint32_t cPages)
{
while (i-- > iFirst)
{
return false;
}
return true;
}
/**
* Tries to allocate a chunk of pages from a heap block.
*
* @retval VINF_SUCCESS on success.
* @retval VERR_NO_MEMORY if the allocation failed.
* @param pBlock The block to allocate from.
* @param cPages The size of the allocation.
* @param fZero Whether it should be zeroed or not.
* @param ppv Where to return the allocation address on success.
*/
DECLINLINE(int) rtHeapPageAllocFromBlock(PRTHEAPPAGEBLOCK pBlock, size_t cPages, bool fZero, void **ppv)
{
{
/* special case: single page. */
if (cPages == 1)
{
}
while ( iPage >= 0
{
{
}
/* next */
break;
}
}
return VERR_NO_MEMORY;
}
/**
* RTAvlrPVDoWithAll callback.
*
* @returns 0 to continue the enum, non-zero to quit it.
* @param pNode The node.
* @param pvUser The user argument.
*/
{
}
/**
* Worker for RTHeapPageAlloc.
*
* @returns IPRT status code
* @param pHeap The heap - locked.
* @param cPages The page count.
* @param pszTag The tag.
* @param fZero Whether to zero the memory.
* @param ppv Where to return the address of the allocation
* on success.
*/
static int rtHeapPageAllocLocked(PRTHEAPPAGE pHeap, size_t cPages, const char *pszTag, bool fZero, void **ppv)
{
int rc;
/*
* Use the hints first.
*/
{
if (rc != VERR_NO_MEMORY)
return rc;
}
{
if (rc != VERR_NO_MEMORY)
return rc;
}
/*
* Search the heap for a block with enough free space.
*
* N.B. This search algorithm is not optimal at all. What (hopefully) saves
* it are the two hints above.
*/
{
{
return VINF_SUCCESS;
}
}
/*
* Didn't find anytyhing, so expand the heap with a new block.
*/
void *pvPages;
-1, 0);
if (pvPages == MAP_FAILED)
{
return RTErrConvertFromErrno(errno);
}
/** @todo Eliminate this rtMemBaseAlloc dependency! */
if (!pBlock)
{
return VERR_NO_MEMORY;
}
/*
* Grab memory from the new block (cannot fail).
*/
return rc;
}
/**
* Allocates one or more pages off the heap.
*
* @returns IPRT status code.
* @param pHeap The page heap.
* @param cPages The number of pages to allocate.
* @param pszTag The allocation tag.
* @param fZero Set if the pages should be zeroed or not.
* @param ppv Where to return the pointer to the pages.
*/
{
/*
* Validate input.
*/
/*
* Grab the lock and call a worker with many returns.
*/
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* RTAvlrPVDoWithAll callback.
*
* @returns 0 to continue the enum, non-zero to quit it.
* @param pNode The node.
* @param pvUser Pointer to a block pointer variable. For returning
* the address of the block to be freed.
*/
{
{
return 1;
}
return 0;
}
/**
* Allocates one or more pages off the heap.
*
* @returns IPRT status code.
* @param pHeap The page heap.
* @param pv Pointer to what RTHeapPageAlloc returned.
* @param cPages The number of pages that was allocated.
*/
{
/*
* Validate input.
*/
if (!pv)
return VINF_SUCCESS;
/*
* Grab the lock and look up the page.
*/
if (RT_SUCCESS(rc))
{
if (pBlock)
{
/*
* Validate the specified address range.
*/
/* Check the range is within the block. */
/* Check that it's the start of an allocation. */
/* Check that the range ends at an allocation boundrary. */
/* Check the other pages. */
if (fOk)
{
/*
* Free the memory.
*/
pHeap->cFreeCalls++;
/*
* Shrink the heap. Not very efficient because of the AVL tree.
*/
)
{
{
if (!pBlock)
break;
pBlock->cFreePages = 0;
}
}
}
else
}
else
}
return rc;
}
/**
* Initializes the heap.
*
* @returns IPRT status code
* @param pvUser1 Unused.
* @param pvUser2 Unused.
*/
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
return rc;
}
return rc;
}
/**
* Allocates memory from the specified heap.
*
* @returns Address of the allocated memory.
* @param cb The number of bytes to allocate.
* @param pszTag The tag.
* @param fZero Whether to zero the memory or not.
* @param pHeap The heap to use.
*/
{
/*
* Validate & adjust the input.
*/
/*
*/
void *pv;
if (cb >= RTMEMPAGEPOSIX_MMAP_THRESHOLD)
{
-1, 0);
if (pv != MAP_FAILED)
{
if (fZero)
}
else
}
else
{
if (RT_SUCCESS(rc))
if (RT_FAILURE(rc))
}
return pv;
}
/**
* Free memory allocated by rtMemPagePosixAlloc.
*
* @param pv The address of the memory to free.
* @param cb The size.
* @param pHeap The heap.
*/
{
/*
* Validate & adjust the input.
*/
if (!pv)
return;
/*
*/
if (cb >= RTMEMPAGEPOSIX_MMAP_THRESHOLD)
{
}
else
{
}
}
{
}
{
}
{
}
{
}
{
}