Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

psMemory.h

Go to the documentation of this file.
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

Generated on Wed Jun 15 11:00:57 2005 for Pan-STARRS Foundation Library by  doxygen 1.4.1