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.

156 lines
4.9 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtSpareList.cpp
*
***/
#include "../Pch.h"
#pragma hdrstop
/****************************************************************************
*
* Exported functions
*
***/
//===========================================================================
CBaseSpareList::CBaseSpareList ()
: m_allocHead(nil),
m_spareHead(nil),
m_chunkSize(0)
{
#ifdef SPARELIST_TRACK_MEMORY
m_unfreedObjects = 0;
#endif
}
//===========================================================================
void * CBaseSpareList::Alloc (unsigned objectSize, const char typeName[]) {
// if there aren't any spare nodes available then make more
if (!m_spareHead)
GrowSpareList(objectSize, typeName);
// dequeue the head of the spare list
void * const object = m_spareHead;
m_spareHead = m_spareHead->spareNext;
#ifdef SPARELIST_TRACK_MEMORY
m_unfreedObjects++;
#endif
// initialize memory to a freaky value in debug mode
#ifdef HS_DEBUGGING
MemSet(object, (byte) ((unsigned) object >> 4), objectSize);
#endif
return object;
}
//===========================================================================
void CBaseSpareList::Free (void * object, unsigned objectSize) {
// initialize memory to a freaky value in debug mode
#ifdef HS_DEBUGGING
MemSet(object, (byte) ((unsigned) object >> 4), objectSize);
#else
ref(objectSize);
#endif
// link memory block onto head of spare list
((SpareNode *) object)->spareNext = m_spareHead;
m_spareHead = (SpareNode *) object;
#ifdef SPARELIST_TRACK_MEMORY
m_unfreedObjects--;
#endif
}
//===========================================================================
void CBaseSpareList::GrowSpareList (unsigned objectSize, const char typeName[]) {
// Grow the allocation by a substantial amount each time
// to reduce the time spent in memory managament
m_chunkSize *= 2;
const unsigned MIN_ALLOC = max(1, 256/objectSize);
const unsigned MAX_ALLOC = max(512, 32*1024/objectSize);
if (m_chunkSize < MIN_ALLOC)
m_chunkSize = MIN_ALLOC;
else if (m_chunkSize > MAX_ALLOC)
m_chunkSize = MAX_ALLOC;
// allocate a block of memory to hold a bunch
// of T-objects, but allocate them as "raw" memory
AllocNode * allocNode = (AllocNode *) MemAlloc(
sizeof(AllocNode) + objectSize * m_chunkSize,
0, // flags
typeName, // file
0 // line
);
// link allocation onto head of allocation list
allocNode->allocNext = m_allocHead;
m_allocHead = allocNode;
// chain newly created raw memory units together onto the spare list
SpareNode * spareCurr = (SpareNode *) (allocNode + 1);
SpareNode * spareEnd = (SpareNode *) ((byte *) spareCurr + objectSize * m_chunkSize);
do {
spareCurr->spareNext = m_spareHead;
m_spareHead = spareCurr;
spareCurr = (SpareNode *) ((byte *) spareCurr + objectSize);
} while (spareCurr < spareEnd);
}
//===========================================================================
void CBaseSpareList::CleanUp (const char typeName[]) {
// warn of resource leaks
#ifdef SPARELIST_TRACK_MEMORY
if (m_unfreedObjects && !ErrorGetOption(kErrOptDisableMemLeakChecking)) {
#ifdef CLIENT
{
char buffer[256];
StrPrintf(buffer, arrsize(buffer), "Memory leak: %s", typeName);
FATAL(buffer);
}
#else
{
DEBUG_MSG("Memory leak: %s", typeName);
}
#endif
}
#else
ref(typeName);
#endif
// walk chain of AllocNodes and free each of them
while (m_allocHead) {
AllocNode * allocNext = m_allocHead->allocNext;
FREE(m_allocHead);
m_allocHead = allocNext;
}
m_spareHead = nil;
}