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/06/15 21:08: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 psU64 psMemoryId; 00052 00053 /// typedef for a memory block's reference count. Guaranteed to be some variety of integer. 00054 typedef psU64 psReferenceCount; 00055 00056 /// typedef for deallocator. 00057 typedef void (*psFreeFcn) (psPtr 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 psPtr startblock; ///< initialised to p_psMEMMAGIC 00067 struct psMemBlock* previousBlock; ///< previous block in allocation list 00068 struct psMemBlock* nextBlock; ///< next block allocation list 00069 psFreeFcn freeFcn; ///< deallocator. If NULL, use generic deallocation. 00070 size_t userMemorySize; ///< the size of the user-portion of the memory block 00071 const psMemoryId id; ///< a unique ID for this allocation 00072 const char *file; ///< set from __FILE__ in e.g. p_psAlloc 00073 const psS32 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 psBool persistent; ///< marks if this non-user persistent data like error stack, etc. 00077 const psPtr endblock; ///< initialised to p_psMEMMAGIC 00078 } 00079 psMemBlock; 00080 00081 /** prototype of a basic callback used by memory functions 00082 * 00083 * @see psMemAllocateCallbackSet 00084 * @ingroup memCallback 00085 */ 00086 typedef psMemoryId(*psMemAllocateCallback) ( 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 psMemoryId(*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 const psMemBlock* ptr, ///< the pointer to the problematic memory block. 00108 const char *file, ///< the file in which the problem originated 00109 psS32 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 psPtr psAlloc(size_t size ///< Size required 00131 ); 00132 #else // #ifdef DOXYGEN 00133 psPtr p_psAlloc(size_t size, ///< Size required 00134 const char *file, ///< File of call 00135 psS32 lineno ///< Line number of call 00136 ); 00137 00138 /// Memory allocation. psAlloc sends file and line number to p_psAlloc. 00139 #ifndef SWIG 00140 #define psAlloc(size) p_psAlloc(size, __FILE__, __LINE__) 00141 #endif // ! SWIG 00142 00143 #endif // ! DOXYGEN 00144 00145 /** Set the deallocator routine 00146 * 00147 * A deallocator routine can optionally be assigned to a memory block to 00148 * ensure that associated memory blocks also get freed, e.g., memory buffers 00149 * referenced within a struct. 00150 * 00151 */ 00152 void psMemSetDeallocator( 00153 psPtr ptr, ///< the memory block to operate on 00154 psFreeFcn freeFcn ///< the function to be executed at deallocation 00155 ); 00156 00157 /** Get the deallocator routine 00158 * 00159 * This function returns the deallocator for a memory block. A deallocator 00160 * routine can optionally be assigned to a memory block to ensure that 00161 * associated memory blocks also get freed, e.g., memory buffers referenced 00162 * within a struct. 00163 * 00164 * @return psFreeFcn the routine to be called at deallocation. 00165 */ 00166 psFreeFcn psMemGetDeallocator( 00167 psPtr ptr ///< the memory block 00168 ); 00169 00170 /** Set the memory as persistent so that it is ignored when detecting memory leaks. 00171 * 00172 * Used to mark a memory block as persistent data within the library, 00173 * i.e., non user-level data used to hold psLib's state or cache data. Such 00174 * examples of this class of memory is psTrace's trace-levels and dynamic 00175 * error codes. 00176 * 00177 * Memory marked as persistent is excluded from memory leak checks. 00178 * 00179 */ 00180 void p_psMemSetPersistent( 00181 psPtr ptr, ///< the memory block to operate on 00182 psBool value ///< true if memory is persistent, otherwise false 00183 ); 00184 00185 /** Get the memory's persistent flag. 00186 * 00187 * Checks if a memory block has been marked as persistent by 00188 * p_psMemSetPresistent. 00189 * 00190 * Memory marked as persistent is excluded from memory leak checks. 00191 * 00192 * @return psBool true if memory is marked persistent, otherwise false. 00193 */ 00194 psBool p_psMemGetPersistent( 00195 psPtr ptr ///< the memory block to check. 00196 ); 00197 00198 00199 /** Memory re-allocation. This operates much like realloc(), but is guaranteed to return a non-NULL value. 00200 * 00201 * @return psPtr pointer to resized buffer. This will not be NULL. 00202 * @see psAlloc, psFree 00203 */ 00204 #ifdef DOXYGEN 00205 psPtr psRealloc( 00206 psPtr ptr, ///< Pointer to re-allocate 00207 size_t size ///< Size required 00208 ); 00209 #else // #ifdef DOXYGEN 00210 psPtr p_psRealloc( 00211 psPtr ptr, ///< Pointer to re-allocate 00212 size_t size, ///< Size required 00213 const char *file, ///< File of call 00214 psS32 lineno ///< Line number of call 00215 ); 00216 00217 /// Memory re-allocation. psRealloc sends file and line number to p_psRealloc. 00218 #ifndef SWIG 00219 #define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__) 00220 #endif // ! SWIG 00221 00222 #endif // ! DOXYGEN 00223 00224 /** Free memory. This operates much like free(). 00225 * 00226 * @see psAlloc, psRealloc 00227 */ 00228 #ifdef DOXYGEN 00229 void psFree( 00230 psPtr ptr ///< Pointer to free, if NULL, function returns immediately. 00231 ); 00232 #else // #ifdef DOXYGEN 00233 void p_psFree( 00234 psPtr ptr, ///< Pointer to free 00235 const char *file, ///< File of call 00236 psS32 lineno ///< Line number of call 00237 ); 00238 00239 /// Free memory. psFree sends file and line number to p_psFree. 00240 #ifndef SWIG 00241 #define psFree(ptr) p_psFree(ptr, __FILE__, __LINE__) 00242 #endif // ! SWIG 00243 00244 #endif // ! DOXYGEN 00245 00246 /** Check for memory leaks. This scans for allocated memory buffers not freed with an ID not less than id0. 00247 * This is used to check for memory leaks by: 00248 * -# before a block of code to be checked, store the current ID count via psGetMemId 00249 * -# after the block of code to be checked, call this function using the ID stored above. If all 00250 * memory in the block that was allocated has been freed, this call should output nothing and 00251 * return 0. 00252 * 00253 * If memory leaks are found, the Memory Problem callback will be called as well. 00254 * 00255 * return psS32 number of memory blocks found as 'leaks', i.e., the number of currently allocated memory 00256 * blocks above id0 that have not been freed. 00257 * @see psAlloc, psFree, psgetMemId, psMemProblemCallbackSet 00258 * @ingroup memTracing 00259 */ 00260 psS32 psMemCheckLeaks( 00261 psMemoryId id0, ///< don't list blocks with id < id0 00262 psMemBlock* ** arr, ///< pointer to array of pointers to leaked blocks, or NULL 00263 FILE * fd, ///< print list of leaks to fd (or NULL) 00264 psBool persistence ///< make check across all object even persistent ones 00265 ); 00266 00267 /** Check for memory corruption. Scans all currently allocated memory buffers and checks for corruptions, 00268 * i.e., invalid markers that signify a buffer under/overflow. 00269 * 00270 * @ingroup memTracing 00271 */ 00272 psS32 psMemCheckCorruption( 00273 psBool abort_on_error ///< Abort on detecting corruption? 00274 ); 00275 00276 /** Return reference counter 00277 * 00278 * @ingroup memRefCount 00279 */ 00280 psReferenceCount psMemGetRefCounter( 00281 psPtr vptr ///< Pointer to get refCounter for 00282 ); 00283 00284 /** Increment reference counter and return the pointer 00285 * 00286 * @ingroup memRefCount 00287 */ 00288 #ifdef DOXYGEN 00289 psPtr psMemIncrRefCounter( 00290 psPtr vptr ///< Pointer to increment refCounter, and return 00291 ); 00292 #else 00293 psPtr p_psMemIncrRefCounter( 00294 psPtr vptr, ///< Pointer to increment refCounter, and return 00295 const char *file, ///< File of call 00296 psS32 lineno ///< Line number of call 00297 ); 00298 00299 #ifndef SWIG 00300 #define psMemIncrRefCounter(vptr) p_psMemIncrRefCounter(vptr, __FILE__, __LINE__) 00301 #endif // !SWIG 00302 00303 #endif // !DOXYGEN 00304 00305 /** Decrement reference counter and return the pointer 00306 * 00307 * @ingroup memRefCount 00308 * 00309 * @return psPtr the pointer deremented in refCount, or NULL if pointer is 00310 * fully dereferenced. 00311 */ 00312 #ifdef DOXYGEN 00313 psPtr psMemDecrRefCounter( 00314 psPtr vptr ///< Pointer to decrement refCounter, and return 00315 ); 00316 #else // DOXYGEN 00317 psPtr p_psMemDecrRefCounter( 00318 psPtr vptr, ///< Pointer to decrement refCounter, and return 00319 const char *file, ///< File of call 00320 psS32 lineno ///< Line number of call 00321 ); 00322 00323 #ifndef SWIG 00324 #define psMemDecrRefCounter(vptr) p_psMemDecrRefCounter(vptr, __FILE__, __LINE__) 00325 #endif // !SWIG 00326 00327 #endif // !DOXYGEN 00328 00329 /** Set callback for problems. 00330 * 00331 * At various occasions, the memory manager can check the state of the memory 00332 * stack. If any of these checks discover that the memory stack is corrupted, 00333 * the psMemProblemCallback is called. 00334 00335 * @ingroup memCallback 00336 * 00337 * @return psMemProblemCallback old psMemProblemCallback function 00338 */ 00339 psMemProblemCallback psMemProblemCallbackSet( 00340 psMemProblemCallback func ///< Function to run at memory problem detection 00341 ); 00342 00343 /** Set callback for out-of-memory. 00344 * 00345 * If not enough memory is available to satisfy a request by psAlloc or 00346 * psRealloc, these functions attempt to find an alternative solution by 00347 * calling the psMemExhaustedCallback, a function which may be set by the 00348 * programmer in appropriate circumstances, rather than immediately fail. 00349 * The typical use of such a feature may be when a program needs a large 00350 * chunk of memory to do an operation, but the exact size is not critical. 00351 * This feature gives the programmer the opportunity to make a smaller 00352 * request and try again, limiting the size of the operating buffer. 00353 * 00354 * @ingroup memCallback 00355 * 00356 * @return psMemExhaustedCallback old psMemExhaustedCallback function 00357 */ 00358 psMemExhaustedCallback psMemExhaustedCallbackSet( 00359 psMemExhaustedCallback func ///< Function to run at memory exhaustion 00360 ); 00361 00362 /** Set call back for when a particular memory block is allocated 00363 * 00364 * A private variable, p_psMemAllocateID, can be used to trace the allocation 00365 * and freeing of specific memory blocks. If p_psMemAllocateID is set and a 00366 * memory block with that ID is allocated, psMemAllocateCallback is called 00367 * just before memory is returned to the calling function. 00368 * 00369 * @ingroup memCallback 00370 * 00371 * @return psMemAllocateCallback old psMemAllocateCallback function 00372 */ 00373 psMemAllocateCallback psMemAllocateCallbackSet( 00374 psMemAllocateCallback func ///< Function to run at memory allocation of specific mem block 00375 ); 00376 00377 /** Set call back for when a particular memory block is freed 00378 * 00379 * A private variable, p_psMemFreeID, can be used to trace the freeing of 00380 * specific memory blocks. If p_psMemFreeID is set and the memory block with 00381 * the ID is about to be freed, the psMemFreeCallback callback is called just 00382 * before the memory block is freed. 00383 * 00384 * @ingroup memCallback 00385 * 00386 * @return psMemFreeCallback old psMemFreeCallback function 00387 */ 00388 psMemFreeCallback psMemFreeCallbackSet( 00389 psMemFreeCallback func ///< Function to run at memory free of specific mem block 00390 ); 00391 00392 /** get next memory ID 00393 * 00394 * @ingroup memCallback 00395 * 00396 * @return psMemoryId the next memory ID to be used 00397 */ 00398 psMemoryId psMemGetId(void); 00399 00400 /** set p_psMemAllocateID to specific id 00401 * 00402 * A private variable, p_psMemAllocateID, can be used to trace the allocation 00403 * and freeing of specific memory blocks. If p_psMemAllocateID is set and a 00404 * memory block with that ID is allocated, psMemAllocateCallback is called 00405 * just before memory is returned to the calling function. 00406 * 00407 * @ingroup memCallback 00408 * 00409 * @return psMemoryId 00410 * 00411 * @see psMemAllocateCallbackSet 00412 */ 00413 psMemoryId psMemAllocateCallbackSetID( 00414 psMemoryId id ///< ID to set 00415 ); 00416 00417 /** set p_psMemFreeID to id 00418 * 00419 * A private variable, p_psMemFreeID, can be used to trace the freeing of 00420 * specific memory blocks. If p_psMemFreeID is set and the memory block with 00421 * the ID is about to be freed, the psMemFreeCallback callback is called just 00422 * before the memory block is freed. 00423 * 00424 * @ingroup memCallback 00425 * 00426 * @return psMemoryId the old p_psMemFreeID 00427 * 00428 * @see psMemFreeCallbackSet 00429 */ 00430 psMemoryId psMemFreeCallbackSetID( 00431 psMemoryId id ///< ID to set 00432 ); 00433 00434 //@} End of Memory Management Functions 00435 00436 #ifndef DOXYGEN 00437 00438 /* 00439 * Ensure that any program using malloc/realloc/free will fail to compile 00440 */ 00441 #ifndef PS_ALLOW_MALLOC 00442 #ifdef __GNUC__ 00443 #pragma GCC poison malloc realloc calloc free 00444 #else // __GNUC__ 00445 #define malloc(S) _Pragma("error Use of malloc is not allowed. Use psAlloc instead.") 00446 #define realloc(P,S) _Pragma("error Use of realloc is not allowed. Use psRealloc instead.") 00447 #define calloc(S) _Pragma("error Use of calloc is not allowed. Use psAlloc instead.") 00448 #define free(P) _Pragma("error Use of free is not allowed. Use psFree instead.") 00449 #endif // ! __GNUC__ 00450 #endif // #ifndef PS_ALLOW_MALLOC 00451 00452 #endif // #ifndef DOXYGEN 00453 00454 #endif // #ifndef PS_MEMORY_H
1.4.1