MemMan.h

Go to the documentation of this file.
00001 
00002 
00016 
00017 //Luke Lenhart, 2001-2007
00018 //See /docs/License.txt for details on how this code may be used.
00019 
00020 #pragma once
00021 
00022 #include "Setup.h"
00023 
00024 // --
00025 
00026 #if defined(_DEBUG) || defined(ENABLE_MEMMAN_TRACE_IN_RELEASE)
00027     #define MEMMAN_TRACING
00028 #endif
00029 
00030 //decide whether this platform already has a thread-safe new and delete operator
00031 //#ifdef WIN32
00032     //#define NEEDS_THREADSAFE_ALLOC
00033 //#endif
00034 
00035 #include <list>
00036 #include <string>
00037 #include "Types.h"
00038 #include "Locks.h"
00039 
00040 //internal use
00041 enum EMemAllocType
00042 {
00043     EMAT_None,
00044     EMAT_One,
00045     EMAT_Array
00046 };
00047 
00049 class MemMan
00050 {
00051 public:
00052     MemMan();
00053     ~MemMan();
00054 
00056     void AddLeakReportCallback(void (*leakCallback)(const std::string &leakMessage));
00057 
00058     //checks for memory corruption around all allocated memory
00059     void CheckForPaddingCorruption();
00060 
00061     //tells the memory manager that some memory has been allocated externally (used for tracking max usage only)
00062     //returns an ID of the hinted allocation
00063     int HintMemAlloc(int bytes);
00064     //tells the memory manager that some memory has been freed externally that was previously hinted at
00065     void HintMemFree(int ID);
00066 
00067     //returns whether the memory manager is ready to handle requests
00068     inline bool IsReady() const
00069         { return m_ready; }
00070 
00071     //used by the allocation scheme, do not call directly - traces an alloc or free
00072     void TraceAlloc(EMemAllocType type, volatile void *addr, void *allocMem, uint size, const char *name, const char *file, int line, int count);
00073     EMemAllocType TraceFree(EMemAllocType type, volatile void *addr, const char *file, int line, char *&outAllocMem, int *outCount=0);
00074 
00075     //used by the allocation scheme, do not call directly - does a threadsafe alloc or free
00076     char* InternalAllocBlock(uint bytes);
00077     void InternalFreeBlock(volatile char *mem);
00078     void InternalInitialize();
00079     void InternalShutdown();
00080 
00081 #ifdef MEMMAN_TRACING // -- if using management  --
00082 
00083     struct SAlloc
00084     {
00085         EMemAllocType type;
00086         void *addr; //object address
00087         void *allocMem; //container memory
00088         uint size;
00089         std::string objName;
00090         std::string srcFile;
00091         int srcLine;
00092         int count; //number in array
00093         std::string allocStack;
00094         std::string deleteStack;
00095 
00096         SAlloc *next;
00097     };
00098 
00099 private:
00100     bool m_critErrors; //did any critical memory errors occur?
00101 
00102     SAlloc *m_head; //first item in linked list of allocations
00103 
00104     // -- max usage tracking
00105 
00106     int maxMem; //maximum amount of memory ever used
00107     void RecalcMaxMem(); //recalcs the max memory used
00108 
00109     int curHintAllocID; //ID of next hint to be requested
00110 
00111     struct Hint
00112     {
00113         int ID;
00114         int bytes;
00115         std::string stack;
00116     };
00117     std::list<Hint> hints; //list of all (hint ID,size) hints
00118 
00119 #endif //tracing
00120 
00121     //calls back to the leak report callbacks
00122     void ReportLeak(const std::string &leak);
00123     std::list<void (*)(const std::string &)> leakCallbacks;
00124 
00125     bool m_ready; //class ready to handle requests
00126     MPMA::MutexLock *syncLock;
00127 
00128 public: //internal
00129     //calls an objects destructor
00130     template <typename T> static void dbgN2_Destruct(T *obj)
00131     {
00132         obj->~T();
00133     }
00134     template <typename T> static void dbgN2_Destruct_array(T *obj, int count)
00135     {
00136         for (int i=0; i<count; ++i)
00137         {
00138             obj->~T();
00139             ++obj;
00140         }
00141     }
00142 };
00143 
00144 extern MemMan mMan;
00145 
00146 #ifdef MEMMAN_TRACING // -- if using management  --
00147 
00148 //bytes on each side of an allocation that are used to check for damage
00149 #define dbgN2_padding 8
00150 
00151 //functions for allocating and setting trace information
00152 
00153 template <typename AllocType> AllocType* new2_call(AllocType *obj, const char *name, const char *file, int line)
00154 {
00155     mMan.TraceAlloc(EMAT_One, obj, (char*)obj-dbgN2_padding, sizeof(AllocType), name, file, line, 1);
00156     return obj;
00157 }
00158 
00159 template <typename AllocType> AllocType* new2_array_call(size_t count, const char *name, const char *file, int line)
00160 {
00161     //alloc
00162     char *realMem=mMan.InternalAllocBlock(sizeof(AllocType)*count + dbgN2_padding*2);
00163     char *allocSpot=realMem+dbgN2_padding;
00164     AllocType *obj=new (allocSpot) AllocType[count];
00165 
00166     mMan.TraceAlloc(EMAT_Array, obj, realMem, sizeof(AllocType)*count, name, file, line, (int)count);
00167     return obj;
00168 }
00169 
00170 #endif
00171 
00172 #ifdef MEMMAN_TRACING // -- if using management  --
00173 
00174 //verifies that a type and object declaration are the same type
00175 void dbgN2_PrecheckType(const char *objName, const char *typName);
00176 
00177 //macros for freeing and setting trace information
00178 
00179 #define delete2_call(obj,pMem,file,line) \
00180 do { \
00181     int count=0; \
00182     char *realMem=0; \
00183     EMemAllocType type=mMan.TraceFree(EMAT_One, obj, file, line, realMem,&count); /*see how it was allocated*/ \
00184     if (type==EMAT_One) MemMan::dbgN2_Destruct(obj); \
00185     else if (type==EMAT_Array) MemMan::dbgN2_Destruct_array(obj,count); \
00186     mMan.InternalFreeBlock(realMem); \
00187     *((uint**)(pMem))=(uint*)-1; /*invalidate their pointer*/ \
00188 } while(false)
00189 
00190 #define delete2_array_call(obj,pMem,file,line) \
00191 do { \
00192     int count=0; \
00193     char *realMem=0; \
00194     EMemAllocType type=mMan.TraceFree(EMAT_Array, obj, file, line, realMem, &count); /*see how it was allocated*/ \
00195     if (type==EMAT_One) MemMan::dbgN2_Destruct(obj); \
00196     else if (type==EMAT_Array) MemMan::dbgN2_Destruct_array(obj,count); \
00197     mMan.InternalFreeBlock(realMem); \
00198     *((uint**)(pMem))=(uint*)-1; /*invalidate their pointer*/ \
00199 } while(false)
00200 
00201 
00202 //macros replace normal calls with extra debug information
00203 
00205 #define new2(obj,type) (dbgN2_PrecheckType(""#obj,""#type), new2_call(new (mMan.InternalAllocBlock(dbgN2_padding*2+sizeof(type))+dbgN2_padding) obj, ""#obj, __FILE__, __LINE__))
00207 #define new2_array(obj,count,type) (dbgN2_PrecheckType(""#obj,""#type), new2_array_call<type>(count, ""#obj, __FILE__, __LINE__))
00208 
00210 #define delete2(obj) delete2_call(obj,(void**)&obj,__FILE__,__LINE__)
00212 #define delete2_array(obj) delete2_array_call(obj,(void**)&obj,__FILE__,__LINE__)
00213 
00214 #define hint_mem_alloc(bytes) mMan.HintMemAlloc(bytes)
00215 #define hint_mem_free(ID) mMan.HintMemFree(ID)
00216 
00217 #else // -- if NOT using management
00218 
00219 #ifdef NEEDS_THREADSAFE_ALLOC //if our platform doesn't have threadsafe new and delete
00220 
00221     #define new2(obj,type) new (mMan.InternalAllocBlock(sizeof(type))) obj
00222 
00223     inline char* MemMan_InjectIntBeforeArray(char *mem, uint count)
00224     {
00225         *(uint*)mem=count;
00226         return mem + sizeof(uint);
00227     }
00228 
00229     #define new2_array(obj,count,type) new (MemMan_InjectIntBeforeArray(mMan.InternalAllocBlock(sizeof(type)*count + sizeof(uint)), count)) obj
00230 
00231     #define delete2(obj) do {\
00232         MemMan::dbgN2_Destruct(obj); \
00233         mMan.InternalFreeBlock((volatile char*)obj); } while(false)
00234 
00235     #define delete2_array(obj) do {\
00236         MemMan::dbgN2_Destruct_array(obj,*((uint*)obj-1)); \
00237         mMan.InternalFreeBlock((volatile char*)obj - sizeof(uint)); } while(false)
00238 
00239 
00240 #else //platform has threadsafe new and delete already
00241 
00242     #define new2(obj,junk) new obj
00243     #define new2_array(obj,count,junk) new obj[count]
00244 
00245     #define delete2(obj) delete obj
00246     #define delete2_array(obj) delete[] obj
00247 
00248 #endif
00249 
00250 #define hint_mem_alloc(bytes) 0
00251 #define hint_mem_free(ID) 
00252 
00253 #endif //(build check)
00254 
00255 
00256 // -- auto scope pointer freer --
00257 //will free a pointer when this goes out of scope (and it's not a null pointer)
00258 //pass in the ADDRESS of your pointer
00259 
00261 template <typename T>
00262 class AutoDelete
00263 {
00264 public:
00265     inline AutoDelete(T *inPtr): ptr(inPtr) {}
00266     inline ~AutoDelete() {if (ptr) delete2(ptr);}
00267 private:
00268     T *ptr;
00269 };
00270 
00272 template <typename T>
00273 class AutoDeleteArray
00274 {
00275 public:
00276     inline AutoDeleteArray(T *inPtr): ptr(inPtr) {}
00277     inline ~AutoDeleteArray() {if (ptr) delete2_array(ptr);}
00278 private:
00279     T *ptr;
00280 };

Generated on Wed Feb 13 20:57:04 2008 for MPMA Framework by  doxygen 1.5.4