00001 /** @file psMemory.h 00002 * 00003 * @brief Contains the definitions for the memory management system 00004 * 00005 * This is the generic memory management system put inbetween the user's high level code and the OS-level 00006 * memory allocation routines. This system adds such features as callback routines for memory error events, 00007 * tracing capabilities, and reference counting. 00008 * 00009 * @author Robert DeSonia, MHPCC 00010 * @author Robert Lupton, Princeton University 00011 * 00012 * @ingroup MemoryManagement 00013 * 00014 * @version $Revision: 1.1.1.1 $ $Name: $ 00015 * @date $Date: 2005/09/14 20:42:48 $ 00016 * 00017 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 00018 */ 00019 00020 #ifndef PS_MEMORY_H 00021 #define PS_MEMORY_H 00022 00023 #include <stdio.h> // needed for FILE 00024 #include <pthread.h> // we need a mutex to make this stuff thread safe. 00025 00026 #include "psType.h" 00027 00028 /** @addtogroup MemoryManagement 00029 * @{ 00030 */ 00031 00032 /** 00033 * @addtogroup memCallback Memory Callbacks 00034 * 00035 * Routines dealing with the creating and setting of memory management callback functions. 00036 */ 00037 00038 /** 00039 * @addtogroup memTracing Memory Tracing 00040 * 00041 * Routines dealing with memory tracing and corruption checking. 00042 */ 00043 00044 /** 00045 * @addtogroup memRefCount Reference Count 00046 * 00047 * Routines dealing with the reference counting of allocated buffers. 00048 */ 00049 00050 /// typedef for memory identification numbers. Guaranteed to be some variety of integer. 00051 typedef unsigned long psMemId; 00052 00053 /// typedef for a memory block's reference count. Guaranteed to be some variety of integer. 00054 typedef unsigned long psReferenceCount; 00055 00056 /// typedef for deallocator. 00057 typedef void (*psFreeFunc) (void* ptr); 00058 00059 /** Book-keeping data for storage allocator. 00060 * N.b. sizeof(psMemBlock) must be chosen such that if ptr is a pointer 00061 * returned by malloc, then ((char *)ptr + sizeof(psMemBlock)) is properly 00062 * aligned for all storage types. 00063 */ 00064 typedef struct psMemBlock 00065 { 00066 const void* startblock; ///< initialised to p_psMEMMAGIC 00067 struct psMemBlock* previousBlock; ///< previous block in allocation list 00068 struct psMemBlock* nextBlock; ///< next block allocation list 00069 psFreeFunc freeFunc; ///< deallocator. If NULL, use generic deallocation. 00070 size_t userMemorySize; ///< the size of the user-portion of the memory block 00071 const psMemId id; ///< a unique ID for this allocation 00072 const char *file; ///< set from __FILE__ in e.g. p_psAlloc 00073 const unsigned int lineno; ///< set from __LINE__ in e.g. p_psAlloc 00074 pthread_mutex_t refCounterMutex; ///< mutex to ensure exclusive access to reference counter 00075 psReferenceCount refCounter; ///< how many times pointer is referenced 00076 bool persistent; ///< marks if this non-user persistent data like error stack, etc. 00077 const void* endblock; ///< initialised to p_psMEMMAGIC 00078 } 00079 psMemBlock; 00080 00081 /** prototype of a basic callback used by memory functions 00082 * 00083 * @see psMemAllocCallbackSet 00084 * @ingroup memCallback 00085 */ 00086 typedef psMemId(*psMemAllocCallback) ( 00087 const psMemBlock* ptr ///< the psMemBlock just allocated 00088 ); 00089 00090 /** prototype of memory free callback used by memory functions 00091 * 00092 * @see psMemFreeCallbackSet 00093 * @ingroup memCallback 00094 */ 00095 typedef psMemId(*psMemFreeCallback) ( 00096 const psMemBlock* ptr ///< the psMemBlock being freed 00097 ); 00098 00099 /** prototype of a callback used in error conditions 00100 * 00101 * This callback should not try to call psAlloc or psFree. 00102 * 00103 * @see psMemProblemCallbackSet 00104 * @ingroup memCallback 00105 */ 00106 typedef void (*psMemProblemCallback) ( 00107 psMemBlock* ptr, ///< the pointer to the problematic memory block. 00108 const char *filename, ///< the file in which the problem originated 00109 unsigned int lineno ///< the line number in which the problem originated 00110 ); 00111 00112 /** prototype of a callback function used when memory runs out 00113 * 00114 * @return psPtr pointer to requested buffer of the size size_t, or NULL if memory could not 00115 * be found. 00116 * 00117 * @see psMemExhaustedCallbackSet 00118 * @ingroup memCallback 00119 */ 00120 typedef psPtr (*psMemExhaustedCallback) ( 00121 size_t size ///< the size of buffer required 00122 ); 00123 00124 /** Memory allocation. This operates much like malloc(), but is guaranteed to return a non-NULL value. 00125 * 00126 * @return psPtr pointer to the allocated buffer. This will not be NULL. 00127 * @see psFree 00128 */ 00129 #ifdef DOXYGEN 00130 00131 psPtr psAlloc( 00132 size_t size ///< Size required 00133 ); 00134 00135 #else // #ifdef DOXYGEN 00136 psPtr p_psAlloc( 00137 size_t size, ///< Size required 00138 const char *filename, ///< File of call 00139 unsigned int lineno ///< Line number of call 00140 ); 00141 00142 /// Memory allocation. psAlloc sends file and line number to p_psAlloc. 00143 #ifndef SWIG 00144 #define psAlloc(size) p_psAlloc(size, __FILE__, __LINE__) 00145 #endif // ! SWIG 00146 00147 #endif // ! DOXYGEN 00148 00149 /** Set the deallocator routine 00150 * 00151 * A deallocator routine can optionally be assigned to a memory block to 00152 * ensure that associated memory blocks also get freed, e.g., memory buffers 00153 * referenced within a struct. 00154 * 00155 */ 00156 void psMemSetDeallocator( 00157 psPtr ptr, ///< the memory block to operate on 00158 psFreeFunc freeFunc ///< the function to be executed at deallocation 00159 ); 00160 00161 /** Get the deallocator routine 00162 * 00163 * This function returns the deallocator for a memory block. A deallocator 00164 * routine can optionally be assigned to a memory block to ensure that 00165 * associated memory blocks also get freed, e.g., memory buffers referenced 00166 * within a struct. 00167 * 00168 * @return psFreeFunc the routine to be called at deallocation. 00169 */ 00170 psFreeFunc psMemGetDeallocator( 00171 const psPtr ptr ///< the memory block 00172 ); 00173 00174 /** Checks the deallocator to see if the pointer matches the desired datatype. 00175 * 00176 * @return bool: True if type matches, otherwise false. 00177 */ 00178 bool psMemCheckType( 00179 psDataType type, ///< The desired psDataType to match 00180 psPtr ptr ///< The desired pointer to match 00181 ); 00182 00183 00184 /** Set the memory as persistent so that it is ignored when detecting memory leaks. 00185 * 00186 * Used to mark a memory block as persistent data within the library, 00187 * i.e., non user-level data used to hold psLib's state or cache data. Such 00188 * examples of this class of memory is psTrace's trace-levels and dynamic 00189 * error codes. 00190 * 00191 * Memory marked as persistent is excluded from memory leak checks. 00192 * 00193 */ 00194 void p_psMemSetPersistent( 00195 psPtr ptr, ///< the memory block to operate on 00196 bool value ///< true if memory is persistent, otherwise false 00197 ); 00198 00199 /** Get the memory's persistent flag. 00200 * 00201 * Checks if a memory block has been marked as persistent by 00202 * p_psMemSetPresistent. 00203 * 00204 * Memory marked as persistent is excluded from memory leak checks. 00205 * 00206 * @return bool true if memory is marked persistent, otherwise false. 00207 */ 00208 bool p_psMemGetPersistent( 00209 psPtr ptr ///< the memory block to check. 00210 ); 00211 00212 00213 /** Memory re-allocation. This operates much like realloc(), but is guaranteed to return a non-NULL value. 00214 * 00215 * @return psPtr pointer to resized buffer. This will not be NULL. 00216 * @see psAlloc, psFree 00217 */ 00218 #ifdef DOXYGEN 00219 00220 psPtr psRealloc( 00221 psPtr ptr, ///< Pointer to re-allocate 00222 size_t size ///< Size required 00223 ); 00224 #else // #ifdef DOXYGEN 00225 00226 psPtr p_psRealloc( 00227 psPtr ptr, ///< Pointer to re-allocate 00228 size_t size, ///< Size required 00229 const char *filename, ///< File of call 00230 unsigned int lineno ///< Line number of call 00231 ); 00232 00233 /// Memory re-allocation. psRealloc sends file and line number to p_psRealloc. 00234 #ifndef SWIG 00235 #define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__) 00236 #endif // ! SWIG 00237 00238 #endif // ! DOXYGEN 00239 00240 /** Free memory. This operates much like free(). 00241 * 00242 * @see psAlloc, psRealloc 00243 */ 00244 #ifdef DOXYGEN 00245 void psFree( 00246 psPtr ptr ///< Pointer to free, if NULL, function returns immediately. 00247 ); 00248 #else // #ifdef DOXYGEN 00249 void p_psFree( 00250 psPtr ptr, ///< Pointer to free 00251 const char *filename, ///< File of call 00252 unsigned int lineno ///< Line number of call 00253 ); 00254 00255 /// Free memory. psFree sends file and line number to p_psFree. 00256 #ifndef SWIG 00257 //#define psFree(ptr) { p_psFree((psPtr)ptr, __FILE__, __LINE__); *(void**)&(ptr) = NULL; } 00258 #define psFree(ptr) { p_psFree((psPtr)ptr, __FILE__, __LINE__); } 00259 #endif // ! SWIG 00260 00261 #endif // ! DOXYGEN 00262 00263 /** Check for memory leaks. This scans for allocated memory buffers not freed with an ID not less than id0. 00264 * This is used to check for memory leaks by: 00265 * -# before a block of code to be checked, store the current ID count via psGetMemId 00266 * -# after the block of code to be checked, call this function using the ID stored above. If all 00267 * memory in the block that was allocated has been freed, this call should output nothing and 00268 * return 0. 00269 * 00270 * If memory leaks are found, the Memory Problem callback will be called as well. 00271 * 00272 * @return int number of memory blocks found as 'leaks', i.e., the number of currently allocated memory 00273 * blocks above id0 that have not been freed. 00274 * @see psAlloc, psFree, psgetMemId, psMemProblemCallbackSet 00275 * @ingroup memTracing 00276 */ 00277 int psMemCheckLeaks( 00278 psMemId id0, ///< don't list blocks with id < id0 00279 psMemBlock ***array, ///< pointer to array of pointers to leaked blocks, or NULL 00280 FILE * fd, ///< print list of leaks to fd (or NULL) 00281 bool persistence ///< make check across all object even persistent ones 00282 ); 00283 00284 /** Check for memory corruption. Scans all currently allocated memory buffers and checks for corruptions, 00285 * i.e., invalid markers that signify a buffer under/overflow. 00286 * 00287 * @return int 00288 * 00289 * @ingroup memTracing 00290 */ 00291 int psMemCheckCorruption( 00292 bool abort_on_error ///< Abort on detecting corruption? 00293 ); 00294 00295 /** Return reference counter 00296 * 00297 * @return psReferenceCount 00298 * 00299 * @ingroup memRefCount 00300 */ 00301 psReferenceCount psMemGetRefCounter( 00302 const psPtr ptr ///< Pointer to get refCounter for 00303 ); 00304 00305 /** Increment reference counter and return the pointer 00306 * 00307 * @return psPtr 00308 * 00309 * @ingroup memRefCount 00310 */ 00311 #ifdef DOXYGEN 00312 psPtr psMemIncrRefCounter( 00313 const psPtr ptr ///< Pointer to increment refCounter, and return 00314 ); 00315 #else 00316 psPtr p_psMemIncrRefCounter( 00317 psPtr vptr, ///< Pointer to increment refCounter, and return 00318 const char *file, ///< File of call 00319 psS32 lineno ///< Line number of call 00320 ); 00321 00322 #ifndef SWIG 00323 #define psMemIncrRefCounter(vptr) p_psMemIncrRefCounter(vptr, __FILE__, __LINE__) 00324 #endif // !SWIG 00325 00326 #endif // !DOXYGEN 00327 00328 /** Decrement reference counter and return the pointer 00329 * 00330 * @ingroup memRefCount 00331 * 00332 * @return psPtr the pointer deremented in refCount, or NULL if pointer is 00333 * fully dereferenced. 00334 */ 00335 #ifdef DOXYGEN 00336 psPtr psMemDecrRefCounter( 00337 psPtr ptr ///< Pointer to decrement refCounter, and return 00338 ); 00339 #else // DOXYGEN 00340 psPtr p_psMemDecrRefCounter( 00341 psPtr vptr, ///< Pointer to decrement refCounter, and return 00342 const char *file, ///< File of call 00343 psS32 lineno ///< Line number of call 00344 ); 00345 00346 #ifndef SWIG 00347 #define psMemDecrRefCounter(vptr) p_psMemDecrRefCounter(vptr, __FILE__, __LINE__) 00348 #endif // !SWIG 00349 00350 #endif // !DOXYGEN 00351 00352 /** Set callback for problems. 00353 * 00354 * At various occasions, the memory manager can check the state of the memory 00355 * stack. If any of these checks discover that the memory stack is corrupted, 00356 * the psMemProblemCallback is called. 00357 00358 * @ingroup memCallback 00359 * 00360 * @return psMemProblemCallback old psMemProblemCallback function 00361 */ 00362 psMemProblemCallback psMemProblemCallbackSet( 00363 psMemProblemCallback func ///< Function to run at memory problem detection 00364 ); 00365 00366 /** Set callback for out-of-memory. 00367 * 00368 * If not enough memory is available to satisfy a request by psAlloc or 00369 * psRealloc, these functions attempt to find an alternative solution by 00370 * calling the psMemExhaustedCallback, a function which may be set by the 00371 * programmer in appropriate circumstances, rather than immediately fail. 00372 * The typical use of such a feature may be when a program needs a large 00373 * chunk of memory to do an operation, but the exact size is not critical. 00374 * This feature gives the programmer the opportunity to make a smaller 00375 * request and try again, limiting the size of the operating buffer. 00376 * 00377 * @ingroup memCallback 00378 * 00379 * @return psMemExhaustedCallback old psMemExhaustedCallback function 00380 */ 00381 psMemExhaustedCallback psMemExhaustedCallbackSet( 00382 psMemExhaustedCallback func ///< Function to run at memory exhaustion 00383 ); 00384 00385 /** Set call back for when a particular memory block is allocated 00386 * 00387 * A private variable, p_psMemAllocID, can be used to trace the allocation 00388 * and freeing of specific memory blocks. If p_psMemAllocID is set and a 00389 * memory block with that ID is allocated, psMemAllocCallback is called 00390 * just before memory is returned to the calling function. 00391 * 00392 * @ingroup memCallback 00393 * 00394 * @return psMemAllocCallback old psMemAllocCallback function 00395 */ 00396 psMemAllocCallback psMemAllocCallbackSet( 00397 psMemAllocCallback func ///< Function to run at memory allocation of specific mem block 00398 ); 00399 00400 /** Set call back for when a particular memory block is freed 00401 * 00402 * A private variable, p_psMemFreeID, can be used to trace the freeing of 00403 * specific memory blocks. If p_psMemFreeID is set and the memory block with 00404 * the ID is about to be freed, the psMemFreeCallback callback is called just 00405 * before the memory block is freed. 00406 * 00407 * @ingroup memCallback 00408 * 00409 * @return psMemFreeCallback old psMemFreeCallback function 00410 */ 00411 psMemFreeCallback psMemFreeCallbackSet( 00412 psMemFreeCallback func ///< Function to run at memory free of specific mem block 00413 ); 00414 00415 /** get next memory ID 00416 * 00417 * @ingroup memCallback 00418 * 00419 * @return psMemId the next memory ID to be used 00420 */ 00421 psMemId psMemGetId(void); 00422 00423 /** set p_psMemAllocID to specific id 00424 * 00425 * A private variable, p_psMemAllocID, can be used to trace the allocation 00426 * and freeing of specific memory blocks. If p_psMemAllocID is set and a 00427 * memory block with that ID is allocated, psMemAllocCallback is called 00428 * just before memory is returned to the calling function. 00429 * 00430 * @ingroup memCallback 00431 * 00432 * @return psMemId 00433 * 00434 * @see psMemAllocCallbackSet 00435 */ 00436 psMemId psMemAllocCallbackSetID( 00437 psMemId id ///< ID to set 00438 ); 00439 00440 /** set p_psMemFreeID to id 00441 * 00442 * A private variable, p_psMemFreeID, can be used to trace the freeing of 00443 * specific memory blocks. If p_psMemFreeID is set and the memory block with 00444 * the ID is about to be freed, the psMemFreeCallback callback is called just 00445 * before the memory block is freed. 00446 * 00447 * @ingroup memCallback 00448 * 00449 * @return psMemId the old p_psMemFreeID 00450 * 00451 * @see psMemFreeCallbackSet 00452 */ 00453 psMemId psMemFreeCallbackSetID( 00454 psMemId id ///< ID to set 00455 ); 00456 00457 //@} End of Memory Management Functions 00458 00459 #ifndef DOXYGEN 00460 00461 /* 00462 * Ensure that any program using malloc/realloc/free will fail to compile 00463 */ 00464 #ifndef PS_ALLOW_MALLOC 00465 #ifdef __GNUC__ 00466 #pragma GCC poison malloc realloc calloc free 00467 #else // __GNUC__ 00468 #define malloc(S) _Pragma("error Use of malloc is not allowed. Use psAlloc instead.") 00469 #define realloc(P,S) _Pragma("error Use of realloc is not allowed. Use psRealloc instead.") 00470 #define calloc(S) _Pragma("error Use of calloc is not allowed. Use psAlloc instead.") 00471 #define free(P) _Pragma("error Use of free is not allowed. Use psFree instead.") 00472 #endif // ! __GNUC__ 00473 #endif // #ifndef PS_ALLOW_MALLOC 00474 00475 #endif // #ifndef DOXYGEN 00476 00477 #endif // #ifndef PS_MEMORY_H
1.4.2