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/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

Generated on Wed Sep 14 10:42:48 2005 for Pan-STARRS Foundation Library by  doxygen 1.4.2