//*CMZ : 0.04/03 25/11/95 18.44.11 by Fons Rademakers//*CMZ : 0.03/10 05/10/95 11.00.10 by Fons Rademakers//*-- Author : Fons Rademakers 29/07/95// Copyright (C) 1994 CodeCERN. All rights reserved.//////////////////////////////////////////////////////////////////////////// //// TStorage //// //// Storage manager. All new and delete operations in the ROOT system //// pass via the custom new and delete operators defined in this file. //// This scheme allows extensive memory checking and usage statistics //// gathering and an easy way to access shared memory segments. //// Memory checking is by default enabled and usage statistics is //// gathered. Using the resource (in .rootrc): Root.MemStat one can //// toggle statistics gathering on or off. More specifically on can trap //// the allocation of a block of memory of a certain size. This can be //// specified using the resource: Root.MemStat.size, using the resource //// Root.MemStat.cnt one can specify after how many allocations of //// this size the trap should occur. //// Set the compile option NOSTATS to de-activate all memory checking //// statistics gathering in the system. //// //// When memory checking is enabled the following happens during //// allocation: //// - each allocation results in the allocation of 9 extra bytes: //// 2 words in front and 1 byte at the end of the memory chunck //// returned to the caller. //// - the allocated memory is set to 0. //// - the size of the chunck is stored in the first word. The second //// word is left empty (for alignment). //// - the last byte is initialized to MEM_MAGIC. //// //// And during de-allocation this happens: //// - first the size if the block is checked. It should be >0 and //// <= than any block allocated up to that moment. If not a Fatal //// error is generated. //// - the MEM_MAGIC byte at the end of the block is checked. When not //// there, the memory has been overwritten and a Fatal error is //// generated. //// - memory block is reset to 0. //// //// Although this does not replace powerful tools like Purify, it is a //// good first line of protection. //// //// The powerful MEM_DEBUG and MEM_STAT macros were borrowed from //// the ET++ framework. //// ////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
//*KEEP,STORAGE.
#include "Storage.h"
//*KEEP,OBJECTTABLE.
#include "ObjectTable.h"
//*KEEP,ERROR.
#include "Error.h"
//*KEEP,RMATH.
#include "RMath.h"
//*KEEP,RSTRING.
#include "RString.h"
//*KEND.
#if !defined(NOSTATS)
# define MEM_DEBUG
# define MEM_STAT
# define MEM_CHECKOBJECTPOINTERS
#endif
#if defined(MEM_STAT) && !defined(MEM_DEBUG)
# define MEM_DEBUG
#endif
#ifdef MEM_DEBUG
# define MEM_MAGIC ((char)0xAB)
# define storage_size(p) ((size_t)(((int*)p)[-2]))
# define RealStart(p) ((char*)(p) - 2*sizeof(int))
# define StoreSize(p, sz) (*((int*)(p)) = (sz))
# define ExtStart(p) ((char*)(p) + 2*sizeof(int))
# define MemClear(p, start, len) \
if ((len) > 0) memset(&((char*)(p))[(start)], 0, (len))
# define RealSize(sz) ((sz) + 2*sizeof(int) + sizeof(char))
# define StoreMagic(p, sz) *((char*)(p)+sz+2*sizeof(int)) = MEM_MAGIC
# define TestMagic(p, sz) (*((char*)(p)+sz) != MEM_MAGIC)
# define CheckMagic(p, s, where) \
if (TestMagic(p, s)) \
Fatal(where, "storage area overwritten");
# define CheckFreeSize(p, where) \
if (storage_size((p)) < 0 || storage_size((p)) > TStorage::fgMaxBlockSize) \
Fatal(where, "unreasonable size (%d)", storage_size(p));
# define RemoveStatMagic(p, where) \
CheckFreeSize(p, where); \
RemoveStat(p); \
CheckMagic(p, storage_size(p), where)
# define StoreSizeMagic(p, size, where) \
StoreSize(p, size); \
StoreMagic(p, size); \
EnterStat(size, ExtStart(p)); \
CheckObjPtr(ExtStart(p), where);
#else
# define storage_size(p) ((size_t)0)
# define RealSize(sz) (sz)
# define RealStart(p) (p)
# define ExtStart(p) (p)
# define MemClear(p, start, len)
# define StoreSizeMagic(p, size, where) \
EnterStat(size, ExtStart(p)); \
CheckObjPtr(ExtStart(p), where);
# define RemoveStatMagic(p, where) \
RemoveStat(p);
#endif
#define CallFreeHook(p, size) \
if (TStorage::fgFreeHook) TStorage::fgFreeHook(TStorage::fgFreeHookData, (p), (size))
#ifdef MEM_CHECKOBJECTPOINTERS
//# define CheckObjPtr(p, name) TObjectTable::CheckPtrAndWarn((name), (p));
# define CheckObjPtr(p, name)
#else
# define CheckObjPtr(p, name)
#endif
ULong_t TStorage::fgLastObject;
ULong_t TStorage::fgLastObjectEnd;
FreeHookFun_t TStorage::fgFreeHook;
void *TStorage::fgFreeHookData;
size_t TStorage::fgMaxBlockSize;
static const char *spaceErr = "storage exhausted";
//------------------------------------------------------------------------------
#ifdef MEM_STAT
const int kObjMaxSize = 1024;
static Bool_t memStatistics;
static Int_t allocated[kObjMaxSize], freed[kObjMaxSize];
static Int_t allocatedTotal, freedTotal;
static void **traceArray = 0;
static Int_t traceCapacity = 10, traceIndex = 0, memSize = -1, memIndex = -1;
//______________________________________________________________________________
void EnterStat(size_t size, void *p)
{
// Register a memory allocation operation. If desired one can trap an // allocation of a certain size in case one tries to find a memory // leak of that particular size.
if (memStatistics && size == memSize) {
if (traceIndex == memIndex)
Fatal("EnterStat", "trapped allocation %d", memIndex);
if (!traceArray) traceArray = (void**) malloc(sizeof(void*)*traceCapacity);
if (traceIndex >= traceCapacity) {
traceCapacity = traceCapacity*2;
traceArray = (void**) realloc(traceArray, sizeof(void*)*traceCapacity);
}
traceArray[traceIndex++] = p;
}
TStorage::fgMaxBlockSize = TMath::Max(TStorage::fgMaxBlockSize, size);
if (size >= kObjMaxSize)
allocated[kObjMaxSize-1]++;
else
allocated[size]++;
allocatedTotal += size;
}
//______________________________________________________________________________
void RemoveStat(void *vp)
{
// Register a memory free operation.
size_t size = storage_size(vp);
if (memStatistics && size == memSize) {
for (int i = 0; i < traceIndex; i++)
if (traceArray[i] == vp) {
traceArray[i] = 0;
break;
}
}
if (size >= kObjMaxSize)
freed[kObjMaxSize-1]++;
else
freed[size]++;
freedTotal+= size;
}
#else
#define EnterStat(s, p) \
TStorage::fgMaxBlockSize = TMath::Max(TStorage::fgMaxBlockSize, s)
#define RemoveStat(p)
#endif
//------------------------------------------------------------------------------//______________________________________________________________________________
void *operator new(size_t size)
{
// Custom new() operator.
static const char *where = "operator new";
if (size < 0)
Fatal(where, "size < 0");
register void *vp = ::calloc(RealSize(size), sizeof(char));
if (vp == 0)
Fatal(where, spaceErr);
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
//______________________________________________________________________________
void *operator new(size_t size, void *vp)
{
// Custom new() operator with placement argument.
static const char *where = "operator new(void *at)";
if (size < 0)
Fatal(where, "size < 0");
if (vp == 0) {
register void *vp = ::calloc(RealSize(size), sizeof(char));
if (vp == 0)
Fatal(where, spaceErr);
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
return vp;
}
//______________________________________________________________________________
void operator delete(void *ptr)
{
// Custom delete() operator.
static const char *where = "operator delete";
TStorage::fgLastObject = TStorage::fgLastObjectEnd = 0;
if (ptr) {
CheckObjPtr(ptr, where);
CallFreeHook(ptr, storage_size(ptr));
RemoveStatMagic(ptr, where);
MemClear(RealStart(ptr), 0, RealSize(storage_size(ptr)));
::errno = 0;
::free(RealStart(ptr));
if (errno != 0)
SysError(where, "free");
}
}
//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
// Reallocate (i.e. resize) block of memory.
static const char *where = "TStorage::ReAlloc";
if (size < 0)
Fatal(where, "size < 0");
if (ovp == 0)
return new char[size];
size_t oldsize = storage_size(ovp);
if (oldsize == size)
return ovp;
RemoveStatMagic(ovp, where);
void *vp = ::realloc((char*)RealStart(ovp), RealSize(size));
if (vp == 0)
Fatal(where, spaceErr);
if (size > oldsize)
MemClear(ExtStart(vp), oldsize, size-oldsize);
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
// Reallocate (i.e. resize) block of memory. Checks if current size is // equal to oldsize. If not memory was overwritten.
static const char *where = "TStorage::ReAlloc";
if (size < 0)
Fatal(where, "size < 0");
if (ovp == 0)
return new char[size];
#if defined(MEM_DEBUG)
if (oldsize != storage_size(ovp))
fprintf(stderr, "TStorage::ReAlloc: oldsize != size\n");
#endif
if (oldsize == size)
return ovp;
RemoveStatMagic(ovp, where);
void *vp = ::realloc((char*)RealStart(ovp), RealSize(size));
if (vp == 0)
Fatal(where, spaceErr);
if (size > oldsize)
MemClear(ExtStart(vp), oldsize, size-oldsize);
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
// Used to allocate a TObject on the heap (via TObject::new()). Directly // after this routine one can call (in the TObject ctor) TStorage::IsOnHeap() // to find out if the just created object is on the heap.
fgLastObject = (ULong_t) new char[sz];
fgLastObjectEnd = fgLastObject + sz;
return (void*) fgLastObject;
}
//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
// Set a free handler.
fgFreeHook = fh;
fgFreeHookData = data;
}
//______________________________________________________________________________
void TStorage::PrintStatistics()
{
// Print memory usage statistics.
#if defined(MEM_DEBUG) && defined(MEM_STAT)
if (!memStatistics)
return;
// Printf("");
Printf("Heap statistics");
Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
Printf("================================================");
int i;
for (i= 0; i < kObjMaxSize; i++)
if (allocated[i] != freed[i])
//if (allocated[i])
Printf("%12d%12d%12d%12d", i, allocated[i], freed[i],
allocated[i]-freed[i]);
if (allocatedTotal != freedTotal) {
Printf("------------------------------------------------");
Printf("Total: %12d%12d%12d", allocatedTotal, freedTotal,
allocatedTotal-freedTotal);
}
if (memSize != -1) {
Printf("------------------------------------------------");
for (i= 0; i < traceIndex; i++)
if (traceArray[i])
Printf("block %d of size %d not freed", i, memSize);
}
Printf("================================================");
Printf("");
#endif
}
//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
// Enable memory usage statistics gathering. Size is the size of the memory // block that should be trapped and ix is after how many such allocations // the trap should happen.
#ifdef MEM_STAT
memSize = size;
memIndex = ix;
memStatistics = kTRUE;
#else
int idum = size; int iidum = ix;
#endif
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or
contact the developers with any questions or problems regarding ROOT.