povray/windows/pvmem.cpp
2013-11-06 13:07:19 -05:00

459 lines
10 KiB
C++

/*******************************************************************************
* pvmem.cpp
*
* This module implements windows-specific memory handling routines.
*
* Author: Christopher J. Cason.
*
* ---------------------------------------------------------------------------
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
*
* POV-Ray is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* POV-Ray 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ---------------------------------------------------------------------------
* POV-Ray is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
* ---------------------------------------------------------------------------
* $File: //depot/public/povray/3.x/windows/pvmem.cpp $
* $Revision: #1 $
* $Change: 6069 $
* $DateTime: 2013/11/06 11:59:40 $
* $Author: chrisc $
*******************************************************************************/
#define POVWIN_FILE
#define _WIN32_IE COMMONCTRL_VERSION
#include <windows.h>
#include <crtdbg.h>
#include <errno.h>
#include <assert.h>
#include "pvengine.h"
#ifdef _DEBUG
#define EXTRA_VALIDATION 1
#else
#define EXTRA_VALIDATION 0
#endif
#include "pvmem.h"
// this must be the last file included
#include "syspovdebug.h"
extern "C"
{
int __cdecl WinMainCRTStartup();
}
#undef new
#undef delete
using namespace pov_base;
namespace povwin
{
bool TrackMem;
__int64 PeakMem;
static WinHeap *gHeap = NULL;
WinHeap *WinMemBlock::m_Heap = NULL;
static WinMemStats gMemStats;
__declspec(thread) static WinMemStats *lMemStats = NULL;
#if POV_MEM_STATS == 0 && WIN_MEM_TRACKING == 0
int __cdecl POVWINStartup()
{
return WinMainCRTStartup();
}
void *win_malloc(size_t size)
{
void *result = malloc(size);
if (result == NULL)
throw std::bad_alloc();
return result;
}
void *win_malloc(size_t size, const void *data, int line)
{
void *result = malloc(size);
if (result == NULL)
throw std::bad_alloc();
return result;
}
void *win_calloc(size_t nelem, size_t size)
{
void *result = calloc(nelem, size);
if (result == NULL)
throw std::bad_alloc();
return result;
}
void *win_calloc(size_t nelem, size_t size, const void *data, int line)
{
void *result = calloc(nelem, size);
if (result == NULL)
throw std::bad_alloc();
return result;
}
void *win_realloc(void *p, size_t size)
{
void *result = realloc(p, size);
if (result == NULL)
throw std::bad_alloc();
return result;
}
void *win_realloc(void *p, size_t size, const void *data, int line)
{
void *result = realloc(p, size);
if (result == NULL)
throw std::bad_alloc();
return result;
}
void win_free(void *p)
{
free(p);
}
void win_free(void *p, const void *data, int line)
{
free(p);
}
char *win_strdup(const char *s)
{
char *result = _strdup(s);
if (result == NULL)
throw std::bad_alloc();
return result;
}
char *win_strdup(const char *s, const void *data, int line)
{
char *result = _strdup(s);
if (result == NULL)
throw std::bad_alloc();
return result;
}
void WinMemStage(bool BeginRender, void *cookie)
{
if (BeginRender)
{
PeakMem = 0;
TrackMem = true;
}
else
TrackMem = false;
}
bool WinMemReport(bool global, uint64& allocs, uint64& frees, int64& current, uint64& peak, uint64 &smallest, uint64 &largest)
{
if (!global)
return false;
allocs = frees = current = smallest = largest = 0;
peak = PeakMem;
return true;
}
void WinMemThreadStartup()
{
}
void WinMemThreadCleanup()
{
}
#else
// This function is the first called when POVWIN starts (even before the CRT startup code).
// Therefore we can't count on very much being set up for us.
int __cdecl POVWINStartup()
{
// note that WinHeap has its own operator new.
gHeap = new WinHeap;
if (gHeap == NULL || gHeap->Validate() == false)
{
// not safe to call MessageBox here due to some other threads getting fired up
// MessageBox(GetDesktopWindow(), "Failed to set up private heap - POV-Ray will now exit", "POV-Ray for Windows", MB_OK | MB_ICONERROR);
return 1;
}
WinMemBlock::SetAllocator(gHeap);
// we never delete gHeap since WinMainCRTStartup() often exits via means other than a return.
return WinMainCRTStartup();
}
void WinMemThreadStartup()
{
lMemStats = new WinMemStats();
}
void WinMemThreadCleanup()
{
delete lMemStats;
}
bool WinMemReport(bool global, uint64& allocs, uint64& frees, int64& current, uint64& peak, uint64 &smallest, uint64 &largest)
{
HeapLock lock(gHeap);
allocs = frees = current = peak = smallest = largest = 0;
if (global)
{
gMemStats.Report(allocs, frees, current, peak, smallest, largest);
return true;
}
if (lMemStats == NULL)
return false;
lMemStats->Report(allocs, frees, current, peak, smallest, largest);
return true;
}
void WinMemStage(bool BeginRender, void *cookie)
{
HeapLock lock(gHeap);
if (BeginRender)
gMemStats.Clear();
}
#ifdef _DEBUG
void *win_malloc(size_t size, const void *data, int line)
{
HeapLock lock(gHeap);
// note that WinMemBlock has its own operator new
WinMemBlock *block = new (size) WinMemBlock(data, line);
if (block == NULL)
throw std::bad_alloc();
gMemStats.RecordAlloc(block->Size(size));
return block->GetMem();
}
void *win_realloc(void *p, size_t newSize, const void *data, int line)
{
if (p == NULL)
return win_malloc(newSize, data, line);
if (newSize != 0)
{
HeapLock lock(gHeap);
size_t oldSize;
WinMemBlock *block = WinMemBlock::GetBlock(p);
if ((block == NULL) || ((oldSize = block->Size()) == (size_t) -1))
throw POV_EXCEPTION(kCannotHandleDataErr, "Bad memory block in realloc()");
if ((block = block->Realloc(newSize, data, line)) == NULL)
throw std::bad_alloc();
gMemStats.RecordFree(oldSize);
gMemStats.RecordAlloc(block->Size(newSize));
return block->GetMem();
}
else
{
win_free(p, data, line);
return NULL;
}
}
void win_free(void *p, const void *data, int line)
{
if (p == NULL)
return;
HeapLock lock(gHeap);
size_t size;
WinMemBlock *block = WinMemBlock::GetBlock(p);
if ((block == NULL) || ((size = block->Size()) == (size_t) -1))
throw POV_EXCEPTION(kCannotHandleDataErr, "Bad memory block in free()");
gMemStats.RecordFree(size);
// note that WinMemBlock has a private delete operator
delete block;
}
void *win_calloc(size_t nelem, size_t size, const void *data, int line)
{
size_t count = size * nelem;
void *p = win_malloc(count, data, line);
if (p == NULL)
throw std::bad_alloc();
memset(p, 0, count);
return p;
}
char *win_strdup(const char *s, const void *data, int line)
{
char *p = (char *) win_malloc(strlen(s) + 1, data, line);
strcpy(p, s);
return p;
}
#else // _DEBUG
// release-mode functions
void *win_malloc(size_t size)
{
HeapLock lock(gHeap);
void *p = gHeap->Alloc(size);
if (p == NULL)
throw std::bad_alloc();
return p;
}
void *win_realloc(void *p, size_t size)
{
if (p == NULL)
return win_malloc(size);
if (size == 0)
{
win_free(p);
return NULL;
}
HeapLock lock(gHeap);
size_t currentSize = gHeap->BlockSize(p);
if (currentSize == (size_t) -1)
throw POV_EXCEPTION(kCannotHandleDataErr, "Bad memory block in realloc()");
void *newBlock = gHeap->ReAlloc(p, size);
if (newBlock == NULL)
{
// this can happen with the low-fragmentation heap, even if memory is available
// as long as it's a shrink, we return the original pointer
if (size < currentSize)
return p;
throw std::bad_alloc();
}
gMemStats.RecordFree(currentSize);
gMemStats.RecordAlloc(size);
return newBlock;
}
void win_free(void *p)
{
if (p == NULL)
return;
HeapLock lock(gHeap);
size_t len = gHeap->BlockSize(p);
if (len == (size_t) -1)
throw POV_EXCEPTION(kCannotHandleDataErr, "Bad memory block in free()");
gMemStats.RecordFree(len);
if (!gHeap->Free(p))
throw POV_EXCEPTION(kCannotHandleDataErr, "Bad memory block in free()");
}
void *win_calloc(size_t nelem, size_t size)
{
size_t count = size * nelem;
void *p = win_malloc(count);
if (p == NULL)
return NULL;
memset(p, 0, count);
return p;
}
char *win_strdup(const char *s)
{
size_t len = strlen(s) + 1;
char *p = (char *) win_malloc(len);
memcpy(p, s, len);
return p;
}
#endif // else portion of '#ifdef _DEBUG'
#endif // else portion of '#if POV_MEM_STATS == 0 && WIN_MEM_TRACKING == 0'
} // end of namespace povwin
#if WIN_MEM_TRACKING
using namespace povwin;
#ifdef _DEBUG
#define DEBUGPARAMS , data, line
#else
#define DEBUGPARAMS
#endif
void *operator new (size_t size, const char *func, const void *data, int line)
{
void *res;
if ((res = win_malloc(size DEBUGPARAMS)) != NULL)
return res;
throw std::bad_alloc () ;
}
void *operator new[] (size_t size, const char *func, const void *data, int line)
{
void *res;
if ((res = win_malloc(size DEBUGPARAMS)) != NULL)
return res;
throw std::bad_alloc () ;
}
void operator delete (void *p, const char *func, const void *data, int line)
{
win_free(p DEBUGPARAMS);
}
void operator delete[] (void *p, const char *func, const void *data, int line)
{
win_free(p DEBUGPARAMS);
}
#ifdef _DEBUG
#undef DEBUGPARAMS
#define DEBUGPARAMS , ReturnAddress(), -1
#endif
void *operator new (size_t size)
{
void *res;
if ((res = win_malloc(size DEBUGPARAMS)) != NULL)
return res;
throw std::bad_alloc () ;
}
void *operator new[] (size_t size)
{
void *res;
if ((res = win_malloc(size DEBUGPARAMS)) != NULL)
return res;
throw std::bad_alloc () ;
}
void operator delete (void *p) throw ()
{
win_free(p DEBUGPARAMS);
}
void operator delete[] (void *p) throw ()
{
win_free(p DEBUGPARAMS);
}
#endif // #if WIN_MEM_TRACKING