Files
mars-flaim/flaim/src/gdpool.cpp

382 lines
10 KiB
C++

//-------------------------------------------------------------------------
// Desc: Memory pool routines.
// Tabs: 3
//
// Copyright (c) 1992-2001,2003-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: gdpool.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
//-------------------------------------------------------------------------
#include "flaimsys.h"
#if defined( FLM_UNIX) || defined( FLM_NLM) || defined( FLM_WIN)
#define PTR_IN_MBLK(p,bp,offs) (((FLMBYTE *)(p) > (FLMBYTE *)(bp)) && \
((FLMBYTE *)(p) <= (FLMBYTE *)(bp) + (offs)))
#else
#error Platform not supported
#endif
FSTATIC RCODE GedPoolFreeToMark(
POOL * pPool,
void * markPtr);
/****************************************************************************
Desc: Initializes a memory pool
****************************************************************************/
FLMEXP void FLMAPI GedPoolInit(
POOL * pPool,
FLMUINT uiBlkSize)
{
pPool->uiBytesAllocated = 0;
pPool->lblk = NULL;
pPool->pPoolStats = NULL;
pPool->uiBlkSize = uiBlkSize;
}
/****************************************************************************
Desc: Returns a "marker" to the current offset in the memory pool
****************************************************************************/
FLMEXP void * FLMAPI GedPoolMark(
POOL * pPool)
{
return (void *)((pPool->lblk)
? (FLMBYTE *) pPool->lblk + pPool->lblk->uiFreeOfs
: (FLMBYTE *)GedPoolAlloc( pPool, 1));
}
/****************************************************************************
Desc: Determine what the initial block size should be for smart pools.
****************************************************************************/
FINLINE void SetInitialSmartPoolBlkSize(
POOL * pPool)
{
/*
Determine starting block size:
1) average of bytes allocated / # of frees/resets (average size needed)
2) add 10% - to minimize extra allocs
*/
pPool->uiBlkSize = (pPool->pPoolStats->uiAllocBytes / pPool->pPoolStats->uiCount);
pPool->uiBlkSize += (pPool->uiBlkSize / 10);
if( pPool->uiBlkSize < 512)
pPool->uiBlkSize = 512;
}
/****************************************************************************
Desc: Update the bytes allocated and alloc count for this pool's POOL_STATS
****************************************************************************/
FINLINE void UpdateSmartPoolStats(
POOL * pPool)
{
if( pPool->uiBytesAllocated)
{
POOL_STATS * pStats = pPool->pPoolStats;
if( (pStats->uiAllocBytes + pPool->uiBytesAllocated) >= 0xFFFF0000)
{
pStats->uiAllocBytes = (pStats->uiAllocBytes / pStats->uiCount) * 100;
pStats->uiCount = 100;
}
else
{
pStats->uiAllocBytes += pPool->uiBytesAllocated;
pStats->uiCount++;
}
pPool->uiBytesAllocated = 0;
}
}
/*************************************************************************
Desc: Initialize a smart pool memory structure. A smart pool is one that
will adjust it's block allocation size based on statistics it
gathers within the POOL_STATS structure. For each pool that user
wants to use smart memory management a global POOL_STATS structure
should be declared. The POOL_STATS structure is used to track the
total bytes allocated and determine what the correct pool block
size should be.
*************************************************************************/
void GedSmartPoolInit(
POOL * pPool,
POOL_STATS * pPoolStats)
{
pPool->lblk = NULL;
pPool->uiBytesAllocated = 0;
pPool->pPoolStats = pPoolStats;
if( pPoolStats && pPoolStats->uiCount)
{
SetInitialSmartPoolBlkSize( pPool);
}
else
{
pPool->uiBlkSize = 2048;
}
}
/****************************************************************************
Desc: Allocates a block of memory from a memory pool.
Note: If the number of bytes is more than the what is left in the
current block then a new block will be allocated and the lbkl element
of the PMS will be updated.
****************************************************************************/
FLMEXP void * FLMAPI GedPoolAlloc(
POOL * pPool,
FLMUINT uiSize)
{
MBLK * blk = pPool->lblk;
MBLK * old_lblk = blk;
FLMBYTE * freePtr;
FLMUINT uiBlkSize;
// Adjust the size to a machine word boundary
// NOTE: ORed and ANDed 0x800.. & 0x7FFF to prevent partial
// stalls on Netware.
if( uiSize & (FLM_ALLOC_ALIGN | 0x80000000))
{
uiSize = ((uiSize + FLM_ALLOC_ALIGN) & (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF));
}
// Check if room in block
if( ! blk || uiSize > blk->uiFreeSize)
{
// Check if previous block has space for allocation
if( blk && blk->pPrevBlk != NULL && uiSize <= blk->pPrevBlk->uiFreeSize)
{
blk = blk->pPrevBlk;
goto Exit;
}
/* Not enough memory in block - allocate new block */
/* Determine the block size:
1) start with max of last block size, initial pool size, or alloc size
2) if this is an extra block alloc then increase the size by 1/2
3) adjust size to include blk header */
uiBlkSize = (blk) ? blk->uiBlkSize : pPool->uiBlkSize;
uiBlkSize = f_max( uiSize, uiBlkSize);
if( blk && (uiBlkSize == blk->uiBlkSize) && uiBlkSize <= 32769)
uiBlkSize += uiBlkSize / 2;
uiBlkSize += sizeof( MBLK);
if( RC_BAD( f_alloc( uiBlkSize, &blk)))
return( NULL);
// Initialize the block elements
blk->uiBlkSize = uiBlkSize;
blk->uiFreeOfs = sizeof( MBLK);
blk->uiFreeSize = uiBlkSize - sizeof( MBLK);
pPool->lblk = blk;
blk->pPrevBlk = old_lblk;
}
Exit:
freePtr = (FLMBYTE *) blk;
freePtr += blk->uiFreeOfs;
blk->uiFreeOfs += uiSize;
blk->uiFreeSize -= uiSize;
pPool->uiBytesAllocated += uiSize;
return( (void *) freePtr);
}
/************************************************************************
Desc: Allocates memory from a pool and initializes all bytes to zero.
*END*********************************************************************/
FLMEXP void * FLMAPI GedPoolCalloc(
POOL * pPool,
FLMUINT uiSize)
{
void * ptr;
if( (ptr = GedPoolAlloc( pPool, uiSize)) != NULL)
{
f_memset( ptr, 0, uiSize);
}
return ptr;
}
/****************************************************************************
Desc: Releases all memory allocated to a pool.
Note: All memory allocated to the pool is returned to the operating system.
****************************************************************************/
FLMEXP RCODE FLMAPI GedPoolFree(
POOL * pPool)
{
MBLK * blk = pPool->lblk;
MBLK * prevBlk;
while( blk)
{
prevBlk = blk->pPrevBlk;
f_free( &blk);
blk = prevBlk;
}
pPool->lblk = NULL;
// For Smart Pools update pool statictics
if( pPool->pPoolStats)
{
UpdateSmartPoolStats( pPool);
}
return( FERR_OK);
}
/****************************************************************************
Desc: Resets memory blocks allocated to a pool.
Note: Will reset the free space in the first memory block, and if
any extra blocks exist they will be freed (destroyed).
****************************************************************************/
FLMEXP RCODE FLMAPI GedPoolReset(
POOL * pPool,
void * markPtr)
{
MBLK * blk = pPool->lblk;
MBLK * prevBlk;
if( ! blk)
return( FERR_OK);
// For Smart Pools update pool statictics
if( pPool->pPoolStats)
{
UpdateSmartPoolStats( pPool);
}
if( markPtr)
{
return( GedPoolFreeToMark( pPool, markPtr));
}
// Free all blocks except last one in chain -- which is really
// the first block allocated. This will help us keep memory from
// getting fragmented.
while( blk->pPrevBlk)
{
prevBlk = blk->pPrevBlk;
f_free( &blk);
blk = prevBlk;
}
if( (blk->uiBlkSize - sizeof(MBLK)) > pPool->uiBlkSize)
{
// The first block was not the default size, so FREE it
f_free( &blk);
pPool->lblk = NULL;
}
else
{
// Reset the allocation pointers in the first block
blk->uiFreeOfs = sizeof( MBLK);
blk->uiFreeSize = blk->uiBlkSize - sizeof( MBLK);
pPool->lblk = blk;
#ifdef FLM_MEM_CHK
{
FLMBYTE * ptr = (FLMBYTE *) blk;
ptr += blk->uiFreeOfs;
f_memset( ptr, 'r', blk->uiFreeSize);
}
#endif
}
// On smart pools, adjust the initial block size on pool resets
if( pPool->pPoolStats)
{
SetInitialSmartPoolBlkSize( pPool);
}
return( FERR_OK);
}
/****************************************************************************
Desc: Frees memory until the markPtr is found.
****************************************************************************/
FSTATIC RCODE GedPoolFreeToMark(
POOL * pPool,
void * markPtr)
{
MBLK * blk = pPool->lblk;
MBLK * prevBlk;
pPool->lblk = NULL; /* Initialize PMS to no BLOCKS */
while( blk) /* Free all allocated blks in chain */
{
prevBlk = blk->pPrevBlk; /* Save pointer to prev block */
/* Check for mark point */
if( PTR_IN_MBLK( markPtr, blk, blk->uiBlkSize))
{
FLMUINT uiOldFreeOfs = blk->uiFreeOfs;
/* Reset freeOfs and freeSize variables */
blk->uiFreeOfs = (FLMUINT)((FLMBYTE *)markPtr - (FLMBYTE *)blk);
blk->uiFreeSize = blk->uiBlkSize - blk->uiFreeOfs;
#if defined( FLM_MEM_CHK) || defined( MEM_TEST)
{
/* memset the memory so someone pointing to it will get a error.*/
FLMBYTE * ptr = (FLMBYTE *) blk;
ptr += blk->uiFreeOfs;
f_memset( ptr, 'r', blk->uiFreeSize); // Set memory to 'r' for Reset
}
#endif
// For Smart Pools deduct the bytes allocated since pool mark
if( pPool->pPoolStats)
{
flmAssert( uiOldFreeOfs >= blk->uiFreeOfs);
pPool->uiBytesAllocated -= (uiOldFreeOfs - blk->uiFreeOfs);
}
break;
}
if( pPool->pPoolStats)
{
pPool->uiBytesAllocated -= (blk->uiFreeOfs - sizeof( MBLK));
}
f_free( &blk);
blk = prevBlk; /* Point to previous block */
}
if( blk)
pPool->lblk = blk;
return( FERR_OK);
}