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
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
|