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

Generated on Mon Jul 3 14:13:44 2006 for Pan-STARRS Foundation Library by  doxygen 1.4.4