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.56 $ $Name: rel12 $ 00015 * @date $Date: 2006/06/21 21:40:12 $ 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 /** Activate or Deactivate thread safety and mutex locking in the memory management. 00184 * 00185 * psMemThreadSafety shall turn on thread safety in the memory management functions if 00186 * safe is true, and deactivate all mutex locking in the memory management functions if 00187 * safe is false. The function shall return the previous value of the thread safety. 00188 * Note that the default behaviour of the library shall be for the locking to be performed. 00189 * 00190 * @return bool: The previous value of the thread safety. 00191 */ 00192 bool psMemSetThreadSafety( 00193 bool safe ///< boolean for turning on/off thread safety 00194 ); 00195 00196 /** Get the current state of thread safety and mutex locking in the memory management. 00197 * 00198 * psMemGetThreadSafety shall return the current state of thread safety in the memory management system. 00199 * 00200 * @return bool: The current state of thread safety. 00201 */ 00202 bool psMemGetThreadSafety(void); 00203 00204 /** Set the memory as persistent so that it is ignored when detecting memory leaks. 00205 * 00206 * Used to mark a memory block as persistent data within the library, 00207 * i.e., non user-level data used to hold psLib's state or cache data. Such 00208 * examples of this class of memory is psTrace's trace-levels and dynamic 00209 * error codes. 00210 * 00211 * Memory marked as persistent is excluded from memory leak checks. 00212 * 00213 */ 00214 void p_psMemSetPersistent( 00215 psPtr ptr, ///< the memory block to operate on 00216 bool value ///< true if memory is persistent, otherwise false 00217 ); 00218 00219 /** Set whether allocated memory is persistent 00220 * 00221 * Set whether allocated memory is persistent. The defeault is false. 00222 * 00223 * @return bool: The previous value of whether all allocated memory is persistent 00224 */ 00225 bool p_psMemAllocatePersistent(bool is_persistent); ///< Should all memory allocated be persistent? 00226 00227 /** Get the memory's persistent flag. 00228 * 00229 * Checks if a memory block has been marked as persistent by 00230 * p_psMemSetPresistent. 00231 * 00232 * Memory marked as persistent is excluded from memory leak checks. 00233 * 00234 * @return bool true if memory is marked persistent, otherwise false. 00235 */ 00236 bool p_psMemGetPersistent( 00237 psPtr ptr ///< the memory block to check. 00238 ); 00239 00240 00241 /** Memory re-allocation. This operates much like realloc(), but is guaranteed to return a non-NULL value. 00242 * 00243 * @return psPtr pointer to resized buffer. This will not be NULL. 00244 * @see psAlloc, psFree 00245 */ 00246 #ifdef DOXYGEN 00247 00248 psPtr psRealloc( 00249 psPtr ptr, ///< Pointer to re-allocate 00250 size_t size ///< Size required 00251 ); 00252 #else // #ifdef DOXYGEN 00253 00254 psPtr p_psRealloc( 00255 psPtr ptr, ///< Pointer to re-allocate 00256 size_t size, ///< Size required 00257 const char *filename, ///< File of call 00258 unsigned int lineno ///< Line number of call 00259 ); 00260 00261 /// Memory re-allocation. psRealloc sends file and line number to p_psRealloc. 00262 #ifndef SWIG 00263 #define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__) 00264 #endif // ! SWIG 00265 00266 #endif // ! DOXYGEN 00267 00268 /** Free memory. This operates much like free(). 00269 * 00270 * @see psAlloc, psRealloc 00271 */ 00272 #ifdef DOXYGEN 00273 void psFree( 00274 psPtr ptr ///< Pointer to free, if NULL, function returns immediately. 00275 ); 00276 #else // #ifdef DOXYGEN 00277 void p_psFree( 00278 psPtr ptr, ///< Pointer to free 00279 const char *filename, ///< File of call 00280 unsigned int lineno ///< Line number of call 00281 ); 00282 00283 /// Free memory. psFree sends file and line number to p_psFree. 00284 #ifndef SWIG 00285 //#define psFree(ptr) { p_psFree((psPtr)ptr, __FILE__, __LINE__); *(void**)&(ptr) = NULL; } 00286 #define psFree(ptr) { p_psFree((psPtr)ptr, __FILE__, __LINE__); } 00287 #endif // ! SWIG 00288 00289 #endif // ! DOXYGEN 00290 00291 /** Check for memory leaks. This scans for allocated memory buffers not freed with an ID not less than id0. 00292 * This is used to check for memory leaks by: 00293 * -# before a block of code to be checked, store the current ID count via psGetMemId 00294 * -# after the block of code to be checked, call this function using the ID stored above. If all 00295 * memory in the block that was allocated has been freed, this call should output nothing and 00296 * return 0. 00297 * 00298 * If memory leaks are found, the Memory Problem callback will be called as well. 00299 * 00300 * @return int number of memory blocks found as 'leaks', i.e., the number of currently allocated memory 00301 * blocks above id0 that have not been freed. 00302 * @see psAlloc, psFree, psgetMemId, psMemProblemCallbackSet 00303 * @ingroup memTracing 00304 */ 00305 int psMemCheckLeaks( 00306 psMemId id0, ///< don't list blocks with id < id0 00307 psMemBlock ***array, ///< pointer to array of pointers to leaked blocks, or NULL 00308 FILE * fd, ///< print list of leaks to fd (or NULL) 00309 bool persistence ///< make check across all object even persistent ones 00310 ); 00311 00312 /** Check for memory corruption. Scans all currently allocated memory buffers and checks for corruptions, 00313 * i.e., invalid markers that signify a buffer under/overflow. 00314 * 00315 * @return int 00316 * 00317 * @ingroup memTracing 00318 */ 00319 int psMemCheckCorruption( 00320 bool abort_on_error ///< Abort on detecting corruption? 00321 ); 00322 00323 /** Return reference counter 00324 * 00325 * @return psReferenceCount 00326 * 00327 * @ingroup memRefCount 00328 */ 00329 psReferenceCount psMemGetRefCounter( 00330 const psPtr ptr ///< Pointer to get refCounter for 00331 ); 00332 00333 /** Increment reference counter and return the pointer 00334 * 00335 * @return psPtr 00336 * 00337 * @ingroup memRefCount 00338 */ 00339 #ifdef DOXYGEN 00340 psPtr psMemIncrRefCounter( 00341 const psPtr ptr ///< Pointer to increment refCounter, and return 00342 ); 00343 #else 00344 psPtr p_psMemIncrRefCounter( 00345 const psPtr vptr, ///< Pointer to increment refCounter, and return 00346 const char *file, ///< File of call 00347 psS32 lineno ///< Line number of call 00348 ); 00349 00350 #ifndef SWIG 00351 #define psMemIncrRefCounter(vptr) p_psMemIncrRefCounter(vptr, __FILE__, __LINE__) 00352 #endif // !SWIG 00353 00354 #endif // !DOXYGEN 00355 00356 /** Decrement reference counter and return the pointer 00357 * 00358 * @ingroup memRefCount 00359 * 00360 * @return psPtr the pointer deremented in refCount, or NULL if pointer is 00361 * fully dereferenced. 00362 */ 00363 #ifdef DOXYGEN 00364 psPtr psMemDecrRefCounter( 00365 psPtr ptr ///< Pointer to decrement refCounter, and return 00366 ); 00367 #else // DOXYGEN 00368 psPtr p_psMemDecrRefCounter( 00369 psPtr vptr, ///< Pointer to decrement refCounter, and return 00370 const char *file, ///< File of call 00371 psS32 lineno ///< Line number of call 00372 ); 00373 00374 #ifndef SWIG 00375 #define psMemDecrRefCounter(vptr) p_psMemDecrRefCounter(vptr, __FILE__, __LINE__) 00376 #endif // !SWIG 00377 00378 #endif // !DOXYGEN 00379 00380 /** Set reference counter and return the pointer 00381 * 00382 * @ingroup memRefCount 00383 * 00384 * @return psPtr the pointer with refCount set, or NULL if pointer is 00385 * fully dereferenced. 00386 */ 00387 #ifdef DOXYGEN 00388 psPtr psMemSetRefCounter( 00389 psPtr ptr, ///< Pointer to decrement refCounter, and return 00390 psReferenceCount count ///< New reference count 00391 ); 00392 #else // DOXYGEN 00393 psPtr p_psMemSetRefCounter( 00394 psPtr vptr, ///< Pointer to decrement refCounter, and return 00395 psReferenceCount count, ///< New reference count 00396 const char *file, ///< File of call 00397 psS32 lineno ///< Line number of call 00398 ); 00399 00400 #ifndef SWIG 00401 #define psMemSetRefCounter(vptr, count) p_psMemSetRefCounter(vptr, count, __FILE__, __LINE__) 00402 #endif // !SWIG 00403 00404 #endif // !DOXYGEN 00405 00406 /** Set callback for problems. 00407 * 00408 * At various occasions, the memory manager can check the state of the memory 00409 * stack. If any of these checks discover that the memory stack is corrupted, 00410 * the psMemProblemCallback is called. 00411 00412 * @ingroup memCallback 00413 * 00414 * @return psMemProblemCallback old psMemProblemCallback function 00415 */ 00416 psMemProblemCallback psMemProblemCallbackSet( 00417 psMemProblemCallback func ///< Function to run at memory problem detection 00418 ); 00419 00420 /** Set callback for out-of-memory. 00421 * 00422 * If not enough memory is available to satisfy a request by psAlloc or 00423 * psRealloc, these functions attempt to find an alternative solution by 00424 * calling the psMemExhaustedCallback, a function which may be set by the 00425 * programmer in appropriate circumstances, rather than immediately fail. 00426 * The typical use of such a feature may be when a program needs a large 00427 * chunk of memory to do an operation, but the exact size is not critical. 00428 * This feature gives the programmer the opportunity to make a smaller 00429 * request and try again, limiting the size of the operating buffer. 00430 * 00431 * @ingroup memCallback 00432 * 00433 * @return psMemExhaustedCallback old psMemExhaustedCallback function 00434 */ 00435 psMemExhaustedCallback psMemExhaustedCallbackSet( 00436 psMemExhaustedCallback func ///< Function to run at memory exhaustion 00437 ); 00438 00439 /** Set call back for when a particular memory block is allocated 00440 * 00441 * A private variable, p_psMemAllocID, can be used to trace the allocation 00442 * and freeing of specific memory blocks. If p_psMemAllocID is set and a 00443 * memory block with that ID is allocated, psMemAllocCallback is called 00444 * just before memory is returned to the calling function. 00445 * 00446 * @ingroup memCallback 00447 * 00448 * @return psMemAllocCallback old psMemAllocCallback function 00449 */ 00450 psMemAllocCallback psMemAllocCallbackSet( 00451 psMemAllocCallback func ///< Function to run at memory allocation of specific mem block 00452 ); 00453 00454 /** Set call back for when a particular memory block is freed 00455 * 00456 * A private variable, p_psMemFreeID, can be used to trace the freeing of 00457 * specific memory blocks. If p_psMemFreeID is set and the memory block with 00458 * the ID is about to be freed, the psMemFreeCallback callback is called just 00459 * before the memory block is freed. 00460 * 00461 * @ingroup memCallback 00462 * 00463 * @return psMemFreeCallback old psMemFreeCallback function 00464 */ 00465 psMemFreeCallback psMemFreeCallbackSet( 00466 psMemFreeCallback func ///< Function to run at memory free of specific mem block 00467 ); 00468 00469 /** get next memory ID 00470 * 00471 * @ingroup memCallback 00472 * 00473 * @return psMemId the next memory ID to be used 00474 */ 00475 psMemId psMemGetId(void); 00476 00477 /** set p_psMemAllocID to specific id 00478 * 00479 * A private variable, p_psMemAllocID, can be used to trace the allocation 00480 * and freeing of specific memory blocks. If p_psMemAllocID is set and a 00481 * memory block with that ID is allocated, psMemAllocCallback is called 00482 * just before memory is returned to the calling function. 00483 * 00484 * @ingroup memCallback 00485 * 00486 * @return psMemId 00487 * 00488 * @see psMemAllocCallbackSet 00489 */ 00490 psMemId psMemAllocCallbackSetID( 00491 psMemId id ///< ID to set 00492 ); 00493 00494 /** set p_psMemFreeID to id 00495 * 00496 * A private variable, p_psMemFreeID, can be used to trace the freeing of 00497 * specific memory blocks. If p_psMemFreeID is set and the memory block with 00498 * the ID is about to be freed, the psMemFreeCallback callback is called just 00499 * before the memory block is freed. 00500 * 00501 * @ingroup memCallback 00502 * 00503 * @return psMemId the old p_psMemFreeID 00504 * 00505 * @see psMemFreeCallbackSet 00506 */ 00507 psMemId psMemFreeCallbackSetID( 00508 psMemId id ///< ID to set 00509 ); 00510 00511 //@} End of Memory Management Functions 00512 00513 #ifndef DOXYGEN 00514 00515 /* 00516 * Ensure that any program using malloc/realloc/free will fail to compile 00517 */ 00518 #ifndef PS_ALLOW_MALLOC 00519 #ifdef __GNUC__ 00520 #pragma GCC poison malloc realloc calloc free 00521 #else // __GNUC__ 00522 #define malloc(S) _Pragma("error Use of malloc is not allowed. Use psAlloc instead.") 00523 #define realloc(P,S) _Pragma("error Use of realloc is not allowed. Use psRealloc instead.") 00524 #define calloc(S) _Pragma("error Use of calloc is not allowed. Use psAlloc instead.") 00525 #define free(P) _Pragma("error Use of free is not allowed. Use psFree instead.") 00526 #endif // ! __GNUC__ 00527 #endif // #ifndef PS_ALLOW_MALLOC 00528 00529 #endif // #ifndef DOXYGEN 00530 00531 #endif // #ifndef PS_MEMORY_H
1.4.4