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
Copyright MathEngine PLC 2000, all rights reserved.