MathEngine
Home Page       Structures       File List       Functions and Macros      

MeMemory.h

Go to the documentation of this file.
00001 #ifndef _MEMEMORY_H
00002 #define _MEMEMORY_H
00003 /*
00004   Copyright MathEngine PLC 2000
00005 
00006   MathEngine memory manager API
00007 
00008   $Name: t-release-0-0-5-msvcrt $
00009 
00010   $Id: MeMemory.h,v 1.17 2000/07/27 15:53:12 jamesg Exp $
00011 */
00012 
00013 /** @file
00014  * The memory manager API.
00015  *
00016  * This API allows a library to use an external memory manager, via a
00017  * a set of function pointers with predefined semantics.
00018  *
00019  * It also allows a library to give hints as to what kind of memory
00020  * management it prefers; the memory manager may or may not heed such
00021  * advice.
00022  *
00023  * It is expected that the debug version of the memory managers will
00024  * perform extensive checks, like verifying redzones around each block.
00025  */
00026 
00027 #include <stddef.h>
00028 
00029 #ifdef __cplusplus
00030   extern "C" {
00031 #endif
00032 
00033 /* All these options are strictly advisory. Default for all is '0',
00034    which means that the allocator chooses something general.
00035 
00036    Suppose instead that one knows in advance that one needs only blocks
00037    of sizes 8 to 12 aligned on 4 byte boundaries, and 64 aligned on 16
00038    bytes boundaries (e.g. 2-3 floats and 16 floats), and one needs
00039    exactly 400 of one and at least 850 of the other, and one likes an
00040    array based algorithm, then one can write:
00041 
00042    struct MeMemoryOptionsSize sizes[] =
00043    {
00044      { 2,       10,12,   400,400},
00045      { 4,       64,64,   850,0  }
00046    };
00047    struct MeMemoryOptions options;
00048 
00049    options.allocation = MeMemoryArrays;
00050    options.reclamation = MeMemoryManual;
00051 
00052    options.arenaAtLeast = 0;
00053    options.arenaAtMost = 0;
00054 
00055    options.blockFixed = 2;
00056    options.block.sizes = sizes;
00057 
00058    (*MeMemoryAPI.setOptions)(&options);
00059    (*MeMemoryAPI.setup)();
00060 
00061    and similarly for other policies. */
00062 
00063 /**
00064  * Type of memory allocation implementation.
00065  */
00066 enum MeMemoryAllocation
00067 {
00068   MeMemoryAny = 0,         /**< Choose any. (default, must be 0) */
00069   MeMemorySegment,         /**< Growing area, like UNIX data segment */
00070   MeMemoryBIBOP,           /**< Big bag of pages */
00071   MeMemoryBTag,            /**< Boundary tag */
00072   MeMemoryBitmap,          /**< Flat bitmap */
00073   MeMemoryBuddy,           /**< Buddy system */
00074   MeMemoryArrays,          /**< Contiguous fixed size arrays */
00075   MeMemoryPools            /**< Contiguous flexible size arrays */
00076 };
00077 
00078 /**
00079  * Type of memory reclamation policy.
00080  */
00081 enum MeMemoryReclamation
00082 {
00083   MeMemoryManual = 0,      /**< Manual/explicit. (default, must be 0) */
00084   MeMemoryNone,            /**< No memory reclamation */
00085   MeMemoryStack,           /**< Like Pascal Mark/Release */
00086   MeMemoryRefCount,        /**< Reference counting */
00087   MeMemoryGC,              /**< Vanilla conservative GC */
00088   MeMemoryGCCompacting,    /**< Compacting GC */
00089   MeMemoryGCCopying,       /**< Baker style copying GC */
00090   MeMemoryGCAged           /**< Hewitt style generational GC */
00091 };
00092 
00093 /**
00094  * Memory manager initialisation options.
00095  *
00096  * The following is pretty obvious, except for the presence of 'minSize'
00097  * and 'maxSize' for fixed size blocks. Well, the blocks are actually
00098  * 'maxSize' large (plus alignment padding), but if smaller size pools
00099  * are used up, a block smaller than 'maxSize' may be allocated in a
00100  * 'maxSize' pool, if it is at least 'minSize' large.
00101  */
00102 struct MeMemoryOptions
00103 {
00104   /** Allocation implementation */
00105   enum MeMemoryAllocation  allocation;
00106 
00107   /** Reclamation policy */
00108   enum MeMemoryReclamation reclamation;
00109 
00110   /** suggested min size of an arena */
00111   size_t                minArena;
00112   /** suggested max size of an arena */
00113   size_t                maxArena;
00114 
00115   /** # of fixed block sizes, 0: flex */
00116   unsigned              blockFixed;
00117   union
00118   {
00119     /**
00120      * Options specific to flexible block size managers.
00121      */
00122     struct MeMemoryOptionsFlex
00123     {
00124       unsigned          align2Addr;     /**< lg2 of address alignment */
00125       unsigned          align2Size;     /**< lg2 of size alignment */
00126       size_t            minSize;        /**< min size of block */
00127       size_t            maxSize;        /**< max size of block */
00128       size_t            minTotal;       /**< min amount of memory */
00129       size_t            maxTotal;       /**< max amount of memory */
00130     }
00131                         flex;           /**< if 'blockFixed' is 0 */
00132 
00133     /**
00134      * Options specific to fixed block size managers.
00135      */
00136     struct MeMemoryOptionsFixed
00137     {
00138       unsigned          align2Addr;     /**< lg2 of address alignment */
00139       size_t            minSize;        /**< minimum block size */
00140       size_t            defSize;        /**< default block size */
00141 
00142       /** min # of blocks in size range */
00143       long unsigned     minCount;
00144       /** max # of blocks in size range */
00145       long unsigned     maxCount;
00146     }
00147                         *fixed;         /**< if 'blockFixed' is > 0 */
00148   }
00149                         block;          /**< Manager specific options */
00150 };
00151 
00152 /**
00153  * Memory manager statistics.
00154  */
00155 struct MeMemoryStats
00156 {
00157   long unsigned         createCounter;  /**< # of create calls */
00158   long unsigned         resizeCounter;  /**< # of resize calls */
00159   long unsigned         incRefCounter;  /**< # of incRef calls */
00160   long unsigned         decRefCounter;  /**< # of decRef calls */
00161   long unsigned         destroyCounter; /**< # of destroy calls */
00162 
00163   /** min size of an arena so far */
00164   size_t                minArena;
00165   /** max size of an arena so far */
00166   size_t                maxArena;
00167 
00168   /** # of fixed block sizes, 0: flex */
00169   unsigned              blockFixed;
00170   union
00171   {
00172     /**
00173      * Options specific to flexible block size managers.
00174      */
00175     struct MeMemoryStatsFlex
00176     {
00177       size_t            minSize;        /**< min requested size */
00178       size_t            maxSize;        /**< max requested size */
00179       long unsigned     currentCount;   /**< current # of blocks busy */
00180       long unsigned     maxCount;       /**< max # of blocks busy */
00181 
00182       /** total memory currently busy */
00183       size_t            currentTotal;
00184       /** total memory highest ever busy */
00185       size_t            maxTotal;
00186     }
00187                         flex;           /**< if 'blockFixed' is 0 */
00188 
00189     /**
00190      * Options specific to Fixed block size managers.
00191      */
00192     struct MeMemoryStatsFixed
00193     {
00194       size_t            minSize;        /**< minimum block size */
00195       size_t            defSize;        /**< default block size */
00196 
00197       /** # of allocations size < defSize */
00198       long unsigned     minCounter;
00199       /** # of allocations size == defSize*/
00200 
00201       long unsigned     defCounter;
00202 
00203       long unsigned     currentCount;   /**< current # of blocks busy */
00204       long unsigned     maxCount;       /**< max # of blocks busy */
00205     }
00206                         *fixed;         /**< if 'blockFixed' is > 0 */
00207   }
00208                         block;          /**< manager specific options */
00209 };
00210 
00211 /**
00212  * Table of pointers to memory manager functions.
00213  *
00214  * Each memory manager usable via this API will come with a set of API
00215  * compliant wrapper functions, that will be packaged in a 'struct'
00216  * similar to this one. At program startup copy that into the canonical
00217  * one called 'MeMemoryAPI' to initialise it.
00218  */
00219 struct MeMemoryAPI
00220 {
00221   /**
00222    * Set memory manager API options.
00223    *
00224    * Use this to setup the memory manager API with hints as to what
00225    * kind of memory manager and policy it should select.
00226    */
00227   void                  (*setOptions)(const struct MeMemoryOptions
00228                                       *const options);
00229   /**
00230    * Get memory manager API options.
00231    *
00232    * Returns the memory manager options that have been set.
00233    */
00234   void                  (*getOptions)(struct MeMemoryOptions
00235                                       *const options);
00236 
00237   /**
00238    * Initialize the memory manager.
00239    *
00240    * Allows memory manager initialisation. You should first call
00241    * setOptions to inform the API what kind of memory manager is
00242    * desirable, and getStats to see what kind of memory arena size the
00243    * API thinks that requires.
00244    *
00245    * Then, if necessary, allocate that size (or something else) and pass
00246    * it the allocate arena to this function.
00247    */
00248   void                  (*init)(void *const arena,const size_t bytes,...);
00249 
00250   /**
00251    * Allocate a block of at least that given size.
00252    *
00253    * If there are any options (form example for placement) then these
00254    * can be specified after the size, but this will be highly unportable.
00255    *
00256    * The in-use count of the newly created block will be one.
00257    */
00258   void                  *(*create)(size_t bytes,...);
00259   /**
00260    * Change the size of a block, possibly moving it.
00261    *
00262    * If there are any options (form example for placement) then these
00263    * can be specified after the size, but this will be highly
00264    * unportable.
00265    *
00266    * This function may fail as it may be unavailable under some memory
00267    * managers, or the specific resizing may be impossible or
00268    * unsupported.  In particular resizing to a smaller size may be
00269    * forbidden, or resizing to a larger one may not be feasible.
00270    */
00271   void                  *(*resize)(void *block,size_t bytes,...);
00272   /**
00273    * Increment the in-use count of a block.
00274    *
00275    * This function may actually do nothing.
00276    */
00277   void                  (*incRef)(const void *const block);
00278   /**
00279    * Decrement the in-use count of a block.
00280    *
00281    * This function may actually do nothing.
00282    */
00283   void                  (*decRef)(const void *const block);
00284   /**
00285    * Reduce the in-use count of a block to zero.
00286    *
00287    * This function may actually do nothing, for example when the
00288    * memory manager does automatic reclamation via garbage collection.
00289    */
00290   void                  (*destroy)(void *const block,...);
00291 
00292   /**
00293    * Obtain a copy of the usage statistics of the memory manager API.
00294    *
00295    * The statistics returned may be incomplete, depending on how many
00296    * are supported by the memory manager itself. It can be called after
00297    * setOptions and before init to
00298    */
00299   void                  (*getStats)(struct MeMemoryStats *const stats);
00300   /**
00301    * Terminate memory manager API operation.
00302    *
00303    * Invoking this will often be needed in order to collect some types
00304    * of statistics. It also will often check that usage of the API has
00305    * been correct, e.g. that the number of calls to incRef and to decRef
00306    * has been the same.
00307    */
00308   void                  (*term)();
00309 };
00310 
00311 /* The table of memory manager API functions */
00312 
00313 extern struct MeMemoryAPI  MeMemoryAPI;
00314 
00315 /* Enable or disable tracing and statistics, if compiled in */
00316 
00317 extern unsigned         MeMemoryDoTrace;
00318 extern unsigned         MeMemoryDoStats;
00319 
00320 #if (__GNUC__)
00321 # define MeMemoryALLOCA(n) __builtin_alloca(n)
00322 # define MeMemoryFREEA(b)  ((void) 0)
00323 #else
00324 #ifdef IRIX
00325 # include <alloca.h>
00326 # define MeMemoryALLOCA(n) alloca(n)
00327 # define MeMemoryFREEA(b)  ((void) 0)
00328 #endif
00329 #endif
00330 
00331 #if (_MSC_VER)
00332 # include <malloc.h>
00333 # define MeMemoryALLOCA(n) _alloca(n)
00334 # define MeMemoryFREEA(b)  ((void) 0)
00335 #endif
00336 
00337   
00338 #if (!defined MeMemoryALLOCA)
00339   /**
00340    * Stack allocation.
00341    *
00342    * If the compiler supports stack allocation (GNU C or MS C)
00343    * then the relevant compiler intrinsics are used. Otherwise
00344    * it uses heap allocation, which is why a FREEA function is
00345    * needed too, and you must use it.
00346    */
00347 # define MeMemoryALLOCA(n) ((*MeMemoryAPI.create)(n))
00348   /**
00349    * Stack deallocation.
00350    *
00351    * If the compiler supports stack allocation (GNU C or MS C)
00352    * then this does nothing. Otherwise heap allocation has been used
00353    * and this just destroys the heap allocated block.
00354    */
00355 # define MeMemoryFREEA(b)  ((*MeMemoryAPI.destroy)(b))
00356 #endif
00357 
00358 
00359 #define MeMemoryQUADALIGNED(n)    assert((((long unsigned) (n)) % 16) == 0)
00360 
00361 #define MeMemoryQUADALIGN(a) \
00362     ((void *) ((((long unsigned) (void *) (a)) + 15) &~ 15))
00363 
00364 
00365 #ifdef MeMemoryALLOCA
00366 # define MeMemoryQUADALIGNEDALLOCA(name, type, n) \
00367         void *name##Addr = \
00368             MeMemoryALLOCA(((n) * sizeof (type)) + 16); \
00369         type *name = (type *) MeMemoryQUADALIGN(name##Addr);
00370 
00371 # define MeMemoryQUADALIGNEDFREEA(name) \
00372         MeMemoryFREEA(name##Addr)
00373 #endif
00374 
00375 /* These functions can be used to print an options or statistics
00376    record returned from 'getOptions' or 'getStats'. */
00377 
00378 void                    MeMemoryPrintOptions(const struct MeMemoryOptions
00379                           *const options);
00380 void                    MeMemoryPrintStats(const struct MeMemoryStats
00381                           *const stats);
00382 
00383 /* This sets the options to some defaults values. */
00384 void                    MeMemorySetDefaults(struct MeMemoryOptions
00385                           *const opts);
00386 
00387 /**
00388  * This flag allows testing whether the API is being used
00389  */
00390 #define MeMemoryAVAILABLE  1
00391 
00392 #ifdef __cplusplus
00393   }
00394 #endif
00395 
00396 #endif

MathEngine Utilities: Memory Manager API - Version 0.0.5 Alpha - Reference Manual generated using doxygen at Wed Oct 11 00:34:57 2000

Copyright MathEngine PLC 2000, all rights reserved.