lib/memalloc.c

Go to the documentation of this file.
00001 /* memalloc.c - Routines to allocate and deallocate dynamic memory. 
00002  * This lets you have a stack of memory handlers.  The default
00003  * memory handler is a thin shell around malloc/free.  You can
00004  * substitute routines that do more integrety checking with
00005  * pushCarefulMem(), or routines of your own devising with
00006  * pushMemHandler(). 
00007  *
00008  * This file is copyright 2002 Jim Kent, but license is hereby
00009  * granted for all use - public, private or commercial. */
00010 
00011 #include "common.h"
00012 #include "obscure.h"
00013 #include "memalloc.h"
00014 #include "dlist.h"
00015 
00016 static char const rcsid[] = "$Id: memalloc.c,v 1.30 2007/03/07 01:46:43 angie Exp $";
00017 
00018 static void *defaultAlloc(size_t size)
00019 /* Default allocator. */
00020 {
00021 return malloc(size);
00022 }
00023 
00024 static void defaultFree(void *vpt)
00025 /* Default deallocator. */
00026 {
00027 free(vpt);
00028 }
00029 
00030 static void *defaultRealloc(void *vpt, size_t size)
00031 /* Default deallocator. */
00032 {
00033 return realloc(vpt, size);
00034 }
00035 
00036 static struct memHandler defaultMemHandler = 
00037 /* Default memory handler. */
00038     {
00039     NULL,
00040     defaultAlloc,
00041     defaultFree,
00042     defaultRealloc,
00043     };
00044 
00045 static struct memHandler *mhStack = &defaultMemHandler;
00046 
00047 struct memHandler *pushMemHandler(struct memHandler *newHandler)
00048 /* Use newHandler for memory requests until matching popMemHandler.
00049  * Returns previous top of memory handler stack. */
00050 {
00051 struct memHandler *oldHandler = mhStack;
00052 slAddHead(&mhStack, newHandler);
00053 return oldHandler;
00054 }
00055 
00056 
00057 struct memHandler *popMemHandler()
00058 /* Removes top element from memHandler stack and returns it. */
00059 {
00060 struct memHandler *oldHandler = mhStack;
00061 if (mhStack == &defaultMemHandler)
00062     errAbort("Too many popMemHandlers()");
00063 mhStack = mhStack->next;
00064 return oldHandler;
00065 }
00066 
00067 
00068 void setDefaultMemHandler()
00069 /* Sets memHandler to the default. */
00070 {
00071 mhStack = &defaultMemHandler;
00072 }
00073 
00074 /* 128*8*1024*1024 == 1073741824 == 2^30 on 32 bit machines,size_t == 4 bytes*/
00075 /* on 64 bit machines, size_t = 8 bytes, 2^30 * 2 * 2 = 2^32 == 4 Gb */
00076 static size_t maxAlloc = 128*8*1024*1024*(sizeof(size_t)/4)*(sizeof(size_t)/4);
00077 
00078 void setMaxAlloc(size_t s)
00079 /* Set large allocation limit. */
00080 {
00081 maxAlloc = s;
00082 }
00083 
00084 void *needLargeMem(size_t size)
00085 /* This calls abort if the memory allocation fails. The memory is
00086  * not initialized to zero. */
00087 {
00088 void *pt;
00089 if (size == 0 || size >= maxAlloc)
00090     errAbort("needLargeMem: trying to allocate %llu bytes (limit: %llu)",
00091          (unsigned long long)size, (unsigned long long)maxAlloc);
00092 if ((pt = mhStack->alloc(size)) == NULL)
00093     errAbort("needLargeMem: Out of memory - request size %llu bytes\n",
00094              (unsigned long long)size);
00095 return pt;
00096 }
00097 
00098 void *needLargeZeroedMem(size_t size)
00099 /* Request a large block of memory and zero it. */
00100 {
00101 void *v;
00102 v = needLargeMem(size);
00103 memset(v, 0, size);
00104 return v;
00105 }
00106 
00107 void *needLargeMemResize(void* vp, size_t size)
00108 /* Adjust memory size on a block, possibly relocating it.  If vp is NULL,
00109  * a new memory block is allocated.  Memory not initted. */
00110 {
00111 void *pt;
00112 if (size == 0 || size >= maxAlloc)
00113     errAbort("needLargeMemResize: trying to allocate %llu bytes (limit: %llu)",
00114          (unsigned long long)size, (unsigned long long)maxAlloc);
00115 if ((pt = mhStack->realloc(vp, size)) == NULL)
00116     errAbort("needLargeMemResize: Out of memory - request size %llu bytes\n",
00117              (unsigned long long)size);
00118 return pt;
00119 }
00120 
00121 void *needLargeZeroedMemResize(void* vp, size_t oldSize, size_t newSize)
00122 /* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
00123  * new memory block is allocated.  If block is grown, new memory is zeroed. */
00124 {
00125 void *v = needLargeMemResize(vp, newSize);
00126 if (newSize > oldSize)
00127     memset(((char*)v)+oldSize, 0, newSize-oldSize);
00128 return v;
00129 }
00130 
00131 void *needHugeMem(size_t size)
00132 /* No checking on size.  Memory not initted. */
00133 {
00134 void *pt;
00135 if (size == 0)
00136     errAbort("needHugeMem: trying to allocate 0 bytes");
00137 if ((pt = mhStack->alloc(size)) == NULL)
00138     errAbort("needHugeMen: Out of huge memory - request size %llu bytes\n",
00139              (unsigned long long)size);
00140 return pt;
00141 }
00142 
00143 
00144 void *needHugeZeroedMem(size_t size)
00145 /* Request a large block of memory and zero it. */
00146 {
00147 void *v;
00148 v = needHugeMem(size);
00149 memset(v, 0, size);
00150 return v;
00151 }
00152 
00153 void *needHugeMemResize(void* vp, size_t size)
00154 /* Adjust memory size on a block, possibly relocating it.  If vp is NULL,
00155  * a new memory block is allocated.  No checking on size.  Memory not
00156  * initted. */
00157 {
00158 void *pt;
00159 if ((pt = mhStack->realloc(vp, size)) == NULL)
00160     errAbort("needHugeMemResize: Out of memory - request resize %llu bytes\n",
00161         (unsigned long long)size);
00162 return pt;
00163 }
00164 
00165 
00166 void *needHugeZeroedMemResize(void* vp, size_t oldSize, size_t newSize)
00167 /* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
00168  * new memory block is allocated.  No checking on size.  If block is grown,
00169  * new memory is zeroed. */
00170 {
00171 void *v;
00172 v = needHugeMemResize(vp, newSize);
00173 if (newSize > oldSize)
00174     memset(((char*)v)+oldSize, 0, newSize-oldSize);
00175 return v;
00176 }
00177 
00178 #define NEEDMEM_LIMIT 500000000
00179 
00180 void *needMem(size_t size)
00181 /* Need mem calls abort if the memory allocation fails. The memory
00182  * is initialized to zero. */
00183 {
00184 void *pt;
00185 if (size == 0 || size > NEEDMEM_LIMIT)
00186     errAbort("needMem: trying to allocate %llu bytes (limit: %llu)",
00187          (unsigned long long)size, (unsigned long long)NEEDMEM_LIMIT);
00188 if ((pt = mhStack->alloc(size)) == NULL)
00189     errAbort("needMem: Out of memory - request size %llu bytes\n",
00190              (unsigned long long)size);
00191 memset(pt, 0, size);
00192 return pt;
00193 }
00194 
00195 void *needMoreMem(void *old, size_t oldSize, size_t newSize)
00196 /* Adjust memory size on a block, possibly relocating it.  If vp is NULL, a
00197  * new memory block is allocated.  No checking on size.  If block is grown,
00198  * new memory is zeroed. */
00199 {
00200 return needLargeZeroedMemResize(old, oldSize, newSize);
00201 }
00202 
00203 void *wantMem(size_t size)
00204 /* Want mem just calls malloc - no zeroing of memory, no
00205  * aborting if request fails. */
00206 {
00207 return mhStack->alloc(size);
00208 }
00209 
00210 void freeMem(void *pt)
00211 /* Free memory will check for null before freeing. */
00212 {
00213 if (pt != NULL)
00214     mhStack->free(pt);
00215 }
00216 
00217 void freez(void *vpt)
00218 /* Pass address of pointer.  Will free pointer and set it 
00219  * to NULL. */
00220 {
00221 void **ppt = (void **)vpt;
00222 void *pt = *ppt;
00223 *ppt = NULL;
00224 freeMem(pt);
00225 }
00226 
00227 static int carefulAlignSize;    /* Alignment size for machine - 8 bytes for DEC alpha, 4 for Sparc. */
00228 static int carefulAlignAdd;     /* Do aliSize = *(unaliSize+carefulAlignAdd)&carefulAlignMask); */
00229 
00230 #if __WORDSIZE == 64
00231 static bits64 carefulAlignMask;    /* to make sure requests are aligned. */
00232 #elif __WORDSIZE == 32
00233 static bits32 carefulAlignMask;    /* to make sure requests are aligned. */
00234 #else
00235 static bits32 carefulAlignMask;    /* to make sure requests are aligned. */
00236 #endif
00237 
00238 static struct memHandler *carefulParent;
00239 
00240 static size_t carefulMaxToAlloc;
00241 static size_t carefulAlloced;
00242 
00243 struct carefulMemBlock
00244 /* Keep one of these for each outstanding memory block.   It's a doubly linked list. */
00245     {
00246     struct carefulMemBlock *next;
00247     struct carefulMemBlock *prev;
00248     int size;
00249     int startCookie;
00250     };
00251 
00252 int cmbStartCookie = 0x78753421;
00253 
00254 char cmbEndCookie[4] = {0x44, 0x33, 0x7F, 0x42};
00255 
00256 struct dlList *cmbAllocedList;
00257 
00258 static void carefulMemInit(size_t maxToAlloc)
00259 /* Initialize careful memory system */
00260 {
00261 carefulMaxToAlloc = maxToAlloc;
00262 cmbAllocedList = newDlList();
00263 carefulAlignSize = sizeof(double);
00264 if (sizeof(void *) > carefulAlignSize)
00265     carefulAlignSize = sizeof(void *);
00266 if (sizeof(long) > carefulAlignSize)
00267     carefulAlignSize = sizeof(long);
00268 if (sizeof(off_t) > carefulAlignSize)
00269     carefulAlignSize = sizeof(off_t);
00270 if (sizeof(long long) > carefulAlignSize)
00271     carefulAlignSize = sizeof(long long);
00272 carefulAlignAdd = carefulAlignSize-1;
00273 carefulAlignMask = ~carefulAlignAdd;
00274 }
00275 
00276 
00277 static void *carefulAlloc(size_t size)
00278 /* Allocate extra memory for cookies and list node, and then
00279  * return memory block. */
00280 {
00281 struct carefulMemBlock *cmb;
00282 char *pEndCookie;
00283 size_t newAlloced = size + carefulAlloced;
00284 size_t aliSize;
00285 
00286 if (newAlloced > carefulMaxToAlloc)
00287     {
00288     char maxAlloc[32];
00289     char allocRequest[32];
00290     sprintLongWithCommas(maxAlloc, (long long)carefulMaxToAlloc);
00291     sprintLongWithCommas(allocRequest, (long long)newAlloced);
00292     errAbort("Allocated too much memory - more than %s bytes (%s)",
00293         maxAlloc, allocRequest);
00294     }
00295 carefulAlloced = newAlloced;
00296 aliSize = ((size + sizeof(*cmb) + 4 + carefulAlignAdd)&carefulAlignMask);
00297 cmb = carefulParent->alloc(aliSize);
00298 cmb->size = size;
00299 cmb->startCookie = cmbStartCookie;
00300 pEndCookie = (char *)(cmb+1);
00301 pEndCookie += size;
00302 memcpy(pEndCookie, cmbEndCookie, sizeof(cmbEndCookie));
00303 dlAddHead(cmbAllocedList, (struct dlNode *)cmb);
00304 return (void *)(cmb+1);
00305 }
00306 
00307 static void carefulFree(void *vpt)
00308 /* Check cookies and free. */
00309 {
00310 struct carefulMemBlock *cmb = ((struct carefulMemBlock *)vpt)-1;
00311 size_t size = cmb->size;
00312 char *pEndCookie;
00313 
00314 carefulAlloced -= size;
00315 pEndCookie = (((char *)(cmb+1)) + size);
00316 if (cmb->startCookie != cmbStartCookie)
00317     errAbort("Bad start cookie %x freeing %llx\n", cmb->startCookie,
00318              ptrToLL(vpt));
00319 if (memcmp(pEndCookie, cmbEndCookie, sizeof(cmbEndCookie)) != 0)
00320     errAbort("Bad end cookie %x%x%x%x freeing %llx\n", 
00321         pEndCookie[0], pEndCookie[1], pEndCookie[2], pEndCookie[3],
00322              ptrToLL(vpt));
00323 dlRemove((struct dlNode *)cmb);
00324 carefulParent->free(cmb);
00325 }
00326 
00327 
00328 static void *carefulRealloc(void *vpt, size_t size)
00329 /* realloc a careful memblock block. */
00330 {
00331 unsigned char* newBlk = carefulAlloc(size);
00332 if (vpt != NULL)
00333     {
00334     struct carefulMemBlock *cmb = ((struct carefulMemBlock *)vpt)-1;
00335     memcpy(newBlk, vpt, cmb->size);
00336     carefulFree(vpt);
00337     }
00338 return newBlk;
00339 }
00340 
00341 
00342 void carefulCheckHeap()
00343 /* Walk through allocated memory and make sure that all cookies are
00344  * in place. */
00345 {
00346 int maxPieces = 10000000;    /* Assume no more than this many pieces allocated. */
00347 struct carefulMemBlock *cmb;
00348 char *pEndCookie;
00349 size_t size;
00350 
00351 if (carefulParent == NULL)
00352     return;
00353 
00354 for (cmb = (struct carefulMemBlock *)(cmbAllocedList->head); cmb->next != NULL; cmb = cmb->next)
00355     {
00356     size = cmb->size;
00357     pEndCookie = (((char *)(cmb+1)) + size);
00358     if (cmb->startCookie != cmbStartCookie)
00359         errAbort("Bad start cookie %x checking %llx\n", cmb->startCookie,
00360                  ptrToLL(cmb+1));
00361     if (memcmp(pEndCookie, cmbEndCookie, sizeof(cmbEndCookie)) != 0)
00362         errAbort("Bad end cookie %x%x%x%x checking %llx\n", 
00363                  pEndCookie[0], pEndCookie[1], pEndCookie[2], pEndCookie[3],
00364                  ptrToLL(cmb+1));
00365     if (--maxPieces == 0)
00366         errAbort("Loop or more than 10000000 pieces in memory list");
00367     }
00368 }
00369 
00370 int carefulCountBlocksAllocated()
00371 /* How many memory items are allocated? */
00372 {
00373 return dlCount(cmbAllocedList);
00374 }
00375 
00376 long carefulTotalAllocated()
00377 /* Return total bases allocated */
00378 {
00379 return carefulAlloced;
00380 }
00381 
00382 static struct memHandler carefulMemHandler = 
00383 /* Default memory handler. */
00384     {
00385     NULL,
00386     carefulAlloc,
00387     carefulFree,
00388     carefulRealloc,
00389     };
00390 
00391 void pushCarefulMemHandler(size_t maxAlloc)
00392 /* Push the careful (paranoid, conservative, checks everything)
00393  * memory handler  top of the memHandler stack and use it. */
00394 {
00395 carefulMemInit(maxAlloc);
00396 carefulParent = pushMemHandler(&carefulMemHandler);
00397 }
00398 
00399 struct memTracker
00400 /* A structure to keep track of memory. */
00401     {
00402     struct memTracker *next;     /* Next in list. */
00403     struct dlList *list;         /* List of allocated blocks. */
00404     struct memHandler *parent;   /* Underlying memory handler. */
00405     struct memHandler *handler;  /* Memory handler. */
00406     };
00407 
00408 static struct memTracker *memTracker = NULL;    /* Head in memTracker list. */
00409 
00410 static void *memTrackerAlloc(size_t size)
00411 /* Allocate extra memory for cookies and list node, and then
00412  * return memory block. */
00413 {
00414 struct dlNode *node;
00415 
00416 size += sizeof (*node);
00417 node = memTracker->parent->alloc(size);
00418 if (node == NULL)
00419     return node;
00420 dlAddTail(memTracker->list, node);
00421 return (void*)(node+1);
00422 }
00423 
00424 static void memTrackerFree(void *vpt)
00425 /* Check cookies and free. */
00426 {
00427 struct dlNode *node = vpt;
00428 node -= 1;
00429 dlRemove(node);
00430 memTracker->parent->free(node);
00431 }
00432 
00433 static void *memTrackerRealloc(void *vpt, size_t size)
00434 /* Resize a memory block from memTrackerAlloc. */
00435 {
00436 if (vpt == NULL)
00437     return memTrackerAlloc(size);
00438 else
00439     {
00440     struct dlNode *node = ((struct dlNode *)vpt)-1;
00441     size += sizeof(*node);
00442     dlRemove(node);
00443     node = memTracker->parent->realloc(node, size);
00444     if (node == NULL)
00445         return node;
00446     dlAddTail(memTracker->list, node);
00447     return (void*)(node+1);
00448     }
00449 }
00450 
00451 void memTrackerStart()
00452 /* Push memory handler that will track blocks allocated so that
00453  * they can be automatically released with memTrackerEnd().  You
00454  * can have memTrackerStart one after the other, but memTrackerStart/End
00455  * need to nest. */
00456 {
00457 struct memTracker *mt;
00458 
00459 if (memTracker != NULL)
00460      errAbort("multiple memTrackerStart calls");
00461 AllocVar(mt);
00462 AllocVar(mt->handler);
00463 mt->handler->alloc = memTrackerAlloc;
00464 mt->handler->free = memTrackerFree;
00465 mt->handler->realloc = memTrackerRealloc;
00466 mt->list = dlListNew();
00467 mt->parent = pushMemHandler(mt->handler);
00468 memTracker = mt;
00469 }
00470 
00471 void memTrackerEnd()
00472 /* Free any remaining blocks and pop tracker memory handler. */
00473 {
00474 struct memTracker *mt = memTracker;
00475 if (mt == NULL)
00476     errAbort("memTrackerEnd without memTrackerStart");
00477 memTracker = NULL;
00478 popMemHandler();
00479 dlListFree(&mt->list);
00480 freeMem(mt->handler);
00481 freeMem(mt);
00482 }

Generated on Tue Dec 25 18:39:31 2007 for blat by  doxygen 1.5.2