Files
Sun1602/Utility/SharedMemoryPool.cpp
2022-10-26 12:25:11 +08:00

1367 lines
55 KiB
C++

#include "UtilityCommon.h"
#include "SharedMemoryPool.h"
#include "LinkedListCS.h"
#include "../ProgramCommon/Version.h"
//==================================================================================================
// Name: SharedMemoryPool
// @history
// 07/09/07 - CheckIn (Waverix)
// 10/02/25 - remove macros '__NA000000_080816_EXSIZE_AND_MEMORY_OVERRUN_DETECT__'
// 10/02/25 - changes pool leak dectector to support common utility
// 10/05/10 - changes a coding style and
// adds a huge size memory tokenizing header which support a memory counter
// 10/05/19 - changed to first instancing approach based on singleton
// 10/05/26 - detached shared code block from template implements
// 11/07/05 - heap control extention and
// full streaming index calculation without the bytes alignment modification
// - upgrade to v0250, see the reference f110706.3L.
//==================================================================================================
#if USING_SUN_SHARED_POOL_REPORT
// 内存泄露检测工具/Release模式也可以检测
#define USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR (1)
#else
// 内存泄露检测工具/Release模式也可以检测
#define USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR (0)
#endif
BOOST_STATIC_ASSERT(SharedMemoryPool::kVersion == 0x0250);
//==================================================================================================
//
#define BUF_ALIGN_008(__size) (((__size)+((8)-1))&(~((8)-1)))
#define BUF_ALIGN_008_BY_IDX(__idx) ((__idx)<<3)
#define BUF_008_IDX_BY_SIZE(__size) ((__size)>>3)
#define BUF_ALIGN_016(__size) (((__size)+((16)-1))&(~((16)-1)))
#define BUF_ALIGN_016_BY_IDX(__idx) ((__idx)<<4) // 因为要计算8x,所以不能只使用这个。参考使用案例
#define BUF_016_IDX_BY_SIZE(__size) ((__size)>>4) // 上洞
#define BUF_ALIGN_032(__size) (((__size)+((32)-1))&(~((32)-1)))
#define BUF_ALIGN_032_BY_IDX(__idx) ((__idx)<<5) // 因为要计算16x,所以不能只使用这个。参考使用案例
#define BUF_032_IDX_BY_SIZE(__size) ((__size)>>5) //
#define BUF_ALIGN_064(__size) (((__size)+((64)-1))&(~((64)-1)))
#define BUF_ALIGN_064_BY_IDX(__idx) ((__idx)<<6) // 因为要进行64x的连续计算,所以不能只使用这个。参考使用案例
#define BUF_064_IDX_BY_SIZE(__size) ((__size)>>6) //
// reference pool
#define BUF_ALIGN_4096(__size) (((__size)+((4096)-1))&(~((4096)-1)))
#define BUF_4096_IDX_BY_SIZE(__size) ((__size)>>12)
#define BUF_ALIGN_1024x1024(__size) (((__size)+((1048576)-1))&(~((1048576)-1)))
#define BUF_1024x1024_IDX_BY_SIZE(__size) ((__size)>>20)
namespace util { namespace memory {
;
//==================================================================================================
struct SharedMemoryTable;
enum eCheckMemoryNodeResult
{
eError_NotDefined,
eError_Success_PoolManagedToken,
eError_Success_PoolUnmanagedToken,
eError_Fail_Null_Pointer,
eError_Unknown_HeapToken,
eError_Fail_BufferOverrunedToken, // not control
eError_Fail_CorruptedHeaderToken, // not control
};
//
struct SharedPoolVerifier
{
ulong verifier;
void* next;
};
//==================================================================================================
// NOTE: f110526.3L, f110513.7L, this class is used by SharedMemoryPoolNode<_size>
class SharedMemoryPoolSizeBased
{
public:
struct Token; // allocated/deallocated management
struct TokenBlock;// Token chunking
struct MemoryForUse; // support memory
struct MemoryBlockForUse; // memory chunking
//----------------------------------------------------------------------------------------------
static const uint16_t kMagicCodeAlloc = ('S') | ('A'<<8);
static const uint16_t kMagicCodeFree = ('s') | ('F'<<8);
static const uint16_t kMagicCodeTailConv = 0x0101; // kMagicCode(Alloc/Free) (+/-) this
//
union UsingTag
{
ulong composed;
struct {
uint16_t size; // requested size
uint16_t tag; // allocated or deallocated tag (magic key)
};
};
struct TokenVerifier
{
UsingTag using_tag;
Token* parent;
};
// allocated/deallocated management
struct Token : public util::__LList<Token>
{
UsingTag using_tag;
MemoryForUse* link;
const char* function;
int line_no;
int issued_number;
};
// Token chunking
struct TokenBlock : public util::__LList<TokenBlock>
{
#pragma warning(push)
#pragma warning(disable:4200)
Token stream[0];
#pragma warning(pop)
};
// support memory
struct MemoryForUse
{
TokenVerifier header[1];
// next specification
//uint8_t type_stream[type_size];
// ...
// TokenVerifier tail; // overrun check & comparison
};
struct MemoryBlockForUse : public util::__LList<MemoryBlockForUse>
{
#pragma warning(push)
#pragma warning(disable:4200)
MemoryForUse stream[0]; // (MemoryForUse + tail + alignment) * n
#pragma warning(pop)
};
//
struct Statistics {
size_t number_of_free_nodes;
size_t number_of_alloc_nodes;
size_t number_of_total_blocks;
size_t number_of_free_requested;
size_t number_of_alloc_requested;
};
//----------------------------------------------------------------------------------------------
SharedMemoryPoolSizeBased(); // not unused, brutely clread
SharedMemoryPoolSizeBased(size_t type_size, size_t chunk_size);
//~SharedMemoryPoolSizeBased(); <- not use destructor
void* Allocate(SharedMemoryTable* const table,
size_t requested_size, const char* name, const int line_no);
void Deallocate(SharedMemoryTable* const table, MemoryForUse* memory_for_use);
void FreeAllElements(SharedMemoryTable* const table);
//
const Statistics& GetStatistics() const;
static MemoryForUse* CheckNodeHeader(void* element, eCheckMemoryNodeResult* const result);
static size_t GetMaxMemoryForUseSize(size_t request_size);
private:
void AddBlock(SharedMemoryTable* const table);
//----------------------------------------------------------------------------------------------
// fields...
const size_t type_size_;
const size_t growth_count_; // page-fit
util::__LList<Token> free_list_;
util::__LList<Token> alloc_list_;
util::__LList<TokenBlock> total_list_;
util::__LList<MemoryBlockForUse> memory_list_;
Statistics statistics_;
//
friend struct SharedMemoryTable;
__DISABLE_COPY(SharedMemoryPoolSizeBased);
};
//==================================================================================================
struct SharedMemoryTable
{
enum ePoolIndex
{
kSizeIndex_None = 0,
// 8x based
kSizeIndex_0008, // very busible access, level 5
kSizeIndex_0016, // level 4
kSizeIndex_0024, // level 4
kSizeIndex_0032, // level 4
kSizeIndex_0040, // level 4
kSizeIndex_0048, // STLX_MAP, node size, level 2
kSizeIndex_0056,
kSizeIndex_0064,
kSizeIndex_0072,
kSizeIndex_0080,
kSizeIndex_0088,
kSizeIndex_0096,
kSizeIndex_0104,
kSizeIndex_0112,
kSizeIndex_0120,
kSizeIndex_0128,
// 32x based
kSizeIndex_0160,
kSizeIndex_0192, // level 3
kSizeIndex_0224,
kSizeIndex_0256,
// 64x based
kSizeIndex_0320,
kSizeIndex_0384,
kSizeIndex_0448,
kSizeIndex_0512,
// 128x based
kSizeIndex_0640, // SCItemSlot, level 4
kSizeIndex_0768,
kSizeIndex_0896,
kSizeIndex_1024,
kSizeIndex_1152,
kSizeIndex_1280, // STLX_HASH_MAP, bucket secondary extention, level 2
kSizeIndex_1408,
//
kSizeIndex_Counts,
};
enum ePoolInfo
{
//------------------------------
kSize008xUpperbound = 128,
kSize032xUpperbound = 256,
kSize064xUpperbound = 512,
kSize128xUpperbound = 1408,
kSizeOverUpperbound = kSize128xUpperbound,
kStreamingSizeCounts = int(kSizeOverUpperbound / 8) + 1, // 176 + 1
};
struct TokenSizeNode
{
uint16_t pool_index;
uint16_t token_size;
};
//----------------------------------------------------------------------------------------------
SharedMemoryTable();
~SharedMemoryTable();
//
void* Allocate(size_t size, const char* name, const int line_no);
void Deallocate(void* ptr);
//
bool ReportMemoryLeaks(const char* path_file_name);
bool ReportCurrentMemoryUsages();
static void TouchMemoryLeakReportFile(const char* path_file_name);
static void ReportRuntimeFailedObject(eCheckMemoryNodeResult error,
void* ptr, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use);
//----------------------------------------------------------------------------------------------
uint8_t padding0_[236];
int initialized_;
//HANDLE handle_token_block_;
//HANDLE handle_using_block_;
int issued_ordered_number_;
int reference_counter_;
TokenSizeNode index_by_size8x_[kStreamingSizeCounts];
uint8_t padding1_[60];
SharedMemoryPoolSizeBased size_pool_instance_[kSizeIndex_Counts];
uint8_t padding2_[256];
SharedMemoryPoolSizeBased::Statistics chunk_statistics_4096[256];
SharedMemoryPoolSizeBased::Statistics chunk_statistics_1024x1024[256];
//
};
//--------------------------------------------------------------------------------------------------
SharedMemoryPoolSizeBased::MemoryForUse* _CheckPoolUnmanagedHeap(
eCheckMemoryNodeResult* const result,
void* element, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use);
SharedMemoryPoolSizeBased::MemoryForUse* _CheckPoolManagedHeap(
eCheckMemoryNodeResult* const result,
void* element, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use);
}}; //end of namespace
//==================================================================================================
// static heap data
static void (*__fnSharedMemoryLeakDetect)(DWORD alloc_counter);
static void (*__fnSharedMemoryLeakCheck)();
static uint8_t shared_memory_pool_block[sizeof(SharedMemoryPool)];
static uint8_t shared_memory_table_block[sizeof(util::memory::SharedMemoryTable)];
//==================================================================================================
// implements
__forceinline util::memory::SharedMemoryPoolSizeBased::MemoryForUse*
util::memory::_CheckPoolUnmanagedHeap(util::memory::eCheckMemoryNodeResult* const result,
void* element, util::memory::SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use)
{
using namespace util::memory;
assert(memory_for_use->header->parent == element);
SharedMemoryPoolSizeBased::TokenVerifier tail_check =
*reinterpret_cast<SharedMemoryPoolSizeBased::TokenVerifier*>(\
reinterpret_cast<char*>(element) + memory_for_use->header->using_tag.composed);
//tail_check.using_tag.tag -= SharedMemoryPoolSizeBased::kMagicCodeTailConv;
if (memory_for_use->header->using_tag.composed == tail_check.using_tag.composed &&
memory_for_use->header->parent == tail_check.parent)
{
*result = eError_Success_PoolUnmanagedToken;
return memory_for_use;
}
else if (memory_for_use->header->parent != tail_check.parent)
{
*result = eError_Fail_BufferOverrunedToken;
return memory_for_use;
}
else //memory_for_use->header->using_tag.composed != tail_check->using_tag.composed
{ // ...
*result = eError_Fail_BufferOverrunedToken;
return memory_for_use;
}
}
__forceinline util::memory::SharedMemoryPoolSizeBased::MemoryForUse*
util::memory::_CheckPoolManagedHeap(util::memory::eCheckMemoryNodeResult* const result,
void* element, util::memory::SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use)
{
using namespace util::memory;
const SharedMemoryPoolSizeBased::UsingTag using_tag =
memory_for_use->header->using_tag;
if (using_tag.tag == util::memory::SharedMemoryPoolSizeBased::kMagicCodeAlloc ||
using_tag.tag == util::memory::SharedMemoryPoolSizeBased::kMagicCodeFree)
{
SharedMemoryPoolSizeBased::TokenVerifier tail_check =
*reinterpret_cast<SharedMemoryPoolSizeBased::TokenVerifier*>(\
reinterpret_cast<char*>(element) + using_tag.size);
tail_check.using_tag.tag -= SharedMemoryPoolSizeBased::kMagicCodeTailConv;
if (using_tag.composed == tail_check.using_tag.composed)
{
*result = eError_Success_PoolManagedToken;
return memory_for_use;
}
else
{
*result = eError_Fail_BufferOverrunedToken;
return memory_for_use;
};
}
else
{
*result = eError_Fail_CorruptedHeaderToken;
return memory_for_use;
};
}
util::memory::SharedMemoryPoolSizeBased::MemoryForUse*
util::memory::SharedMemoryPoolSizeBased::CheckNodeHeader(
void* element, eCheckMemoryNodeResult* const result)
{
MemoryForUse* memory_for_use = reinterpret_cast<MemoryForUse*>(element);
if (memory_for_use == NULL) {
*result = eError_Fail_Null_Pointer; // error: null pointer
return NULL;
};
--memory_for_use;
if (Token* parent = memory_for_use->header->parent)
{
if (parent == element)
{ // large size token, not managed in pool
return _CheckPoolUnmanagedHeap(result, element, memory_for_use);
}
else
{ // managed node in the size-based pool or normal heap containing corrupted header
return _CheckPoolManagedHeap(result, element, memory_for_use);
};
};
// error handling
*result = eError_Unknown_HeapToken; // error: unexpected pointer, can't control
return memory_for_use;
};
//==================================================================================================
// SharedMemoryPool implementations
//
#define SMPOOL_PTR() reinterpret_cast<SharedMemoryPool*>(shared_memory_pool_block)
#define CHECK_SMPOOL_INSTANCED() (SMPOOL_PTR()->instanced_tag_ == kInstancedTag)
#define SMROUTER_PTR(_pool_instance_) \
reinterpret_cast<util::memory::SharedMemoryTable*>((_pool_instance_)->inter_block_)
__forceinline SharedMemoryPool* SharedMemoryPool::Instance()
{
if (CHECK_SMPOOL_INSTANCED()) {
return SMPOOL_PTR();
};
SharedMemoryPool::CreateInstance();
return SMPOOL_PTR();
};
bool SharedMemoryPool::CreateInstance()
{
if (CHECK_SMPOOL_INSTANCED()) {
return true;
}
// initialize buffer block
new (shared_memory_pool_block) SharedMemoryPool;
return true;
}
bool SharedMemoryPool::CheckInstanced()
{
return CHECK_SMPOOL_INSTANCED();
}
void SharedMemoryPool::DestroyInstance()
{
SMPOOL_PTR()->~SharedMemoryPool();
*(ulong*)shared_memory_pool_block = 0x00011000; // released dummy value
}
SharedMemoryPool::SharedMemoryPool()
: instanced_tag_(kInstancedTag)
{
static bool initialized_static = false;
if (initialized_static == false)
{
ZeroMemory(shared_memory_table_block, sizeof(shared_memory_table_block));
inter_block_ = new (shared_memory_table_block) util::memory::SharedMemoryTable;
initialized_static = true;
};
}
SharedMemoryPool::~SharedMemoryPool()
{
static bool released_static = false;
if (released_static == false)
{
if (inter_block_)
{
SMROUTER_PTR(this)->~SharedMemoryTable();
inter_block_ = NULL;
}
released_static = true;
}
}
void* SharedMemoryPool::MemoryAllocate(size_t size, const char* name, const int line_no)
{
SharedMemoryPool* shared_memory_pool = SharedMemoryPool::Instance();
void* ptr = SMROUTER_PTR(shared_memory_pool)->Allocate(size, name, line_no);
return ptr;
}
void SharedMemoryPool::MemoryDeAllocate(void* ptr)
{
SharedMemoryPool* shared_memory_pool = SharedMemoryPool::Instance();
if ((ptr && shared_memory_pool) == false) {
return;
}
SMROUTER_PTR(shared_memory_pool)->Deallocate(ptr);
int reference_counter = SMROUTER_PTR(shared_memory_pool)->reference_counter_;
if (reference_counter < 2) {
SharedMemoryPool::DestroyInstance();
}
}
void* SharedMemoryPool::RedirectNew_MemoryAllocate(size_t size,
const char* name, const int line_no, SharedMemoryPool*)
{
static void* (*redirect_new_static)(size_t, const char*, const int) = \
&SharedMemoryPool::MemoryAllocate;
// same as MemoryAllocate
return (*redirect_new_static)(size, name, line_no);
}
void SharedMemoryPool::RedirectNew_MemoryDeallocate(void* ptr)
{
static void (*redirect_new_static)(void*) = &SharedMemoryPool::MemoryDeAllocate;
return (*redirect_new_static)(ptr);
}
// NOTE: f110708.5L, added the token validation routine
bool SharedMemoryPool::CheckValidAllocatedMemory(void* ptr)
{
SharedMemoryPool* shared_memory_pool = SharedMemoryPool::Instance();
if ((ptr && shared_memory_pool) == false) {
return false;
};
util::memory::eCheckMemoryNodeResult result = util::memory::eError_NotDefined;
util::memory::SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use = \
util::memory::SharedMemoryPoolSizeBased::CheckNodeHeader(ptr, &result);
__UNUSED(memory_for_use);
if (result == util::memory::eError_Success_PoolManagedToken ||
result == util::memory::eError_Success_PoolUnmanagedToken)
{
return true;
};
return false;
};
//==================================================================================================
//==================================================================================================
//==================================================================================================
util::memory::SharedMemoryPoolSizeBased::SharedMemoryPoolSizeBased()
: type_size_(0)
, growth_count_(0)
{
}
util::memory::SharedMemoryPoolSizeBased::SharedMemoryPoolSizeBased(
size_t type_size, size_t chunk_size)
: type_size_(type_size)
, growth_count_(chunk_size)
{
util::LList::Init(&free_list_);
util::LList::Init(&alloc_list_);
util::LList::Init(&total_list_);
util::LList::Init(&memory_list_);
}
void* util::memory::SharedMemoryPoolSizeBased::Allocate(SharedMemoryTable* const table,
size_t requested_size, const char* name, const int line_no)
{
if (util::LList::IsEmpty(&free_list_)) {
AddBlock(table);
};
Token* token = free_list_.next;
util::LList::Delete(token);
--statistics_.number_of_free_nodes;
//
token->function = name;
token->line_no = line_no;
token->issued_number = ++table->issued_ordered_number_;
if (TokenVerifier* verifier = token->link->header)
{
verifier->parent = token; // must be pre-checked
verifier->using_tag.size = static_cast<uint16_t>(requested_size);
verifier->using_tag.tag = this->kMagicCodeAlloc;
token->using_tag = verifier->using_tag;
};
uint8_t* ptr = reinterpret_cast<uint8_t*>(token->link->header + 1);
if (TokenVerifier* tail = reinterpret_cast<TokenVerifier*>(ptr + requested_size)) {
tail->parent = token;
tail->using_tag = token->using_tag;
tail->using_tag.tag += this->kMagicCodeTailConv;
};
util::LList::AddPrev(token, &alloc_list_);
++statistics_.number_of_alloc_nodes;
++statistics_.number_of_alloc_requested;
//
return ptr;
}
void util::memory::SharedMemoryPoolSizeBased::Deallocate(SharedMemoryTable* const table,
MemoryForUse* memory_for_use)
{
__UNUSED(table);
// validated memory_for_use
Token* const token = memory_for_use->header->parent;
if (token->link != memory_for_use ||
token->using_tag.composed != memory_for_use->header->using_tag.composed ||
token->using_tag.tag != this->kMagicCodeAlloc ||
util::LList::IsEmpty(&alloc_list_))
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
// memory leak occurrence
if (token->function != NULL && ::IsBadReadPtr(token->function, sizeof(char*))) {
token->function = NULL;
};
uint8_t* used_ptr = reinterpret_cast<uint8_t*>(memory_for_use->header + 1);
SUNLOG(eCRITICAL_LOG,
_T("|MemoryCheckReport|斤口=unexpected free operation")
_T("|MemInfo=size(%d), tag([%02X:%02X])|Suspicious Location='%s', %d lines")
_T("|Dump=[%02X][%02X][%02X][%02X]|"),
token->function, token->line_no,
token->using_tag.size,
(token->using_tag.tag & 0xFF), ((token->using_tag.tag >> 8) & 0xFF),
used_ptr[0], used_ptr[1], used_ptr[2], used_ptr[3]);
#endif
#ifdef _SERVER
assert(!"corrupted!");
#else
ASSERT(!"corrupted!");
#endif
return;
}
else
{ // validated memory
ulong* dest_it = reinterpret_cast<ulong*>(memory_for_use + 1);
const ulong* const dest_upperbound = &dest_it[this->type_size_ >> 2];
for (; dest_it < dest_upperbound; ++dest_it) {
*dest_it = 0xFEEEEEEE;
};
};
//----------------------------------------------------------------------------------------------
;{
util::LList::Delete(token);
--statistics_.number_of_alloc_nodes;
util::LList::AddPrev(token, &free_list_);
++statistics_.number_of_free_nodes;
//
++statistics_.number_of_free_requested;
};
//
if (UsingTag* tag = &token->using_tag) {
tag->composed = 0;
tag->tag = this->kMagicCodeFree;
};
}
__forceinline size_t
util::memory::SharedMemoryPoolSizeBased::GetMaxMemoryForUseSize(size_t request_size)
{
//assert(request_size != 0 && BUF_ALIGN_008(request_size) == request_size);
// header body tail
size_t block_size = sizeof(MemoryForUse) + BUF_ALIGN_008(request_size) + sizeof(TokenVerifier);
assert(block_size == BUF_ALIGN_008(block_size));
return block_size;
};
void util::memory::SharedMemoryPoolSizeBased::AddBlock(SharedMemoryTable* const table)
{
__UNUSED(table);
const size_t token_array_size = sizeof(TokenBlock) + (sizeof(Token) * growth_count_);
const size_t one_token_memory_for_use = GetMaxMemoryForUseSize(type_size_);
const size_t chunked_elements_size = sizeof(MemoryBlockForUse) +
(growth_count_ * one_token_memory_for_use);
//
TokenBlock* const block = (TokenBlock*)::HeapAlloc(\
::GetProcessHeap(), 0, token_array_size);
;{
ZeroMemory(block, token_array_size);
util::LList::Init(block);
util::LList::AddPrev(block, &total_list_);
++statistics_.number_of_total_blocks;
};
MemoryBlockForUse* const use_block = (MemoryBlockForUse*)::malloc(chunked_elements_size);
//(MemoryBlockForUse*)::HeapAlloc(table->handle_using_block_, 0, chunked_elements_size);
;{
util::LList::Init(use_block);
util::LList::AddPrev(use_block, &memory_list_);
// same 'statistics_.number_of_total_blocks'
};
Token* token = block->stream;
MemoryForUse* memory_for_use = use_block->stream;
#define NextMemoryForUse(__ptr__) \
reinterpret_cast<MemoryForUse*>(reinterpret_cast<uint8_t*>(__ptr__) + one_token_memory_for_use)
for (size_t i = 0; i < growth_count_;
++i, ++token, (memory_for_use = NextMemoryForUse(memory_for_use)))
{
// init tokens
util::LList::Init(token);
token->link = memory_for_use;
if (UsingTag* tag = &token->using_tag)
{
tag->composed = 0;
tag->tag = this->kMagicCodeFree;
memory_for_use->header->parent = token;
memory_for_use->header->using_tag = token->using_tag;
};
util::LList::AddPrev(token, &free_list_);
++statistics_.number_of_free_nodes;
};
}
#if _BUILD_FLAG_SHARED_MEMORY_NEWDEL_SYNC_CHECK_
void util::memory::SharedMemoryPoolSizeBased::DeadBeef(Element* element)
{
int* it = &element->deadBeef;
int* itend = (int*)((byte*)element + elementSize_);
while(it < itend)
*it++ = 0xDEADBEEF;
}
#endif
//------------------------------------------------------------------------------
// ()
// name:
// usage:
void util::memory::SharedMemoryPoolSizeBased::FreeAllElements(SharedMemoryTable* const table)
{
__UNUSED(table);
;{
size_t counter = 0;
TokenBlock* root = static_cast<TokenBlock*>(&total_list_);
TokenBlock* token = root->next;
while (token != root)
{
TokenBlock* next_token = util::LList::Delete(token);
::HeapFree(::GetProcessHeap(), 0, token);
token = next_token;
++counter;
};
ASSERT(statistics_.number_of_total_blocks == counter);
};
;{
size_t counter = 0;
MemoryBlockForUse* root = static_cast<MemoryBlockForUse*>(&memory_list_);
MemoryBlockForUse* token = root->next;
while (token != root)
{
MemoryBlockForUse* next_token = util::LList::Delete(token);
::free(token);
//::HeapFree(table->handle_using_block_, 0, token);
token = next_token;
++counter;
};
ASSERT(statistics_.number_of_total_blocks == counter);
};
ZeroMemory(&statistics_, sizeof(statistics_));
}
//==================================================================================================
//==================================================================================================
//==================================================================================================
void* util::memory::SharedMemoryTable::Allocate(
size_t requested_size, const char* name, const int line_no)
{
size_t resized = BUF_ALIGN_008(requested_size);
if (resized == 0) {
// NOTE: f110708.6L, some of applications has internal memory check routine
// that the size 0 test. for example, the DirectX 9.0c, 2006, Feb. version differ
// after version.
//assert(!"do you really want to require size 0 allocation?");
requested_size = 1;
resized = BUF_ALIGN_008(1);
};
void* allocated_ptr = NULL;
if (resized <= this->kSizeOverUpperbound)
{
size_t index = (resized >> 3);
if (const TokenSizeNode* pool_info = &this->index_by_size8x_[index]) {
index = pool_info->pool_index;
assert(pool_info->token_size == resized);
};
if (SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[index]) {
allocated_ptr = pool->Allocate(this, requested_size, name, line_no);
};
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
if (__fnSharedMemoryLeakDetect) {
__fnSharedMemoryLeakDetect(issued_ordered_number_);
};
#endif
}
else
{
size_t block_size = sizeof(SharedMemoryPoolSizeBased::MemoryForUse) +
BUF_ALIGN_008(requested_size) +
sizeof(SharedMemoryPoolSizeBased::TokenVerifier);
SharedMemoryPoolSizeBased::MemoryForUse* head_ptr = \
reinterpret_cast<SharedMemoryPoolSizeBased::MemoryForUse*>(::malloc(block_size));
if (head_ptr == NULL)
{
SUNLOG(eCRITICAL_LOG, "[%s:%d] malloc fail : %s, %d, size=%d",
__FUNCTION__, __LINE__, name, line_no, requested_size);
return NULL;
}
allocated_ptr = (uint8_t*)(head_ptr) + sizeof(*head_ptr);
if (SharedMemoryPoolSizeBased::TokenVerifier* header = head_ptr->header) {
header->parent = (SharedMemoryPoolSizeBased::Token*)(allocated_ptr);
header->using_tag.composed = static_cast<ulong>(requested_size);
};
if (SharedMemoryPoolSizeBased::TokenVerifier* tail =
reinterpret_cast<SharedMemoryPoolSizeBased::TokenVerifier*>(
(uint8_t*)(allocated_ptr) + requested_size))
{
*tail = *head_ptr->header;
};
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
const bool huge_chunk = (1024 * 1024) < block_size;
SharedMemoryPoolSizeBased::Statistics* statistic = NULL;
if (huge_chunk) {
size_t bound_index = BUF_1024x1024_IDX_BY_SIZE(block_size);
if (bound_index < _countof(chunk_statistics_1024x1024)) {
statistic = &chunk_statistics_1024x1024[bound_index];
}
}
else {
size_t bound_index = BUF_4096_IDX_BY_SIZE(block_size);
if (bound_index < _countof(chunk_statistics_4096)) {
statistic = &chunk_statistics_4096[bound_index];
}
};
if (statistic != NULL) {
++statistic->number_of_alloc_nodes;
++statistic->number_of_alloc_requested;
};
#endif
}
if (allocated_ptr) {
++reference_counter_;
if (reference_counter_ < 0) {
SUNLOG(eCRITICAL_LOG, "[%s:%d] reference_counter_ overflow accured",
__FUNCTION__, __LINE__);
}
};
return allocated_ptr;
}
void util::memory::SharedMemoryTable::Deallocate(void* element)
{
eCheckMemoryNodeResult result = util::memory::eError_NotDefined;
SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use = \
SharedMemoryPoolSizeBased::CheckNodeHeader(element, &result);
if (result == util::memory::eError_Success_PoolManagedToken)
{
size_t used_size = memory_for_use->header->using_tag.size;
size_t resized = BUF_ALIGN_008(used_size);
size_t index = (resized >> 3);
; index = this->index_by_size8x_[index].pool_index;
SharedMemoryPoolSizeBased* const pool = &this->size_pool_instance_[index];
pool->Deallocate(this, memory_for_use);
--reference_counter_;
return;
}
else if (result == util::memory::eError_Success_PoolUnmanagedToken)
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
size_t block_size = memory_for_use->header->using_tag.composed;
const bool huge_chunk = (1024 * 1024) < block_size;
SharedMemoryPoolSizeBased::Statistics* statistic = NULL;
if (huge_chunk) {
size_t bound_index = BUF_1024x1024_IDX_BY_SIZE(block_size);
if (bound_index < _countof(chunk_statistics_1024x1024)) {
statistic = &chunk_statistics_1024x1024[bound_index];
}
}
else {
size_t bound_index = BUF_4096_IDX_BY_SIZE(block_size);
if (bound_index < _countof(chunk_statistics_4096)) {
statistic = &chunk_statistics_4096[bound_index];
}
};
if (statistic != NULL) {
++statistic->number_of_free_nodes;
++statistic->number_of_free_requested;
};
#endif
--reference_counter_;
::free(memory_for_use);
return;
}
// error handling
this->ReportRuntimeFailedObject(result, element, memory_for_use);
__debugbreak();
}
//==================================================================================================
#define CALCULATE_PAGE_FIT_IN_INFO(__info__, __aligned_size__)
#define SM_NODE_LIST() \
/* 8x based */ \
SM_NODE_DECL(kSizeIndex_0008, 8, 8, 5290) /* 124K*/ \
SM_NODE_DECL(kSizeIndex_0016, 16, 16, 4905) /* 128K*/ \
SM_NODE_DECL(kSizeIndex_0024, 24, 24, 3174) /* 124K*/ \
SM_NODE_DECL(kSizeIndex_0032, 32, 32, 2645) /* 124K*/ \
SM_NODE_DECL(kSizeIndex_0040, 40, 40, 146) /* 8K*/ \
SM_NODE_DECL(kSizeIndex_0048, 48, 48, 127) /* 8K*/ \
SM_NODE_DECL(kSizeIndex_0056, 56, 56, 56) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0064, 64, 64, 51) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0072, 72, 72, 46) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0080, 80, 80, 213) /* 20K*/ \
SM_NODE_DECL(kSizeIndex_0088, 88, 88, 1142) /* 116K*/ \
SM_NODE_DECL(kSizeIndex_0096, 96, 96, 73) /* 8K*/ \
SM_NODE_DECL(kSizeIndex_0104, 104, 104, 34) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0112, 112, 112, 31) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0120, 120, 120, 30) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0128, 128, 128, 28) /* 4K*/ \
/* 32x based */ \
SM_NODE_DECL(kSizeIndex_0160, 160, 160, 93) /* 16K*/ \
SM_NODE_DECL(kSizeIndex_0192, 192, 192, 315) /* 64K*/ \
SM_NODE_DECL(kSizeIndex_0224, 224, 224, 17) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0256, 256, 256, 15) /* 4K*/ \
/* 64x based */ \
SM_NODE_DECL(kSizeIndex_0320, 320, 320, 12) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0384, 384, 384, 10) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0448, 448, 448, 8) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0512, 512, 512, 7) /* 4K*/ \
/* 128x based */ \
SM_NODE_DECL(kSizeIndex_0640, 640, 640, 231) /* 148K*/ \
SM_NODE_DECL(kSizeIndex_0768, 768, 768, 5) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_0896, 896, 896, 4) /* 4K*/ \
SM_NODE_DECL(kSizeIndex_1024, 1024, 1024, 63) /* 64K*/ \
SM_NODE_DECL(kSizeIndex_1152, 1152, 1152, 7) /* 8K*/ \
SM_NODE_DECL(kSizeIndex_1280, 1280, 1280, 22) /* 28K*/ \
SM_NODE_DECL(kSizeIndex_1408, 1408, 1408, 23) /* 32K*/
//==================================================================================================
util::memory::SharedMemoryTable::SharedMemoryTable()
{
//FitInPageInfo fitin_pageinfo;
memset(padding0_, 0xFF, sizeof(padding0_));
memset(padding1_, 0xCC, sizeof(padding1_));
memset(padding2_, 0xCD, sizeof(padding2_));
++issued_ordered_number_;
++reference_counter_;
BOOST_STATIC_ASSERT(kStreamingSizeCounts < 256);
BOOST_STATIC_ASSERT((BUF_ALIGN_008(0) == 0) && (BUF_ALIGN_008(1) == 8));
// NOTE: f110706.3L, create two private heaps to support 'TokenBlock' and 'memory token for use'
// the reason of using each separated heap protect the unexpected status
// of the 'memory token for use' like a buffer overrun.
;{
//this->handle_token_block_ = ::HeapCreate(0, 0, 0);
//assert(handle_token_block_ != INVALID_HANDLE_VALUE);
//this->handle_using_block_ = ::HeapCreate(0, 0, 0);
//assert(handle_using_block_ != INVALID_HANDLE_VALUE);
};
// start 0 size.
for (size_t token_size = 0; token_size <= kSizeOverUpperbound; (token_size += 8))
{
size_t array_index = (token_size >> 3);
if (token_size <= kSize008xUpperbound)
{
size_t recalc_size = token_size - 0;
index_by_size8x_[array_index].pool_index = static_cast<uint16_t>(recalc_size >> 3);
index_by_size8x_[array_index].token_size = static_cast<uint16_t>(token_size);
}
else if (token_size <= kSize032xUpperbound)
{
size_t recalc_size = token_size - kSize008xUpperbound;
index_by_size8x_[array_index].pool_index = static_cast<uint16_t>(\
(recalc_size >> 5) + ((recalc_size & (32 - 1)) ? 1 : 0) + kSizeIndex_0128);
index_by_size8x_[array_index].token_size = static_cast<uint16_t>(token_size);
}
else if (token_size <= kSize064xUpperbound)
{
size_t recalc_size = token_size - kSize032xUpperbound;
index_by_size8x_[array_index].pool_index = static_cast<uint16_t>(\
(recalc_size >> 6) + ((recalc_size & (64 - 1)) ? 1 : 0) + kSizeIndex_0256);
index_by_size8x_[array_index].token_size = static_cast<uint16_t>(token_size);
}
else if (token_size <= kSize128xUpperbound)
{
size_t recalc_size = token_size - kSize064xUpperbound;
index_by_size8x_[array_index].pool_index = static_cast<uint16_t>(\
(recalc_size >> 7) + ((recalc_size & (128 - 1)) ? 1 : 0) + kSizeIndex_0512);
index_by_size8x_[array_index].token_size = static_cast<uint16_t>(token_size);
}
};
assert(*(ulong*)padding0_ == 0xFFFFFFFF);
assert(*(ulong*)padding1_ == 0xCCCCCCCC);
assert(*(ulong*)padding2_ == 0xCDCDCDCD);
//
//----------------------------------------------------------------------------------------------
if (util::memory::SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[kSizeIndex_None])
{
// nothing to do
};
#undef SM_NODE_DECL
#define SM_NODE_DECL(_size_index_, _byte_alignment_size_, _dummy_, _growth_) \
if (util::memory::SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[_size_index_]) \
{ \
CALCULATE_PAGE_FIT_IN_INFO(&fitin_pageinfo, (_byte_alignment_size_)); \
new (pool) util::memory::SharedMemoryPoolSizeBased((_byte_alignment_size_), (_growth_)); \
};
//----------------------------------------------------------------------------------------------
SM_NODE_LIST(); // instance
//----------------------------------------------------------------------------------------------
this->initialized_ = true;
}
util::memory::SharedMemoryTable::~SharedMemoryTable()
{
this->initialized_ = false;
#undef SM_NODE_DECL
#define SM_NODE_DECL(_size_index_, _byte_alignment_size_, _dummy_, _growth_) \
if (util::memory::SharedMemoryPoolSizeBased* pool = &this->size_pool_instance_[_size_index_]) \
{ \
pool->FreeAllElements(this); \
};
//----------------------------------------------------------------------------------------------
SM_NODE_LIST(); // release
//----------------------------------------------------------------------------------------------
//if (this->handle_token_block_ != INVALID_HANDLE_VALUE) {
// ::HeapDestroy(this->handle_token_block_);
// this->handle_token_block_ = INVALID_HANDLE_VALUE;
//};
//if (this->handle_using_block_ != INVALID_HANDLE_VALUE) {
// ::HeapDestroy(this->handle_using_block_);
// this->handle_using_block_ = INVALID_HANDLE_VALUE;
//};
}
//==================================================================================================
void _SetSharedMemoryLeakDetect(void (*userhook)(DWORD))
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
__fnSharedMemoryLeakDetect = userhook;
return;
#else
__UNUSED(userhook);
#endif
}
void TestUnit_UsedLogOutput()
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
if (SharedMemoryPool::CheckInstanced() == false) {
return;
};
SharedMemoryPool* shared_memory_pool = SMPOOL_PTR();
SMROUTER_PTR(shared_memory_pool)->ReportCurrentMemoryUsages();
return;
#endif //
}
BOOL TraceShareMemoryLeak(const char* const path_file_name)
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
if (SharedMemoryPool::CheckInstanced() == false) {
util::memory::SharedMemoryTable::TouchMemoryLeakReportFile(path_file_name);
return true;
};
SharedMemoryPool* shared_memory_pool = SMPOOL_PTR();
return SMROUTER_PTR(shared_memory_pool)->ReportMemoryLeaks(path_file_name);
//
#else
__UNUSED(path_file_name);
return true;
#endif
}
void util::memory::SharedMemoryTable::ReportRuntimeFailedObject(eCheckMemoryNodeResult error,
void* ptr, SharedMemoryPoolSizeBased::MemoryForUse* memory_for_use)
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
switch (error)
{
case util::memory::eError_NotDefined:
ASSERT(!"unexpected error");
return;
case util::memory::eError_Success_PoolManagedToken:
case util::memory::eError_Success_PoolUnmanagedToken:
ASSERT(!"can't entered with this result");
return;
case util::memory::eError_Fail_Null_Pointer:
ASSERT(!"requested null pointer releasing");
return;
};
SharedMemoryPoolSizeBased::UsingTag verifier = memory_for_use->header->using_tag;
uint8_t* used_ptr = reinterpret_cast<uint8_t*>(ptr);
if ((error != util::memory::eError_Fail_BufferOverrunedToken) ||
(void*)memory_for_use->header->parent == used_ptr)
{
SUNLOG(eCRITICAL_LOG,
_T("|MemoryCheckReport|斤口=token validation error logging#1, Error(%d)")
_T("|MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)")
_T("|Dump=")
_T("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X|"),
error, memory_for_use, verifier.size,
(verifier.tag & 0xFF), ((verifier.tag >> 8) & 0xFF),
*(ulong*)memory_for_use,
used_ptr[ 0], used_ptr[ 1], used_ptr[ 2], used_ptr[ 3],
used_ptr[ 4], used_ptr[ 5], used_ptr[ 6], used_ptr[ 7],
used_ptr[ 8], used_ptr[ 9], used_ptr[10], used_ptr[11],
used_ptr[12], used_ptr[13], used_ptr[14], used_ptr[15]);
}
else
{
util::memory::SharedMemoryPoolSizeBased::Token* const token = memory_for_use->header->parent;
// ... dangerous...
SUNLOG(eCRITICAL_LOG,
_T("|MemoryCheckReport|斤口=token validation error logging#2, Error(%d)")
_T("|MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)")
_T("|Location='%s', %d lines|ExtraMsg='%s'")
_T("|Dump=")
_T("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X|"),
error, used_ptr, token->using_tag.size,
(token->using_tag.tag & 0xFF), ((token->using_tag.tag >> 8) & 0xFF),
*(ulong*)used_ptr,
token->function, token->line_no,
"suspicious buffer overrun object",
used_ptr[ 0], used_ptr[ 1], used_ptr[ 2], used_ptr[ 3],
used_ptr[ 4], used_ptr[ 5], used_ptr[ 6], used_ptr[ 7],
used_ptr[ 8], used_ptr[ 9], used_ptr[10], used_ptr[11],
used_ptr[12], used_ptr[13], used_ptr[14], used_ptr[15]);
}
assert(!"corrupted!");
return;
#else
__UNUSED((error, ptr, memory_for_use));
return;
#endif
}
void util::memory::SharedMemoryTable::TouchMemoryLeakReportFile(const char* path_file_name)
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
HANDLE file_handle = ::CreateFile(path_file_name,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
return;
};
::CloseHandle(file_handle);
return;
#else
__UNUSED(path_file_name);
return;
#endif
}
bool util::memory::SharedMemoryTable::ReportMemoryLeaks(const char* path_file_name)
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
const int kMaxOutputCounter = 100;
if (this->initialized_ == false) {
return true; // already free.
};
#if defined(_SERVER)
HANDLE file_handle = ::CreateFile(path_file_name,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
return false;
};
#endif
//
char buffer[4096];
DWORD file_written = 0;
int written = 0;
__TOUCHED((path_file_name, file_written));
SharedMemoryPoolSizeBased* pool_it = &this->size_pool_instance_[1]; // 0 is unused
const SharedMemoryPoolSizeBased* const pool_end =
&this->size_pool_instance_[_countof(this->size_pool_instance_)];
for (int counter = 0; pool_it != pool_end; ++pool_it)
{
util::__LList<SharedMemoryPoolSizeBased::Token>* const token_end = &pool_it->alloc_list_;
SharedMemoryPoolSizeBased::Token* token_it = pool_it->alloc_list_.next;
for (; token_it != token_end; token_it = token_it->next)
{
if (counter >= kMaxOutputCounter) {
buffer[written++] = '/';
buffer[written++] = '/';
};
//
SharedMemoryPoolSizeBased::MemoryForUse* const memory_for_use = token_it->link;
ulong* const used_ptr = reinterpret_cast<ulong*>(memory_for_use + 1);
uint8_t* const used_ptr_dump = reinterpret_cast<uint8_t*>(used_ptr);
SharedMemoryPoolSizeBased::TokenVerifier tail_tag = \
*reinterpret_cast<SharedMemoryPoolSizeBased::TokenVerifier*>(
used_ptr_dump + token_it->using_tag.size);
tail_tag.using_tag.tag -= SharedMemoryPoolSizeBased::kMagicCodeTailConv;
const bool matched_link = (token_it == memory_for_use->header->parent);
const bool matched_headtag = (token_it->using_tag.composed ==
memory_for_use->header->using_tag.composed);
const bool matched_tail = (token_it == tail_tag.parent) &&
(token_it->using_tag.composed == tail_tag.using_tag.composed);
if ((matched_headtag) && (matched_link) && (matched_tail))
{ // 000
written += _snprintf(&buffer[written], _countof(buffer) - written,
" case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg=(none)\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3]);
++counter;
}
else if ((matched_headtag) && (matched_link) && (!matched_tail))
{ // 001
written += _snprintf(&buffer[written], _countof(buffer) - written,
" case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3],
"suspicious buffer overrun object");
++counter;
}
else if ((matched_headtag) && (!matched_link) && (matched_tail))
{ // 010 -- very rarely
written += _snprintf(&buffer[written], _countof(buffer) - written,
"// case %8u: |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3],
"corrupted");
}
else if ((matched_headtag) && (!matched_link) && (!matched_tail))
{ // 011 -- very rarely
written += _snprintf(&buffer[written], _countof(buffer) - written,
" case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3],
"corrupted & overruned");
++counter;
}
else if ((!matched_headtag) && (matched_link) && (matched_tail))
{ // 100 -- rarely
written += _snprintf(&buffer[written], _countof(buffer) - written,
" case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3],
"may be overruned by previous token");
++counter;
}
else if ((!matched_headtag) && (matched_link) && (!matched_tail))
{ // 101 -- vary rarely
written += _snprintf(&buffer[written], _countof(buffer) - written,
" case %8u: // |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3],
"may be overruned by previous token and overruned");
++counter;
}
else if ((!matched_headtag) && (!matched_link) && (matched_tail))
{ // 110 -- rarely
written += _snprintf(&buffer[written], _countof(buffer) - written,
"// case %8u: |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3],
"may be overruned by previous token");
}
else if ((!matched_headtag) && (!matched_link) && (!matched_tail))
{ // 111 -- rarely
written += _snprintf(&buffer[written], _countof(buffer) - written,
"// case %8u: |MemInfo=ptr(0x%08X), size(%d), tag([%02X:%02X]), vft(0x%08X)|"
"Location='%s', %d lines|Dump=[%02X][%02X][%02X][%02X]|ExtraMsg='%s'\r\n",
token_it->issued_number, used_ptr, token_it->using_tag.size,
(token_it->using_tag.tag & 0xFF), ((token_it->using_tag.tag >> 8) & 0xFF),
*used_ptr,
token_it->function, token_it->line_no,
used_ptr_dump[0], used_ptr_dump[1], used_ptr_dump[2], used_ptr_dump[3],
"may be overruned by previous token, fully overruned");
}
//
#if defined(_SERVER)
::WriteFile(file_handle, buffer, written, &file_written, NULL);
#else
OutputDebugString(buffer);
#endif
written = 0;
//
};
};
#if defined(_SERVER)
::FlushFileBuffers(file_handle);
::CloseHandle(file_handle);
#endif
return true;
#else // !USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
__UNUSED(path_file_name);
return true;
#endif //
}
bool util::memory::SharedMemoryTable::ReportCurrentMemoryUsages()
{
#if USING_SUN_SHARED_MEMORY_POOL_LEAK_DETECTOR
if (this->initialized_ == false) {
return true; // already free.
};
HANDLE file_handle = ::CreateFile("./memory_usage.log",
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
return false;
};
//
char buffer[32768];
int written = 0;
SharedMemoryPoolSizeBased* pool_it = &this->size_pool_instance_[1]; // 0 is unused
const SharedMemoryPoolSizeBased* const pool_end =
&this->size_pool_instance_[_countof(this->size_pool_instance_)];
for (/*int counter = 0*/; pool_it != pool_end; ++pool_it)
{
const SharedMemoryPoolSizeBased::Statistics& statistics = pool_it->statistics_;
written += _snprintf(&buffer[written], _countof(buffer) - written,
"|TokenSize=[%4u]|TotalTokens=%8u"
"|NumberOfAllocated=%8u|NumberOfFreed=%8u"
"|NumberOfAllocRequest=%8u|NumberOfFreeRequest=%8u|\r\n",
pool_it->type_size_, statistics.number_of_total_blocks * pool_it->growth_count_,
statistics.number_of_alloc_nodes, statistics.number_of_free_nodes,
statistics.number_of_alloc_requested, statistics.number_of_free_requested);
};
DWORD file_written = 0;
::WriteFile(file_handle, buffer, written, &file_written, NULL);
//
;{
written = 0;
const SharedMemoryPoolSizeBased::Statistics* non_pool_it = this->chunk_statistics_4096,
* const non_pool_end = &this->chunk_statistics_4096[_countof(this->chunk_statistics_4096)];
for (; non_pool_it != non_pool_end; ++non_pool_it)
{
written += _snprintf(&buffer[written], _countof(buffer) - written,
"|NonPool|MaxSize=[%2uKBytes]|"
"|NumberOfAllocated=%8u|NumberOfFreed=%8u"
"|NumberOfAllocRequest=%8u|NumberOfFreeRequest=%8u|\r\n",
((static_cast<int>(non_pool_it - this->chunk_statistics_4096) + 1) * 4),
non_pool_it->number_of_alloc_nodes, non_pool_it->number_of_free_nodes,
non_pool_it->number_of_alloc_requested, non_pool_it->number_of_free_requested);
}
::WriteFile(file_handle, buffer, written, &file_written, NULL);
};
;{
written = 0;
const SharedMemoryPoolSizeBased::Statistics* non_pool_it = this->chunk_statistics_1024x1024,
* const non_pool_end = &this->chunk_statistics_1024x1024[\
_countof(this->chunk_statistics_1024x1024)];
for (; non_pool_it != non_pool_end; ++non_pool_it)
{
written += _snprintf(&buffer[written], _countof(buffer) - written,
"|NonPool|MaxSize=[%2uMBytes]|"
"|NumberOfAllocated=%8u|NumberOfFreed=%8u"
"|NumberOfAllocRequest=%8u|NumberOfFreeRequest=%8u|\r\n",
(static_cast<int>(non_pool_it - this->chunk_statistics_1024x1024) + 1),
non_pool_it->number_of_alloc_nodes, non_pool_it->number_of_free_nodes,
non_pool_it->number_of_alloc_requested, non_pool_it->number_of_free_requested);
}
::WriteFile(file_handle, buffer, written, &file_written, NULL);
};
::FlushFileBuffers(file_handle);
::CloseHandle(file_handle);
return true;
#else
return true;
#endif
}