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.
 
 
 
 
 
 

829 lines
23 KiB

/***************************************************************************\
*
* File: SimpleHelp.cpp
*
* Description:
* SimpleHeap.cpp implements the heap operations used throughout DirectUser.
*
*
* History:
* 11/26/1999: JStall: Created
*
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
*
\***************************************************************************/
#include "stdafx.h"
#include "Base.h"
#include "SimpleHeap.h"
#include "List.h"
#include "Locks.h"
DWORD g_tlsHeap = (DWORD) -1;
HANDLE g_hHeap = NULL;
DUserHeap * g_pheapProcess;
/***************************************************************************\
*****************************************************************************
*
* class DUserHeap
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
DUserHeap::DUserHeap()
{
m_cRef = 1;
}
//------------------------------------------------------------------------------
void
DUserHeap::Lock()
{
SafeIncrement(&m_cRef);
}
//------------------------------------------------------------------------------
BOOL
DUserHeap::Unlock()
{
AssertMsg(m_cRef > 0, "Must have an outstanding referenced");
if (SafeDecrement(&m_cRef) == 0) {
placement_delete(this, DUserHeap);
HeapFree(g_hHeap, 0, this);
return FALSE; // Heap is no longer valid
}
return TRUE; // Heap is still valid
}
#ifdef _DEBUG // Needs DEBUG CRT's
/***************************************************************************\
*****************************************************************************
*
* class CrtDbgHeap
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
class CrtDbgHeap : public DUserHeap
{
// Construction
public:
virtual ~CrtDbgHeap();
// Operations
public:
virtual void * Alloc(SIZE_T cbSize, bool fZero DBG_HEAP_PARAMS);
virtual void * Realloc(void * pvMem, SIZE_T cbNewSize DBG_HEAP_PARAMS);
virtual void MultiAlloc(int * pnActual, void * prgAlloc[], int cItems, SIZE_T cbSize DBG_HEAP_PARAMS);
virtual void Free(void * pvMem);
virtual void MultiFree(int cItems, void * prgAlloc[], SIZE_T cbSize);
};
//------------------------------------------------------------------------------
CrtDbgHeap::~CrtDbgHeap()
{
}
//------------------------------------------------------------------------------
void *
CrtDbgHeap::Alloc(SIZE_T cbSize, bool fZero DBG_HEAP_PARAMS)
{
void * pvMem = _malloc_dbg(cbSize, _NORMAL_BLOCK, pszFileName, idxLineNum);
if ((pvMem != NULL) && fZero) {
ZeroMemory(pvMem, cbSize);
}
return pvMem;
}
//------------------------------------------------------------------------------
void *
CrtDbgHeap::Realloc(void * pvMem, SIZE_T cbNewSize DBG_HEAP_PARAMS)
{
void * pvNewMem = _realloc_dbg(pvMem, cbNewSize, _NORMAL_BLOCK, pszFileName, idxLineNum);
return pvNewMem;
}
//------------------------------------------------------------------------------
void
CrtDbgHeap::MultiAlloc(int * pnActual, void * prgAlloc[], int cItems, SIZE_T cbSize DBG_HEAP_PARAMS)
{
int idx = 0;
while (idx < cItems) {
prgAlloc[idx] = _malloc_dbg(cbSize, _NORMAL_BLOCK, pszFileName, idxLineNum);
if (prgAlloc[idx] == NULL) {
break;
}
idx++;
}
*pnActual = idx;
}
//------------------------------------------------------------------------------
void
CrtDbgHeap::Free(void * pvMem)
{
_free_dbg(pvMem, _NORMAL_BLOCK);
}
//------------------------------------------------------------------------------
void
CrtDbgHeap::MultiFree(int cItems, void * prgAlloc[], SIZE_T cbSize)
{
UNREFERENCED_PARAMETER(cbSize);
for (int idx = 0; idx < cItems; idx++) {
_free_dbg(prgAlloc[idx], _NORMAL_BLOCK);
}
}
#endif // _DEBUG
/***************************************************************************\
*****************************************************************************
*
* class NtHeap
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
class NtHeap : public DUserHeap
{
// Construction
public:
inline NtHeap();
virtual ~NtHeap();
HRESULT Create(BOOL fSerialize);
inline void Destroy();
inline void Attach(HANDLE hHeap, BOOL fPassOwnership);
inline HANDLE Detach();
// Operations
public:
virtual void * Alloc(SIZE_T cbSize, bool fZero DBG_HEAP_PARAMS);
virtual void * Realloc(void * pvMem, SIZE_T cbNewSize DBG_HEAP_PARAMS);
virtual void MultiAlloc(int * pnActual, void * prgAlloc[], int cItems, SIZE_T cbSize DBG_HEAP_PARAMS);
virtual void Free(void * pvMem);
virtual void MultiFree(int cItems, void * prgAlloc[], SIZE_T cbSize);
// Implementation
protected:
inline DWORD GetFlags(DWORD dwExtra = 0) const;
// Data
protected:
HANDLE m_hHeap;
BOOL m_fOwnHeap:1;
BOOL m_fSerialize:1;
};
//------------------------------------------------------------------------------
inline
NtHeap::NtHeap()
{
m_hHeap = NULL;
m_fOwnHeap = FALSE;
m_fSerialize = FALSE;
}
//------------------------------------------------------------------------------
NtHeap::~NtHeap()
{
Destroy();
}
//------------------------------------------------------------------------------
HRESULT
NtHeap::Create(BOOL fSerialize)
{
AssertMsg(m_hHeap == NULL, "Can not re-create heap");
m_hHeap = HeapCreate(fSerialize ? 0 : HEAP_NO_SERIALIZE, 256 * 1024, 0);
if (m_hHeap != NULL) {
m_fOwnHeap = TRUE;
m_fSerialize = fSerialize;
}
return m_hHeap != NULL ? S_OK : E_OUTOFMEMORY;
}
//------------------------------------------------------------------------------
inline void
NtHeap::Destroy()
{
if (m_fOwnHeap && (m_hHeap != NULL)) {
HeapDestroy(m_hHeap);
m_hHeap = NULL;
m_fOwnHeap = FALSE;
m_fSerialize = FALSE;
}
}
//------------------------------------------------------------------------------
inline void
NtHeap::Attach(HANDLE hHeap, BOOL fPassOwnership)
{
AssertMsg(hHeap != NULL, "Must specify valid heap");
AssertMsg(m_hHeap == NULL, "Can re-attach heap");
m_hHeap = hHeap;
m_fOwnHeap = fPassOwnership;
m_fSerialize = TRUE;
}
//------------------------------------------------------------------------------
inline HANDLE
NtHeap::Detach()
{
HANDLE hHeap = m_hHeap;
m_hHeap = NULL;
m_fOwnHeap = FALSE;
m_fSerialize = FALSE;
return hHeap;
}
//------------------------------------------------------------------------------
inline DWORD
NtHeap::GetFlags(DWORD dwExtra) const
{
return dwExtra | (m_fSerialize ? 0 : HEAP_NO_SERIALIZE);
}
//------------------------------------------------------------------------------
void *
NtHeap::Alloc(SIZE_T cbSize, bool fZero DBG_HEAP_PARAMS)
{
DBG_HEAP_USE;
return HeapAlloc(m_hHeap, GetFlags(fZero ? HEAP_ZERO_MEMORY : 0), cbSize);
}
//------------------------------------------------------------------------------
void *
NtHeap::Realloc(void * pvMem, SIZE_T cbNewSize DBG_HEAP_PARAMS)
{
DBG_HEAP_USE;
DWORD dwFlags = GetFlags(HEAP_ZERO_MEMORY);
if (pvMem == NULL) {
return HeapAlloc(m_hHeap, dwFlags, cbNewSize);
} else {
return HeapReAlloc(m_hHeap, dwFlags, pvMem, cbNewSize);
}
}
//------------------------------------------------------------------------------
void
NtHeap::MultiAlloc(int * pnActual, void * prgAlloc[], int cItems, SIZE_T cbSize DBG_HEAP_PARAMS)
{
DBG_HEAP_USE;
DWORD dwFlags = GetFlags();
int idx = 0;
while (idx < cItems) {
prgAlloc[idx] = HeapAlloc(m_hHeap, dwFlags, cbSize);
if (prgAlloc[idx] == NULL) {
break;
}
idx++;
}
*pnActual = idx;
}
//------------------------------------------------------------------------------
void
NtHeap::Free(void * pvMem)
{
if (pvMem != NULL) {
HeapFree(m_hHeap, 0, pvMem);
}
}
//------------------------------------------------------------------------------
void
NtHeap::MultiFree(int cItems, void * prgAlloc[], SIZE_T cbSize)
{
UNREFERENCED_PARAMETER(cbSize);
DWORD dwFlags = GetFlags(0);
for (int idx = 0; idx < cItems; idx++) {
if (prgAlloc[idx] != NULL) {
HeapFree(m_hHeap, dwFlags, prgAlloc[idx]);
}
}
}
/***************************************************************************\
*****************************************************************************
*
* class RockAllHeap
*
*****************************************************************************
\***************************************************************************/
#if USE_ROCKALL
#include <Rockall.hpp>
#pragma comment(lib, "RAHeap.lib")
#pragma comment(lib, "RALibrary.lib")
#pragma comment(lib, "Rockall.lib")
//------------------------------------------------------------------------------
class RockAllHeap : public DUserHeap
{
// Construction
public:
RockAllHeap(BOOL fSerialize);
HRESULT Create();
// Operations
public:
virtual void * Alloc(SIZE_T cbSize, bool fZero DBG_HEAP_PARAMS);
virtual void * Realloc(void * pvMem, SIZE_T cbNewSize DBG_HEAP_PARAMS);
virtual void MultiAlloc(int * pnActual, void * prgAlloc[], int cItems, SIZE_T cbSize DBG_HEAP_PARAMS);
virtual void Free(void * pvMem);
virtual void MultiFree(int cItems, void * prgAlloc[], SIZE_T cbSize);
// Implementation
protected:
class CustomHeap : public ROCKALL
{
// Construction
public:
CustomHeap(bool ThreadSafe=true, int MaxFreeSpace=4194304, bool Recycle=true, bool SingleImage=false);
};
// Data
protected:
CustomHeap m_heap;
};
//------------------------------------------------------------------------------
RockAllHeap::RockAllHeap(BOOL fSerialize) : m_heap(!!fSerialize)
{
}
//------------------------------------------------------------------------------
HRESULT
RockAllHeap::Create()
{
return m_heap.Corrupt() ? E_OUTOFMEMORY : S_OK;
}
//------------------------------------------------------------------------------
void *
RockAllHeap::Alloc(SIZE_T cbSize, bool fZero DBG_HEAP_PARAMS)
{
DBG_HEAP_USE;
return m_heap.New(cbSize, NULL, fZero);
}
//------------------------------------------------------------------------------
void *
RockAllHeap::Realloc(void * pvMem, SIZE_T cbNewSize DBG_HEAP_PARAMS)
{
DBG_HEAP_USE;
return m_heap.Resize(pvMem, cbNewSize);
}
//------------------------------------------------------------------------------
void
RockAllHeap::MultiAlloc(int * pnActual, void * prgAlloc[], int cItems, SIZE_T cbSize DBG_HEAP_PARAMS)
{
DBG_HEAP_USE;
m_heap.MultipleNew(pnActual, prgAlloc, cItems, cbSize, NULL, false);
}
//------------------------------------------------------------------------------
void
RockAllHeap::Free(void * pvMem)
{
m_heap.Delete(pvMem);
}
//------------------------------------------------------------------------------
void
RockAllHeap::MultiFree(int cItems, void * prgAlloc[], SIZE_T cbSize)
{
m_heap.MultipleDelete(cItems, prgAlloc, cbSize);
}
const int FindCacheSize = 4096;
const int FindCacheThreshold = 0;
const int FindSize = 2048;
const int Stride1 = 8;
const int Stride2 = 1024;
/********************************************************************/
/* */
/* The description of the heap. */
/* */
/* A heap is a collection of fixed sized allocation caches. */
/* An allocation cache consists of an allocation size, the */
/* number of pre-built allocations to cache, a chunk size and */
/* a parent page size which is sub-divided to create elements */
/* for this cache. A heap consists of two arrays of caches. */
/* Each of these arrays has a stride (i.e. 'Stride1' and */
/* 'Stride2') which is typically the smallest common factor of */
/* all the allocation sizes in the array. */
/* */
/********************************************************************/
//
// NOTE: DUser needs to ensure that all memory is allocated on 8 byte
// boundaries. This is used be several external components, including
// S-Lists. To ensure this, the smallest "Bucket Size" must be >= 8 bytes.
//
static ROCKALL::CACHE_DETAILS Caches1[] =
{
//
// Bucket Size Of Bucket Parent
// Size Cache Chunks Page Size
//
{ 16, 128, 4096, 4096 },
{ 24, 64, 4096, 4096 },
{ 32, 64, 4096, 4096 },
{ 40, 256, 4096, 4096 },
{ 64, 256, 4096, 4096 },
{ 80, 256, 4096, 4096 },
{ 128, 32, 4096, 4096 },
{ 256, 16, 4096, 4096 },
{ 512, 4, 4096, 4096 },
{ 0,0,0,0 }
};
static ROCKALL::CACHE_DETAILS Caches2[] =
{
//
// Bucket Size Of Bucket Parent
// Size Cache Chunks Page Size
//
{ 1024, 16, 4096, 4096 },
{ 2048, 16, 4096, 4096 },
{ 3072, 4, 65536, 65536 },
{ 4096, 8, 65536, 65536 },
{ 5120, 4, 65536, 65536 },
{ 6144, 4, 65536, 65536 },
{ 7168, 4, 65536, 65536 },
{ 8192, 8, 65536, 65536 },
{ 9216, 0, 65536, 65536 },
{ 10240, 0, 65536, 65536 },
{ 12288, 0, 65536, 65536 },
{ 16384, 2, 65536, 65536 },
{ 21504, 0, 65536, 65536 },
{ 32768, 0, 65536, 65536 },
{ 65536, 0, 65536, 65536 },
{ 65536, 0, 65536, 65536 },
{ 0,0,0,0 }
};
/********************************************************************/
/* */
/* The description bit vectors. */
/* */
/* All heaps keep track of allocations using bit vectors. An */
/* allocation requires 2 bits to keep track of its state. The */
/* following array supplies the size of the available bit */
/* vectors measured in 32 bit words. */
/* */
/********************************************************************/
static int NewPageSizes[] = { 1,4,16,64,128,0 };
//------------------------------------------------------------------------------
RockAllHeap::CustomHeap::CustomHeap(bool ThreadSafe, int MaxFreeSpace, bool Recycle, bool SingleImage) :
ROCKALL(Caches1, Caches2, FindCacheSize, FindCacheThreshold, FindSize,
MaxFreeSpace, NewPageSizes, Recycle, SingleImage,
Stride1, Stride2, ThreadSafe)
{
}
#endif // USE_ROCKALL
//------------------------------------------------------------------------------
HRESULT
CreateProcessHeap()
{
AssertMsg(g_pheapProcess == NULL, "Only should init process heap once");
g_tlsHeap = TlsAlloc();
if (g_tlsHeap == (DWORD) -1) {
return E_OUTOFMEMORY;
}
g_hHeap = GetProcessHeap();
DUserHeap * pNewHeap;
#ifdef _DEBUG
pNewHeap = (DUserHeap *) HeapAlloc(g_hHeap, 0, sizeof(CrtDbgHeap));
#else
pNewHeap = (DUserHeap *) HeapAlloc(g_hHeap, 0, sizeof(NtHeap));
#endif
if (pNewHeap == NULL) {
return E_OUTOFMEMORY;
}
#ifdef _DEBUG
placement_new(pNewHeap, CrtDbgHeap);
#else
placement_new(pNewHeap, NtHeap);
((NtHeap *) pNewHeap)->Attach(g_hHeap, FALSE /* Don't pass ownership */);
#endif
g_pheapProcess = pNewHeap;
return S_OK;
}
//------------------------------------------------------------------------------
void
DestroyProcessHeap()
{
if (g_pheapProcess != NULL) {
g_pheapProcess->Unlock();
g_pheapProcess = NULL;
}
if (g_tlsHeap == (DWORD) -1) {
TlsFree(g_tlsHeap);
g_tlsHeap = (DWORD) -1;
}
g_hHeap = NULL;
}
/***************************************************************************\
*
* CreateContextHeap
*
* CreateContextHeap() initializes the thread-specific heap to either an
* existing heap or a new heap. All threads in the same Context should be
* initialized with the same heap so that they can safely shared data between
* threads. When the Context is finally destroyed, call DestroyContextHeap()
* to cleanup the heap.
*
\***************************************************************************/
HRESULT
CreateContextHeap(
IN DUserHeap * pLinkHeap, // Existing heap to share
IN BOOL fThreadSafe, // Heap mode
IN DUserHeap::EHeap id, // Heap type
OUT DUserHeap ** ppNewHeap) // New heap (OPTIONAL)
{
HRESULT hr;
if (ppNewHeap != NULL) {
*ppNewHeap = NULL;
}
//
// Check if a heap already exists.
//
// NOTE: This will occur on the starting thread because the initial heap
// must be initialized so that we can create new objects.
//
DUserHeap * pNewHeap = reinterpret_cast<DUserHeap *> (TlsGetValue(g_tlsHeap));
if (pNewHeap == NULL) {
if (pLinkHeap == NULL) {
//
// Need to create a new heap.
//
switch (id)
{
case DUserHeap::idProcessHeap:
case DUserHeap::idNtHeap:
pNewHeap = (DUserHeap *) HeapAlloc(g_hHeap, 0, sizeof(NtHeap));
break;
#ifdef _DEBUG
case DUserHeap::idCrtDbgHeap:
pNewHeap = (DUserHeap *) HeapAlloc(g_hHeap, 0, sizeof(CrtDbgHeap));
break;
#endif
#if USE_ROCKALL
case DUserHeap::idRockAllHeap:
pNewHeap = (DUserHeap *) HeapAlloc(g_hHeap, 0, sizeof(RockAllHeap));
break;
#endif
default:
AssertMsg(0, "Unknown heap type");
}
if (pNewHeap == NULL) {
return E_OUTOFMEMORY;
}
hr = E_FAIL;
switch (id)
{
case DUserHeap::idProcessHeap:
placement_new(pNewHeap, NtHeap);
((NtHeap *) pNewHeap)->Attach(g_hHeap, FALSE /* Don't pass ownership */);
hr = S_OK;
break;
case DUserHeap::idNtHeap:
placement_new(pNewHeap, NtHeap);
hr = ((NtHeap *) pNewHeap)->Create(fThreadSafe);
break;
#ifdef _DEBUG
case DUserHeap::idCrtDbgHeap:
placement_new(pNewHeap, CrtDbgHeap);
hr = S_OK;
break;
#endif
#if USE_ROCKALL
case DUserHeap::idRockAllHeap:
placement_new1(pNewHeap, RockAllHeap, fThreadSafe);
hr = ((RockAllHeap *) pNewHeap)->Create();
break;
#endif
default:
AssertMsg(0, "Unknown heap type");
}
if (FAILED(hr)) {
pNewHeap->Unlock();
return hr;
}
} else {
pLinkHeap->Lock();
pNewHeap = pLinkHeap;
}
Verify(TlsSetValue(g_tlsHeap, pNewHeap));
}
if (ppNewHeap != NULL) {
*ppNewHeap = pNewHeap;
}
return S_OK;
}
/***************************************************************************\
*
* DestroyContextHeap
*
* DestroyContextHeap() frees resources used by a Context's shared heap.
*
\***************************************************************************/
void
DestroyContextHeap(
IN DUserHeap * pHeapDestroy) // Heap to destroy
{
if (pHeapDestroy != NULL) {
pHeapDestroy->Unlock();
}
DUserHeap * pHeap = reinterpret_cast<DUserHeap *> (TlsGetValue(g_tlsHeap));
if (pHeapDestroy == pHeap) {
Verify(TlsSetValue(g_tlsHeap, NULL));
}
}
/***************************************************************************\
*
* ForceSetContextHeap
*
* ForceSetContextHeap() is called during shutdown when it is necessary to
* "force" the current thread to use a different thread's heap so that the
* objects can be properly destroyed.
*
* NOTE: This function must be VERY carefully called since it directly
* changes the heap for a thread. It should only be called from the
* ResourceManager when destroying threads.
*
\***************************************************************************/
void
ForceSetContextHeap(
IN DUserHeap * pHeapThread) // Heap to use on this Thread
{
Verify(TlsSetValue(g_tlsHeap, pHeapThread));
}
#if DBG
//------------------------------------------------------------------------------
void
DumpData(
IN void * pMem,
IN int nLength)
{
int row = 4;
char * pszData = (char *) pMem;
int cbData = min(16, nLength);
int cbTotal = 0;
//
// For each row, we will dump up to 16 characters in both hexidecimal
// and if an actual character, their displayed character.
//
while ((row-- > 0) && (cbTotal < nLength)) {
int cb = cbData;
char * pszDump = pszData;
Trace("0x%p: ", pszData);
int cbTemp = cbTotal;
while (cb-- > 0) {
cbTemp++;
if (cbTemp > nLength) {
Trace(" ");
} else {
Trace("%02x ", (unsigned char) (*pszDump++));
}
}
Trace(" ");
cb = cbData;
while (cb-- > 0) {
char ch = (unsigned char) (*pszData++);
Trace("%c", IsCharAlphaNumeric(ch) ? ch : '.');
cbTotal++;
if (cbTotal > nLength) {
break;
}
}
Trace("\n");
}
Trace("\n");
}
#endif // DBG