Leaked source code of windows server 2003
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.
 
 
 
 
 
 

498 lines
10 KiB

/*
* M E M X . H
*
* Default implementation of DAV allocators.
*
* It is possible that sometime in the future we may decide that different
* implementations of DAV may require different allocator implementations,
* so each DAV implementation has its own allocator implementation file
* (mem.cpp) in its own directory. However, until we need to differentiate
* allocator implementations among DAV implementations (if we ever do),
* it is easier to have the common default implementation in one place -- here.
*
* This header defines a full implementation for a fast heap allocator
* and implementations for other allocators that can be used for debugging.
* This file should be included exactly once by mem.cpp in each DAV implementation.
*
* To use the virtual heap allocator set:
*
* [General]
* UseVirtual=1
*
* Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
*/
#include <singlton.h>
#include <except.h>
// ===================================================================================
//
// IHeap
//
// Heap interface base class.
//
class IHeap
{
public:
// CREATORS
//
virtual ~IHeap() = 0;
// ACCESSORS
//
virtual LPVOID Alloc( SIZE_T cb ) const = 0;
virtual LPVOID Realloc( LPVOID lpv, SIZE_T cb ) const = 0;
virtual VOID Free( LPVOID pv ) const = 0;
};
// ------------------------------------------------------------------------
//
// IHeap::~IHeap()
//
// Out of line virtual destructor necessary for proper deletion
// of objects of derived classes via this class
//
IHeap::~IHeap() {}
// ===================================================================================
//
// CMultiHeap
//
// Multi-heap implementation (provided by STAXMEM.DLL). It is significantly
// faster than the process heap on multiprocessor machines because it uses
// multiple internal heaps, lookaside lists and deferred freeing to reduce
// contention on system heap critical sections.
//
class CMultiHeap :
public IHeap,
private Singleton<CMultiHeap>
{
//
// Friend declarations required by Singleton template
//
friend class Singleton<CMultiHeap>;
typedef HANDLE (WINAPI *HEAPCREATE) (
ULONG cHeaps,
DWORD dwFlags,
SIZE_T dwInitialSize,
SIZE_T dwMaxSize );
typedef BOOL (WINAPI *HEAPDESTROY) ();
typedef LPVOID (WINAPI *HEAPALLOC) (
SIZE_T dwSize );
typedef LPVOID (WINAPI *HEAPREALLOC) (
LPVOID pvOld,
SIZE_T dwSize );
typedef BOOL (WINAPI *HEAPFREE) (
LPVOID pvFree );
//
// Allocation functions
//
HEAPCREATE m_HeapCreate;
HEAPDESTROY m_HeapDestroy;
HEAPALLOC m_HeapAlloc;
HEAPREALLOC m_HeapRealloc;
HEAPFREE m_HeapFree;
// CREATORS
//
// Declared private to ensure that arbitrary instances
// of this class cannot be created. The Singleton
// template (declared as a friend above) controls
// the sole instance of this class.
//
CMultiHeap() :
m_HeapCreate(NULL),
m_HeapDestroy(NULL),
m_HeapAlloc(NULL),
m_HeapRealloc(NULL),
m_HeapFree(NULL)
{
}
// MANIPULATORS
//
BOOL FInit();
public:
// STATICS
//
static CMultiHeap * New();
// CREATORS
//
~CMultiHeap();
// ACCESSORS
//
LPVOID Alloc( SIZE_T cb ) const;
LPVOID Realloc( LPVOID lpv, SIZE_T cb ) const;
VOID Free( LPVOID pv ) const;
};
CMultiHeap *
CMultiHeap::New()
{
if ( CreateInstance().FInit() )
return &Instance();
DestroyInstance();
return NULL;
}
BOOL
CMultiHeap::FInit()
{
//
// Load up STAXMEM.DLL - or whatever
//
HINSTANCE hinst = LoadLibraryExW( g_szMemDll, NULL, 0 );
if ( !hinst )
return FALSE;
//
// Get the function pointers for the multi-heap implementation
//
m_HeapCreate = reinterpret_cast<HEAPCREATE>(
GetProcAddress( hinst, "ExchMHeapCreate" ));
m_HeapDestroy = reinterpret_cast<HEAPDESTROY>(
GetProcAddress( hinst, "ExchMHeapDestroy" ));
m_HeapAlloc = reinterpret_cast<HEAPALLOC>(
GetProcAddress( hinst, "ExchMHeapAlloc" ));
m_HeapRealloc = reinterpret_cast<HEAPREALLOC>(
GetProcAddress( hinst, "ExchMHeapReAlloc" ));
m_HeapFree = reinterpret_cast<HEAPFREE>(
GetProcAddress( hinst, "ExchMHeapFree" ));
//
// Make sure we found all of the entrypoints
//
if ( !(m_HeapCreate &&
m_HeapDestroy &&
m_HeapAlloc &&
m_HeapRealloc &&
m_HeapFree) )
{
return FALSE;
}
//
// Create the multi-heap. We don't need the heap HANDLE
// that is returned since none of the allocation functions
// take it. We just need to know whether it succeeded.
//
return !!m_HeapCreate( 0, // number of heaps -- 0 means use a default
// proportional to the number of CPUs.
0, // no flags
8192, // initially 8K (growable)
0 ); // size unlimited
}
CMultiHeap::~CMultiHeap()
{
if ( m_HeapDestroy )
m_HeapDestroy();
}
LPVOID
CMultiHeap::Alloc( SIZE_T cb ) const
{
return m_HeapAlloc( cb );
}
LPVOID
CMultiHeap::Realloc( LPVOID lpv, SIZE_T cb ) const
{
return m_HeapRealloc( lpv, cb );
}
void
CMultiHeap::Free( LPVOID lpv ) const
{
m_HeapFree( lpv );
}
//
// Debug-only allocators...
//
#if defined(DBG)
// ===================================================================================
//
// CVirtualHeap (X86 only)
//
// Places allocations at the end of virtual memory pages.
// While being drastically slower than other allocators,
// this one catches memory overwrites immediately by
// throwing a memory access violation exception.
//
#if defined(_X86_)
class CVirtualHeap :
public IHeap,
private Singleton<CVirtualHeap>
{
//
// Friend declarations required by Singleton template
//
friend class Singleton<CVirtualHeap>;
// CREATORS
//
// Declared private to ensure that arbitrary instances
// of this class cannot be created. The Singleton
// template (declared as a friend above) controls
// the sole instance of this class.
//
CVirtualHeap() {}
public:
// STATICS
//
static CVirtualHeap * New()
{
return &CreateInstance();
}
// ACCESSORS
//
LPVOID Alloc( SIZE_T cb ) const
{
return VMAlloc( cb );
}
LPVOID Realloc( LPVOID lpv, SIZE_T cb ) const
{
return VMRealloc( lpv, cb );
}
VOID Free( LPVOID lpv ) const
{
VMFree( lpv );
}
};
#endif // defined(_X86)
#endif // DBG
// ===================================================================================
//
// CHeapImpl
//
// Top-level heap implementation
//
class CHeapImpl : private RefCountedGlobal<CHeapImpl>
{
//
// Friend declarations required by RefCountedGlobal template
//
friend class Singleton<CHeapImpl>;
friend class RefCountedGlobal<CHeapImpl>;
//
// Pointer to the object that provides our heap implementation
//
auto_ptr<IHeap> m_pHeapImpl;
// CREATORS
//
// Declared private to ensure that arbitrary instances
// of this class cannot be created. The Singleton
// template (declared as a friend above) controls
// the sole instance of this class.
//
CHeapImpl() {}
// NOT IMPLEMENTED
//
CHeapImpl( const CHeapImpl& );
CHeapImpl& operator=( const CHeapImpl& );
//
// Initialization routine called
// by the RefCountedGlobal template
//
BOOL FInit()
{
//
// And bind to a particular heap implementation
//
// In DBG builds only, check whether we are being told
// to use the virtual allocator heap implementation
//
#if defined(DBG)
#if defined(_X86_)
if ( GetPrivateProfileIntA( gc_szDbgGeneral,
gc_szDbgUseVirtual,
FALSE,
gc_szDbgIni ) )
{
m_pHeapImpl = CVirtualHeap::New();
}
else
#endif // defined(_X86_)
#endif // DBG
m_pHeapImpl = CMultiHeap::New();
return !!m_pHeapImpl;
}
public:
using RefCountedGlobal<CHeapImpl>::DwInitRef;
using RefCountedGlobal<CHeapImpl>::DeinitRef;
static IHeap& Heap()
{
Assert( Instance().m_pHeapImpl.get() != NULL );
return *Instance().m_pHeapImpl;
}
};
// ===================================================================================
//
// CHeap
//
// Top-level heap.
//
// This "class" (it's actually a struct) really only acts as a namespace.
// I.e. its only members are static functions. It remains a class for
// historical reasons (mainly to avoid changing a LOT of code from calling
// "g_heap.Fn()" to simply calling "Fn()").
//
BOOL
CHeap::FInit()
{
return !!CHeapImpl::DwInitRef();
}
void
CHeap::Deinit()
{
CHeapImpl::DeinitRef();
}
LPVOID
CHeap::Alloc( SIZE_T cb )
{
LPVOID lpv;
Assert( cb > 0 );
lpv = CHeapImpl::Heap().Alloc(cb);
#ifndef _NOTHROW_
if ( !lpv )
{
DebugTrace ("CHeap::Alloc() - Error allocating (%d)\n", GetLastError());
throw CLastErrorException();
}
#endif // _NOTHROW_
return lpv;
}
LPVOID
CHeap::Realloc( LPVOID lpv, SIZE_T cb )
{
LPVOID lpvNew;
Assert( cb > 0 );
// Just in case some heap implementation doesn't handle
// realloc with NULL lpv, map that case to Alloc here.
//
if (!lpv)
lpvNew = CHeapImpl::Heap().Alloc(cb);
else
lpvNew = CHeapImpl::Heap().Realloc(lpv, cb);
#ifndef _NOTHROW_
if ( !lpvNew )
{
DebugTrace ("CHeap::Alloc() - Error reallocating (%d)\n", GetLastError());
throw CLastErrorException();
}
#endif // _NOTHROW_
return lpvNew;
}
VOID
CHeap::Free( LPVOID lpv )
{
if ( lpv )
{
CHeapImpl::Heap().Free( lpv );
}
}
//
// The one global heap "object". CHeap is really just a struct
// containing only static member functions, so there should be
// no space required for this declaration. The actual heap
// implementation (CHeapImpl) provides everything. CHeap is
// now just an interface.
//
CHeap g_heap;
// ------------------------------------------------------------------------
//
// Global new operator
// Global delete operator
//
// Remap all calls to new to use our memory manager.
// (Don't forget to throw explicitly on error!)
//
void * __cdecl operator new(size_t cb)
{
#ifdef DBG
AssertSz(cb, "Zero-size allocation detecetd!");
// Force small allocations up to min size of four
// so that I can reliably do the "vtable-nulling trick" in delete!
//
if (cb < 4) cb = 4;
#endif // DBG
PVOID pv = g_heap.Alloc(cb);
#ifndef _NOTHROW_
if (!pv)
throw CDAVException();
#endif // _NOTHROW_
return pv;
}
void __cdecl operator delete(void * pv)
{
#ifdef DBG
// Zero-out the first four bytes of this allocation.
// (If there was a vtable there previously, we'll now trap
// if we try to use it!)
//
if (pv)
*((DWORD *)pv) = 0;
#endif // DBG
g_heap.Free(pv);
}