mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
951 lines
30 KiB
951 lines
30 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1994 - 2000.
|
|
//
|
|
// File: tblalloc.hxx
|
|
//
|
|
// Contents: Memory allocation wrappers for large tables
|
|
//
|
|
// Classes: PVarAllocator - protocol for variable data allocators
|
|
// PFixedAllocator - protocol for fixed and variable alloctors
|
|
// PFixedVarAllocator - protocol for fixed and variable alloctors
|
|
// CVarBufferAllocator - simple allocation from a buffer
|
|
// CFixedVarBufferAllocator - fixed/var allocation from a buffer
|
|
// CWindowDataAllocator - data allocator for window var data
|
|
// CFixedVarAllocator - data allocator for fixed and var pieces
|
|
//
|
|
// Functions: TblPageAlloc - Allocate page-alligned memory
|
|
// TblPageRealloc - re-allocate page-alligned memory
|
|
// TblPageDealloc - deallocate page-alligned memory
|
|
// TblPageGrowSize - suggest a new size for page-alligned memory
|
|
//
|
|
// Notes: TODO - There is no means to limit growth of data segments.
|
|
// How will memory allocation targets be maintained?
|
|
// Does there need to be some means of signalling
|
|
// between the memory allocators and their consumers?
|
|
//
|
|
// History: 14 Mar 1994 AlanW Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#ifdef DISPLAY_INCLUDES
|
|
#pragma message( "#include <" __FILE__ ">..." )
|
|
#endif
|
|
|
|
#include <pmalloc.hxx>
|
|
|
|
typedef ULONG_PTR TBL_OFF;
|
|
|
|
//
|
|
// Signature structure (for debugging primarily)
|
|
//
|
|
|
|
struct TBL_PAGE_SIGNATURE {
|
|
ULONG ulSig;
|
|
ULONG cbSize;
|
|
PVOID pbAddr;
|
|
PVOID pCaller; // pad to paragraph for convenience
|
|
};
|
|
|
|
//
|
|
// Signature values; all start with the string 'tbl'
|
|
//
|
|
const ULONG TBL_SIG_COMPRESSED = 0x436c6274; // 'tblC'
|
|
const ULONG TBL_SIG_ROWDATA = 0x526c6274; // 'tblR'
|
|
const ULONG TBL_SIG_VARDATA = 0x566c6274; // 'tblV'
|
|
|
|
const unsigned cbTblAllocAlignment = sizeof( double );
|
|
|
|
inline DWORD _RoundUpToChunk( DWORD x, DWORD chunksize )
|
|
{ return (x + chunksize - 1) & ~(chunksize - 1); }
|
|
|
|
//
|
|
// Minimum size and incremental growth constants
|
|
//
|
|
|
|
const ULONG TBL_PAGE_ALLOC_MIN = 4096;
|
|
|
|
const ULONG TBL_PAGE_MASK = (TBL_PAGE_ALLOC_MIN - 1);
|
|
|
|
const ULONG TBL_PAGE_ALLOC_INCR = 32768;
|
|
|
|
//
|
|
// Maximum size of a growable data segment
|
|
//
|
|
|
|
const ULONG TBL_PAGE_MAX_SEGMENT_SIZE = 64 * 1024;
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: TblPageAlloc, public
|
|
//
|
|
// Synopsis: Allocate page-alligned memory
|
|
//
|
|
// Effects: The memory allocation counter is incremented.
|
|
// rcbSizeNeeded is adjusted on return to indicate the
|
|
// size of the allocated memory.
|
|
//
|
|
// Arguments: [rcbSizeNeeded] - required size of memory area
|
|
// [rcbPageAllocTracker] - memory allocation counter
|
|
// [ulSig] - signature of the memory (optional)
|
|
//
|
|
// Returns: PVOID - pointer to the allocated memory. NULL if
|
|
// allocation failure.
|
|
//
|
|
// Notes: rcbSizeNeeded is set to the minimum required size
|
|
// needed. TblPageGrowSize can be called to suggest
|
|
// a new size for an existing memory region.
|
|
//
|
|
// If ulSig is non-zero, the beginning of the allocated
|
|
// block is initialized with a signature block which
|
|
// identifies the caller, and which gives the size of the
|
|
// memory block. In this case, the returned pointer is
|
|
// advanced beyond the signature block.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
PVOID TblPageAlloc(
|
|
ULONG& rcbSizeNeeded,
|
|
ULONG& rcbPageAllocTracker,
|
|
ULONG const ulSig = 0
|
|
);
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: TblPageRealloc, public
|
|
//
|
|
// Synopsis: Re-allocate page-alligned memory
|
|
//
|
|
// Effects: The memory allocation counter is incremented.
|
|
// Memory is committed or decommitted to the required size.
|
|
//
|
|
// Arguments: [rcbSizeNeeded] - required size of memory area
|
|
// [rcbPageAllocTracker] - memory allocation counter
|
|
// [cbNewSize] - required size of memory area
|
|
// [cbOldSize] - current size of memory area
|
|
//
|
|
// Returns: PVOID - pointer to the allocated memory. NULL if
|
|
// allocation failure.
|
|
//
|
|
// Notes: cbOldSize need not be supplied if the memory area
|
|
// begins with a signature block. In this case, the
|
|
// pbMem passed in should point to beyond the signature
|
|
// block, and the cbNewSize should not include the size
|
|
// of the signature block.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
PVOID TblPageRealloc(
|
|
PVOID pbMem,
|
|
ULONG& rcbPageAllocTracker,
|
|
ULONG cbNewSize,
|
|
ULONG cbOldSize
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: TblPageDealloc, public
|
|
//
|
|
// Synopsis: Deallocate page-alligned memory
|
|
//
|
|
// Effects: The memory allocation counter is decremented
|
|
//
|
|
// Arguments: [pbMem] - pointer to the memory to be deallocated
|
|
// [rcbPageAllocTracker] - memory allocation counter
|
|
//
|
|
// Requires: memory to be deallocated must have previously been
|
|
// allocated by TblPageAlloc.
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void TblPageDealloc(
|
|
PVOID pbMem,
|
|
ULONG& rcbPageAllocTracker,
|
|
ULONG cbSize = 0
|
|
);
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: TblPageGrowSize, inline
|
|
//
|
|
// Synopsis: Suggest a new size for memory growth
|
|
//
|
|
// Arguments: [cbCurrentSize] - current allocation size
|
|
// [fSigned] - TRUE iff mem. block will include signature
|
|
//
|
|
// Returns: ULONG - size to be input to TblPageAlloc
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline ULONG TblPageGrowSize(
|
|
ULONG cbCurrentSize,
|
|
ULONG const fSigned = FALSE
|
|
) {
|
|
if (cbCurrentSize == 0) {
|
|
return (ULONG)(fSigned ? TBL_PAGE_ALLOC_MIN - sizeof (TBL_PAGE_SIGNATURE):
|
|
TBL_PAGE_ALLOC_MIN);
|
|
}
|
|
|
|
ULONG cbSize = cbCurrentSize;
|
|
if (fSigned) {
|
|
cbSize += sizeof (TBL_PAGE_SIGNATURE);
|
|
}
|
|
|
|
if (cbSize < TBL_PAGE_ALLOC_INCR) {
|
|
cbSize *= 2;
|
|
} else {
|
|
cbSize += TBL_PAGE_ALLOC_INCR;
|
|
}
|
|
|
|
// Round to page size
|
|
cbSize = _RoundUpToChunk( cbSize, TBL_PAGE_ALLOC_MIN );
|
|
|
|
if (fSigned)
|
|
cbSize -= sizeof (TBL_PAGE_SIGNATURE);
|
|
return cbSize;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: PFixedAllocator
|
|
//
|
|
// Purpose: Base class for fixed data allocator
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class PFixedAllocator
|
|
{
|
|
public:
|
|
// Allocate a piece of fixed memory.
|
|
virtual PVOID AllocFixed() = 0;
|
|
|
|
// Return the size of the allocation unit
|
|
virtual size_t FixedWidth() const = 0;
|
|
|
|
// Return the base address of the reserved area
|
|
virtual BYTE* BufferAddr() const = 0;
|
|
|
|
// Return the size of the reserved area
|
|
virtual size_t GetReservedSize() const = 0;
|
|
|
|
virtual void ReInit( BOOL fVarOffsets,
|
|
size_t cbReserved,
|
|
void * pvBuf,
|
|
ULONG cbBuf )
|
|
{ Win4Assert(!"Never called"); }
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: PFixedVarAllocator
|
|
//
|
|
// Purpose: Base class for fixed/variable data allocator
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class PFixedVarAllocator: public PVarAllocator, public PFixedAllocator
|
|
{
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CVarBufferAllocator
|
|
//
|
|
// Purpose: Simple data allocator for byte buffer allocation.
|
|
//
|
|
// Notes: This allocator just carves pieces out of a data
|
|
// buffer and hands them out.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CVarBufferAllocator : public PVarAllocator {
|
|
public:
|
|
CVarBufferAllocator (PVOID pBuf,
|
|
size_t cbBuf) :
|
|
_pBuf( (BYTE *)pBuf),
|
|
_pBaseAddr( (BYTE *)pBuf ),
|
|
_cbBuf( cbBuf )
|
|
{
|
|
}
|
|
|
|
// Allocate a piece of memory.
|
|
PVOID Allocate(ULONG cbNeeded);
|
|
|
|
// Free a previously allocated piece of memory (can't in a buffer).
|
|
void Free(PVOID pMem) {
|
|
return;
|
|
}
|
|
|
|
// Return whether OffsetToPointer has non-null effect
|
|
BOOL IsBasedMemory(void) {
|
|
return _pBaseAddr != 0;
|
|
}
|
|
|
|
// Convert a pointer offset to a pointer.
|
|
PVOID OffsetToPointer(TBL_OFF oBuf) {
|
|
return _pBaseAddr + oBuf;
|
|
}
|
|
|
|
// Convert a pointer to a pointer offset.
|
|
TBL_OFF PointerToOffset(PVOID pBuf) {
|
|
return (BYTE *)pBuf - _pBaseAddr;
|
|
}
|
|
|
|
// Set base address for OffsetToPointer and PointerToOffset
|
|
void SetBase(BYTE* pbBase) {
|
|
_pBaseAddr = pbBase;
|
|
}
|
|
|
|
protected:
|
|
BYTE* _pBuf; // Buffer base
|
|
BYTE* _pBaseAddr; // Bias for addresses
|
|
size_t _cbBuf; // Available space in _pBuf
|
|
};
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CVarBufferAllocator::Allocate, inline
|
|
//
|
|
// Synopsis: Allocates a piece of data out of a memory buffer
|
|
//
|
|
// Effects: updates _pBuf and _cbBuf
|
|
//
|
|
// Arguments: [cbNeeded] - number of byes of memory needed
|
|
//
|
|
// Returns: PVOID - a pointer to the allocated memory
|
|
//
|
|
// Signals: Throws E_OUTOFMEMORY if not enough memory is available.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline PVOID CVarBufferAllocator::Allocate( ULONG cbNeeded )
|
|
{
|
|
BYTE* pRetBuf;
|
|
if (cbNeeded <= _cbBuf)
|
|
{
|
|
pRetBuf = _pBuf;
|
|
_pBuf += cbNeeded;
|
|
_cbBuf -= cbNeeded;
|
|
}
|
|
else
|
|
{
|
|
QUIETTHROW( CException(E_OUTOFMEMORY) );
|
|
}
|
|
return pRetBuf;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CFixedVarBufferAllocator
|
|
//
|
|
// Purpose: fixed/var data allocator for byte buffer allocation.
|
|
//
|
|
// Notes: This allocator just carves pieces out of a data
|
|
// buffer and hands them out. It supports both fixed
|
|
// and variable data allocation, growing variable data
|
|
// downward from the end of the buffer.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CFixedVarBufferAllocator : public PFixedVarAllocator
|
|
{
|
|
public:
|
|
CFixedVarBufferAllocator (PVOID pBuf,
|
|
ULONG_PTR ulOffsetFixup,
|
|
size_t cbBuf,
|
|
size_t cbFixed,
|
|
size_t cbReserved = 0) :
|
|
_pBufferAddr( (BYTE *)pBuf ),
|
|
_pBaseOffset( (BYTE *)pBuf ),
|
|
_ulOffsetFixup( ulOffsetFixup ),
|
|
_pFixedBuf( (BYTE *)pBuf + cbReserved),
|
|
_pVarBuf( (BYTE *)pBuf + cbBuf),
|
|
_cbReserved( cbReserved ),
|
|
_cbFixed( cbFixed )
|
|
{
|
|
// make the variable allocations 8-byte aligned
|
|
while ( ( (ULONG_PTR) _pVarBuf ) & ( cbTblAllocAlignment - 1 ) )
|
|
_pVarBuf--;
|
|
}
|
|
|
|
// Allocate a piece of fixed memory.
|
|
PVOID AllocFixed();
|
|
|
|
// Allocate a piece of variable memory.
|
|
PVOID Allocate(ULONG cbNeeded);
|
|
|
|
// Free a previously allocated piece of memory (can't in a buffer).
|
|
void Free(PVOID pMem) {}
|
|
|
|
// Return whether OffsetToPointer has non-null effect
|
|
BOOL IsBasedMemory(void) { return _pBaseOffset != 0; }
|
|
|
|
// Convert a pointer offset to a pointer.
|
|
PVOID OffsetToPointer(TBL_OFF oBuf) {
|
|
return oBuf -
|
|
_ulOffsetFixup +
|
|
_pBaseOffset;
|
|
}
|
|
|
|
// Convert a pointer to a pointer offset.
|
|
TBL_OFF PointerToOffset(PVOID pBuf) {
|
|
return (BYTE *) pBuf -
|
|
_pBaseOffset +
|
|
_ulOffsetFixup;
|
|
}
|
|
|
|
// Set base address for OffsetToPointer and PointerToOffset
|
|
void SetBase(BYTE* pbBase) { _pBaseOffset = pbBase; }
|
|
|
|
// Return size of fixed data records
|
|
size_t FixedWidth() const { return _cbFixed; }
|
|
|
|
// Return the size of the reserved area
|
|
size_t GetReservedSize() const { return _cbReserved; }
|
|
|
|
// Return the base address of the reserved area
|
|
BYTE* BufferAddr() const { return _pBufferAddr; }
|
|
|
|
protected:
|
|
size_t _FreeSpace() { return (size_t)(_pVarBuf - _pFixedBuf); }
|
|
|
|
BYTE* _pBufferAddr; // Buffer base
|
|
BYTE* _pBaseOffset; // Buffer base for offset calculations
|
|
ULONG_PTR _ulOffsetFixup; // Client's version of the buffer base
|
|
BYTE* _pFixedBuf; // Buffer pointer for next fixed alloc.
|
|
BYTE* _pVarBuf; // Buffer pointer for next variable alloc.
|
|
size_t _cbFixed; // Size of fixed allocations
|
|
size_t _cbReserved; // Size of reserved area
|
|
};
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CFixedVarBufferAllocator::AllocFixed, inline
|
|
//
|
|
// Synopsis: Allocates a piece of fixed data out of a memory buffer
|
|
//
|
|
// Effects: updates _pFixedBuf
|
|
//
|
|
// Arguments: [cbNeeded] - number of byes of memory needed
|
|
//
|
|
// Returns: PVOID - a pointer to the allocated memory
|
|
//
|
|
// Signals: Throws STATUS_BUFFER_TOO_SMALL if not enough memory
|
|
// is available.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline PVOID CFixedVarBufferAllocator::AllocFixed()
|
|
{
|
|
BYTE* pRetBuf = _pFixedBuf;
|
|
|
|
if (_cbFixed <= _FreeSpace())
|
|
_pFixedBuf += _cbFixed;
|
|
else
|
|
QUIETTHROW( CException( STATUS_BUFFER_TOO_SMALL ) );
|
|
|
|
return pRetBuf;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CFixedVarBufferAllocator::Allocate, inline
|
|
//
|
|
// Synopsis: Allocates a piece of data out of a memory buffer
|
|
//
|
|
// Effects: updates _pVarBuf
|
|
//
|
|
// Arguments: [cbNeeded] - number of byes of memory needed
|
|
//
|
|
// Returns: PVOID - a pointer to the allocated memory
|
|
//
|
|
// Signals: Throws STATUS_BUFFER_TOO_SMALL if not enough memory
|
|
// is available.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline PVOID CFixedVarBufferAllocator::Allocate( ULONG cbNeeded )
|
|
{
|
|
// align to 8 byte boundry -- a little wasteful?
|
|
|
|
cbNeeded = _RoundUpToChunk( cbNeeded, cbTblAllocAlignment );
|
|
|
|
if (cbNeeded <= _FreeSpace())
|
|
_pVarBuf -= cbNeeded;
|
|
else
|
|
QUIETTHROW( CException( STATUS_BUFFER_TOO_SMALL ) );
|
|
|
|
return _pVarBuf;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CWindowDataAllocator
|
|
//
|
|
// Purpose: Data allocator for window variable data
|
|
//
|
|
// Interface: PVarAllocator
|
|
//
|
|
// Notes: This allocator manages a pool of pages as a simple
|
|
// heap.
|
|
//
|
|
// Data allocated out of the variable data space will
|
|
// be stored internally as offsets, so that the data may
|
|
// be moved around without need for adjusting pointers.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CWindowDataAllocator: public PVarAllocator
|
|
{
|
|
|
|
friend class CFixedVarAllocator; // for access to CHeapHeader
|
|
|
|
//
|
|
// Heap header used to record sizes of allocated and
|
|
// freed memory.
|
|
//
|
|
struct CHeapHeader {
|
|
|
|
USHORT cbSize; // size of this memory block
|
|
USHORT cbPrev; // size of preceeding mem. block
|
|
|
|
// the size of this struct needs to be 8-byte aligned.
|
|
ULONG _dummy;
|
|
|
|
// Flags or'ed with cbSize or cbPrev
|
|
enum EHeapFlags {
|
|
HeapFree = 1,
|
|
HeapEnd = 2,
|
|
HEAP_FLAGS = 3 // HeapFree | HeapEnd
|
|
};
|
|
|
|
USHORT Size(void) { return cbSize & ~HEAP_FLAGS; }
|
|
BOOL IsFree(void) { return cbSize & HeapFree; }
|
|
BOOL IsFirst(void) { return (cbPrev & HeapEnd) != 0; }
|
|
BOOL IsLast(void) { return (cbSize & HeapEnd) != 0; }
|
|
CHeapHeader* Next(void) { return IsLast() ? 0 :
|
|
(CHeapHeader*) (((BYTE *) this) + Size());
|
|
}
|
|
CHeapHeader* Prev(void) { return IsFirst() ? 0 :
|
|
(CHeapHeader*) (((BYTE *) this) -
|
|
(cbPrev & ~HEAP_FLAGS));
|
|
}
|
|
};
|
|
|
|
//
|
|
// Header used on each segment of arena to link them together
|
|
// and provide for offset mapping.
|
|
//
|
|
struct CSegmentHeader {
|
|
CSegmentHeader* pNextSegment; // linked list to other segments
|
|
ULONG oBaseOffset; // assigned offset for first memory
|
|
ULONG cbSize;
|
|
ULONG cbFree; // Free space in segment
|
|
};
|
|
|
|
public:
|
|
CWindowDataAllocator (ULONG* pcbPageTracker = &_cbPageTracker) :
|
|
_cbTotal( 0 ),
|
|
_pBaseAddr( 0 ),
|
|
_pcbPageUsed( pcbPageTracker ),
|
|
_oNextOffset( sizeof (TBL_PAGE_SIGNATURE ))
|
|
{ }
|
|
|
|
CWindowDataAllocator (PVOID pBuf,
|
|
size_t cbBuf,
|
|
CHeapHeader* pHeap = NULL,
|
|
ULONG* pcbPageTracker = &_cbPageTracker
|
|
) :
|
|
_cbTotal( 0 ),
|
|
_pBaseAddr( 0 ),
|
|
_pcbPageUsed( pcbPageTracker ),
|
|
_oNextOffset( sizeof (TBL_PAGE_SIGNATURE )) {
|
|
_SetArena(pBuf, cbBuf, pHeap, sizeof(TBL_PAGE_SIGNATURE));
|
|
}
|
|
|
|
~CWindowDataAllocator();
|
|
|
|
// Allocate a piece of memory.
|
|
PVOID Allocate(ULONG cbNeeded);
|
|
|
|
// Free a previously allocated piece of memory.
|
|
void Free(PVOID pMem);
|
|
|
|
// Return whether OffsetToPointer has non-null effect
|
|
BOOL IsBasedMemory(void) {
|
|
return TRUE;
|
|
}
|
|
|
|
// Convert a pointer offset to a pointer.
|
|
PVOID OffsetToPointer(TBL_OFF oBuf);
|
|
|
|
// Convert a pointer to a pointer offset.
|
|
TBL_OFF PointerToOffset(PVOID pBuf);
|
|
|
|
// Set base address for OffsetToPointer and PointerToOffset
|
|
void SetBase(BYTE* pbBase);
|
|
|
|
#if CIDBG
|
|
void WalkHeap(void (pfnReport)(PVOID pb, USHORT cb, USHORT f));
|
|
#endif
|
|
|
|
|
|
private:
|
|
// Set the limits of the allocation area.
|
|
void _SetArena( PVOID pBufBase,
|
|
size_t cbBuf,
|
|
CHeapHeader* pHeap = NULL,
|
|
ULONG oBuf = 0);
|
|
PVOID _SplitHeap(CSegmentHeader* pSegHdr,
|
|
CHeapHeader* pThisHeap,
|
|
size_t cbNeeded);
|
|
|
|
CSegmentHeader* _pBaseAddr; // pointer to first segment in arena
|
|
ULONG _oNextOffset; // next offset value to be assigned
|
|
size_t _cbTotal; // total size of allocation area
|
|
ULONG* _pcbPageUsed; // page usage tracking variable
|
|
static ULONG _cbPageTracker; // default page tracker
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CFixedVarAllocator
|
|
//
|
|
// Purpose: The ultimate data allocator. Supports fixed and
|
|
// variable memory allocations from the same segment.
|
|
// Automatically grows both fixed and variable allocations
|
|
// automatically.
|
|
// When memory usage grows beyond 1 page, fixed and
|
|
// variable allocations will be taken from separate
|
|
// segments.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CFixedVarAllocator: public PFixedVarAllocator
|
|
{
|
|
public:
|
|
CFixedVarAllocator (BOOL fGrowInitially,
|
|
BOOL fVarOffsets,
|
|
size_t cbDataWidth,
|
|
size_t cbReserved = 0) :
|
|
_fVarOffsets( fVarOffsets ),
|
|
_pbBaseAddr( NULL ),
|
|
_pbLastAddrPlusOne( NULL ),
|
|
_pbBuf( NULL ),
|
|
_cbBuf( 0 ),
|
|
_cbReserved( cbReserved ),
|
|
_cbDataWidth( cbDataWidth ),
|
|
_VarAllocator( NULL ),
|
|
_cbPageUsed( 0 ),
|
|
_cbTotal( 0 ),
|
|
_fDidReInit( FALSE )
|
|
{
|
|
if ( fGrowInitially )
|
|
_GrowData();
|
|
}
|
|
|
|
~CFixedVarAllocator ( );
|
|
|
|
void ReInit( BOOL fVarOffsets,
|
|
size_t cbReserved,
|
|
void * pvBuf,
|
|
ULONG cbBuf )
|
|
{
|
|
Win4Assert( ! _fDidReInit );
|
|
Win4Assert( 0 == _pbBaseAddr );
|
|
Win4Assert( 0 == _VarAllocator );
|
|
|
|
_cbPageUsed = cbBuf;
|
|
_cbReserved = cbReserved;
|
|
_fVarOffsets = fVarOffsets;
|
|
_pbBaseAddr = (BYTE *) pvBuf;
|
|
_pbLastAddrPlusOne = _pbBaseAddr + _cbBuf;
|
|
_fDidReInit = TRUE;
|
|
}
|
|
|
|
// Allocate a piece of fixed memory.
|
|
PVOID AllocFixed()
|
|
{
|
|
Win4Assert( ! _fDidReInit );
|
|
BYTE* pRetBuf;
|
|
|
|
if (_pbBaseAddr == NULL)
|
|
_GrowData();
|
|
|
|
if ( _cbDataWidth <= FreeSpace() )
|
|
{
|
|
pRetBuf = _pbBuf;
|
|
_pbBuf += _cbDataWidth;
|
|
return pRetBuf;
|
|
}
|
|
|
|
if (_cbDataWidth > FreeSpace() )
|
|
{
|
|
if (_cbTotal != _cbBuf)
|
|
_SplitData(TRUE);
|
|
else
|
|
_GrowData();
|
|
}
|
|
|
|
if ( _cbDataWidth <= FreeSpace() )
|
|
{
|
|
pRetBuf = _pbBuf;
|
|
_pbBuf += _cbDataWidth;
|
|
}
|
|
else
|
|
{
|
|
Win4Assert( !"unexpected out of memory" );
|
|
}
|
|
return pRetBuf;
|
|
}
|
|
|
|
// Return the size of the allocation unit
|
|
size_t FixedWidth() const { return _cbDataWidth; }
|
|
|
|
// Return the base address of the reserved area
|
|
BYTE* BufferAddr() const { return _pbBaseAddr; }
|
|
|
|
// Return the size of the reserved area
|
|
size_t GetReservedSize() const { return _cbReserved; }
|
|
|
|
// Convert an offset to a pointer
|
|
BYTE* FixedPointer( TBL_OFF obData ) const { return _pbBaseAddr+obData; }
|
|
|
|
// Convert an offset to a pointer
|
|
TBL_OFF FixedOffset( BYTE* pbData ) const { return pbData - _pbBaseAddr; }
|
|
|
|
// Return the base address of the allocation area
|
|
BYTE* FirstRow() const { return _pbBaseAddr + _cbReserved; }
|
|
|
|
// Set the size of the allocation unit
|
|
VOID SetRowSize(size_t cbDataWidth) { _cbDataWidth = cbDataWidth; }
|
|
|
|
// Set the size of the reserved area
|
|
VOID SetReservedSize(size_t cbReserved)
|
|
{
|
|
_cbReserved = cbReserved;
|
|
if (_pbBaseAddr == NULL)
|
|
_pbBuf = _pbBaseAddr + cbReserved;
|
|
}
|
|
|
|
// Resize the fixed portion of the buffer
|
|
void ResizeAndInitFixed( size_t cbDataWidth, ULONG cItems );
|
|
|
|
// Get a buffer for the specified number of fixed size allocations
|
|
void * AllocMultipleFixed( ULONG cItems );
|
|
|
|
// Allocate a piece of variable memory.
|
|
PVOID Allocate(ULONG cbNeeded);
|
|
|
|
// Free a previously allocated piece of memory.
|
|
void Free(PVOID pMem);
|
|
|
|
// Return whether OffsetToPointer has non-null effect
|
|
BOOL IsBasedMemory(void)
|
|
{
|
|
return _fVarOffsets;
|
|
}
|
|
|
|
// Set base address for OffsetToPointer and PointerToOffset
|
|
void SetBase(BYTE* pbBase)
|
|
{
|
|
if (pbBase == 0)
|
|
_fVarOffsets = FALSE;
|
|
else
|
|
Win4Assert( !"CFixedVarAllocator::SetBase not supported" );
|
|
}
|
|
|
|
// Convert a pointer offset to a pointer.
|
|
PVOID OffsetToPointer(TBL_OFF oBuf)
|
|
{
|
|
if (_fVarOffsets)
|
|
{
|
|
if (_VarAllocator)
|
|
return _VarAllocator->OffsetToPointer(oBuf);
|
|
else if ( _fDidReInit )
|
|
return _pbBaseAddr + oBuf;
|
|
else
|
|
return _pbBaseAddr + oBuf - sizeof (TBL_PAGE_SIGNATURE);
|
|
}
|
|
else
|
|
{
|
|
return (PVOID) oBuf;
|
|
}
|
|
}
|
|
|
|
// Convert a pointer to a pointer offset. Bias it so the offset
|
|
// adds easily with a page address.
|
|
TBL_OFF PointerToOffset(PVOID pBuf)
|
|
{
|
|
if (_fVarOffsets)
|
|
{
|
|
if (_VarAllocator)
|
|
return _VarAllocator->PointerToOffset(pBuf);
|
|
else if ( _fDidReInit )
|
|
return (BYTE *) pBuf - _pbBaseAddr;
|
|
else
|
|
return ((BYTE *)pBuf - _pbBaseAddr) + sizeof (TBL_PAGE_SIGNATURE);
|
|
}
|
|
else
|
|
{
|
|
return (TBL_OFF) pBuf;
|
|
}
|
|
}
|
|
|
|
// Return free space in buffer
|
|
size_t FreeSpace() const
|
|
{
|
|
return (_cbBuf - (UINT)(_pbBuf - _pbBaseAddr));
|
|
}
|
|
|
|
// Return total memory used
|
|
ULONG MemUsed( void ) { return _cbPageUsed; }
|
|
|
|
#if CIDBG
|
|
CWindowDataAllocator* VarAllocator(void) { return _VarAllocator; }
|
|
#endif
|
|
|
|
#ifdef CIEXTMODE
|
|
void CiExtDump(void *ciExtSelf);
|
|
#endif
|
|
|
|
protected:
|
|
size_t _cbTotal; // Total allocated size of _pbBaseAddr
|
|
ULONG _cbPageUsed; // Total memory used
|
|
|
|
private:
|
|
void _GrowData(size_t cbNeeded = 0);
|
|
void _SplitData(BOOL fMoveFixedData);
|
|
CWindowDataAllocator* _VarAllocator; // Var data allocator after split
|
|
BOOL _fVarOffsets; // offsets != pointers for var allocations
|
|
BOOL _fDidReInit; // hence the allocator is read-only and
|
|
// has one buffer for fixed & variable data
|
|
|
|
BYTE* _pbBaseAddr; // Bias for addresses
|
|
BYTE* _pbLastAddrPlusOne; // First byte past allocated memory
|
|
BYTE* _pbBuf; // Buffer base
|
|
size_t _cbBuf; // Available space in _pbBaseAddr
|
|
size_t _cbDataWidth; // Size of each allocated piece of memory
|
|
size_t _cbReserved; // Size of reserved area
|
|
};
|
|
|
|
class CFixedVarTableWindowAllocator: public PFixedVarAllocator
|
|
{
|
|
enum { cbFixedIncrement = 4096, cbVariableIncrement = 8192 };
|
|
|
|
public:
|
|
CFixedVarTableWindowAllocator() :
|
|
_cbFixedSize(0),
|
|
_cbFixedUsed(0),
|
|
_iCurVar(0),
|
|
_cbVarUsed(0)
|
|
{}
|
|
|
|
~CFixedVarTableWindowAllocator()
|
|
{
|
|
for ( unsigned i = 0; i < _aVariableBufs.Count(); i++ )
|
|
delete _aVariableBufs[i];
|
|
}
|
|
|
|
PVOID AllocFixed()
|
|
{
|
|
Win4Assert( _cbFixedSize <= cbFixedIncrement );
|
|
|
|
if ( ( _cbFixedSize + _cbFixedUsed ) > _aFixed.Count() )
|
|
_aFixed.ReSize( _aFixed.Count() + cbFixedIncrement );
|
|
|
|
void *pv = _aFixed.Get() + _cbFixedUsed;
|
|
_cbFixedUsed += _cbFixedSize;
|
|
return pv;
|
|
}
|
|
|
|
size_t FixedWidth() const { return _cbFixedSize; }
|
|
|
|
BYTE * BufferAddr() const { return _aFixed.Get(); }
|
|
|
|
size_t GetReservedSize() const { return 0; }
|
|
|
|
void ReInit( BOOL fVarOffsets,
|
|
size_t cbReserved,
|
|
void * pvBuf,
|
|
ULONG cbBuf ) { Win4Assert(!"Never called"); }
|
|
|
|
PVOID Allocate(ULONG cbNeeded)
|
|
{
|
|
cbNeeded = _RoundUpToChunk( cbNeeded, sizeof( double ) );
|
|
|
|
Win4Assert( cbNeeded <= cbVariableIncrement );
|
|
|
|
if ( 0 == _aVariableBufs.Count() )
|
|
{
|
|
XArray<BYTE> xTmp( cbVariableIncrement );
|
|
_aVariableBufs[0] = xTmp.Get();
|
|
xTmp.Acquire();
|
|
}
|
|
else if ( ( cbNeeded + _cbVarUsed ) > cbVariableIncrement )
|
|
{
|
|
_iCurVar = _aVariableBufs.Count();
|
|
XArray<BYTE> xTmp( cbVariableIncrement );
|
|
_aVariableBufs[_aVariableBufs.Count()] = xTmp.Get();
|
|
xTmp.Acquire();
|
|
_cbVarUsed = 0;
|
|
}
|
|
|
|
void * pv = _aVariableBufs[_iCurVar] + _cbVarUsed;
|
|
_cbVarUsed += cbNeeded;
|
|
return pv;
|
|
}
|
|
|
|
void Free(PVOID pMem) { Win4Assert( !"not called" ); }
|
|
|
|
BOOL IsBasedMemory(void) { return FALSE; }
|
|
|
|
PVOID OffsetToPointer(TBL_OFF oBuf) { return (PVOID) oBuf; }
|
|
|
|
TBL_OFF PointerToOffset(PVOID pBuf) { return (TBL_OFF) pBuf; }
|
|
|
|
void SetBase(BYTE* pbBase) {}
|
|
|
|
VOID SetRowSize(size_t cbDataWidth) { _cbFixedSize = cbDataWidth; }
|
|
|
|
BYTE * FixedPointer( TBL_OFF obData ) { return _aFixed.Get()+obData; }
|
|
|
|
TBL_OFF FixedOffset( BYTE* pbData ) { return pbData - _aFixed.Get(); }
|
|
|
|
ULONG MemUsed()
|
|
{
|
|
return _cbFixedUsed + _aVariableBufs.Count() * cbVariableIncrement;
|
|
}
|
|
|
|
BYTE * FirstRow() const { return _aFixed.Get(); }
|
|
|
|
private:
|
|
size_t _cbFixedSize;
|
|
size_t _cbFixedUsed;
|
|
XArray<BYTE> _aFixed;
|
|
|
|
unsigned _iCurVar;
|
|
unsigned _cbVarUsed;
|
|
CDynArrayInPlace<BYTE *> _aVariableBufs;
|
|
};
|
|
|