usermode/library/malloc-hoard-old/src/dlmalloc.c

00001 /* 
00002   A version of malloc/free/realloc written by Doug Lea and released to the 
00003   public domain. 
00004 
00005   VERSION 2.5
00006 
00007 * History:
00008     Based loosely on libg++-1.2X malloc. (It retains some of the overall 
00009        structure of old version,  but most details differ.)
00010     trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
00011     fixups Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
00012       * removed potential for odd address access in prev_chunk
00013       * removed dependency on getpagesize.h
00014       * misc cosmetics and a bit more internal documentation
00015       * anticosmetics: mangled names in macros to evade debugger strangeness
00016       * tested on sparc, hp-700, dec-mips, rs6000 
00017           with gcc & native cc (hp, dec only) allowing
00018           Detlefs & Zorn comparison study (to appear, SIGPLAN Notices.)
00019 
00020      Sat Apr  2 06:51:25 1994  Doug Lea  (dl at g)
00021       * Propagate failure in realloc if malloc returns 0
00022       * Add stuff to allow compilation on non-ANSI compilers
00023 
00024 * Overview
00025 
00026   This malloc, like any other, is a compromised design. 
00027 
00028   Chunks of memory are maintained using a `boundary tag' method as
00029   described in e.g., Knuth or Standish.  The size of the chunk is
00030   stored both in the front of the chunk and at the end.  This makes
00031   consolidating fragmented chunks into bigger chunks very fast.  The
00032   size field also hold a bit representing whether a chunk is free or
00033   in use.
00034 
00035   Malloced chunks have space overhead of 8 bytes: The preceding and
00036   trailing size fields.  When a chunk is freed, 8 additional bytes are
00037   needed for free list pointers. Thus, the minimum allocatable size is
00038   16 bytes.  8 byte alignment is currently hardwired into the design.
00039   This seems to suffice for all current machines and C compilers.
00040   Calling memalign will return a chunk that is both 8-byte aligned
00041   and meets the requested (power of two) alignment.
00042 
00043   It is assumed that 32 bits suffice to represent chunk sizes.  The
00044   maximum size chunk is 2^31 - 8 bytes.  malloc(0) returns a pointer
00045   to something of the minimum allocatable size.  Requests for negative
00046   sizes (when size_t is signed) or with the highest bit set (when
00047   unsigned) will also return a minimum-sized chunk.
00048 
00049   Available chunks are kept in doubly linked lists. The lists are
00050   maintained in an array of bins using a power-of-two method, except
00051   that instead of 32 bins (one for each 1 << i), there are 128: each
00052   power of two is split in quarters.  Chunk sizes up to 128 are
00053   treated specially; they are categorized on 8-byte boundaries.  This
00054   both better distributes them and allows for special faster
00055   processing.
00056 
00057   The use of very fine bin sizes closely approximates the use of one
00058   bin per actually used size, without necessitating the overhead of
00059   locating such bins. It is especially desirable in common
00060   applications where large numbers of identically-sized blocks are
00061   malloced/freed in some dynamic manner, and then later are all freed.
00062   The finer bin sizes make finding blocks fast, with little wasted
00063   overallocation. The consolidation methods ensure that once the
00064   collection of blocks is no longer useful, fragments are gathered
00065   into bigger chunks awaiting new roles.
00066 
00067   The bins av[i] serve as heads of the lists. Bins contain a dummy
00068   header for the chunk lists. Each bin has two lists. The `dirty' list
00069   holds chunks that have been returned (freed) and not yet either
00070   re-malloc'ed or consolidated. (A third free-standing list contains
00071   returned chunks that have not yet been processed at all.) The `clean'
00072   list holds split-off fragments and consolidated space. All
00073   procedures maintain the invariant that no clean chunk physically
00074   borders another clean chunk. Thus, clean chunks never need to be
00075   scanned during consolidation.
00076 
00077 * Algorithms
00078 
00079   Malloc:
00080 
00081     This is a very heavily disguised first-fit algorithm.
00082     Most of the heuristics are designed to maximize the likelihood
00083     that a usable chunk will most often be found very quickly,
00084     while still minimizing fragmentation and overhead.
00085 
00086     The allocation strategy has several phases:
00087 
00088       0. Convert the request size into a usable form. This currently
00089          means to add 8 bytes overhead plus possibly more to obtain
00090          8-byte alignment. Call this size `nb'.
00091 
00092       1. Check if the last returned (free()'d) or preallocated chunk
00093          is of the exact size nb. If so, use it.  `Exact' means no
00094          more than MINSIZE (currently 16) bytes larger than nb. This
00095          cannot be reduced, since a chunk with size < MINSIZE cannot
00096          be created to hold the remainder.
00097 
00098          This check need not fire very often to be effective.  It
00099          reduces overhead for sequences of requests for the same
00100          preallocated size to a dead minimum.
00101 
00102       2. Look for a dirty chunk of exact size in the bin associated
00103          with nb.  `Dirty' chunks are those that have never been
00104          consolidated.  Besides the fact that they, but not clean
00105          chunks require scanning for consolidation, these chunks are
00106          of sizes likely to be useful because they have been
00107          previously requested and then freed by the user program.
00108 
00109          Dirty chunks of bad sizes (even if too big) are never used
00110          without consolidation. Among other things, this maintains the
00111          invariant that split chunks (see below) are ALWAYS clean.
00112 
00113          2a If there are dirty chunks, but none of the right size,
00114              consolidate them all, as well as any returned chunks
00115              (i.e., the ones from step 3). This is all a heuristic for
00116              detecting and dealing with excess fragmentation and
00117              random traversals through memory that degrade
00118              performance especially when the user program is running
00119              out of physical memory.
00120 
00121       3. Pull other requests off the returned chunk list, using one if
00122          it is of exact size, else distributing into the appropriate
00123          bins.
00124 
00125       4. Try to use the last chunk remaindered during a previous
00126          malloc. (The ptr to this chunk is kept in var last_remainder,
00127          to make it easy to find and to avoid useless re-binning
00128          during repeated splits.  The code surrounding it is fairly
00129          delicate. This chunk must be pulled out and placed in a bin
00130          prior to any consolidation, to avoid having other pointers
00131          point into the middle of it, or try to unlink it.) If
00132          it is usable, proceed to step 9.
00133 
00134       5. Scan through clean chunks in the bin, choosing any of size >=
00135          nb. Split later (step 9) if necessary below.  (Unlike in step
00136          2, it is good to split here, because it creates a chunk of a
00137          known-to-be-useful size out of a fragment that happened to be
00138          close in size.)
00139 
00140       6. Scan through the clean lists of all larger bins, selecting
00141          any chunk at all. (It will surely be big enough since it is
00142          in a bigger bin.)  The scan goes upward from small bins to
00143          large.  It would be faster downward, but could lead to excess
00144          fragmentation. If successful, proceed to step 9.
00145 
00146       7. Consolidate chunks in other dirty bins until a large enough
00147          chunk is created. Break out to step 9 when one is found.
00148 
00149          Bins are selected for consolidation in a circular fashion
00150          spanning across malloc calls. This very crudely approximates
00151          LRU scanning -- it is an effective enough approximation for
00152          these purposes.
00153 
00154       8. Get space from the system using sbrk.
00155 
00156          Memory is gathered from the system (via sbrk) in a way that
00157          allows chunks obtained across different sbrk calls to be
00158          consolidated, but does not require contiguous memory. Thus,
00159          it should be safe to intersperse mallocs with other sbrk
00160          calls.
00161 
00162       9. If the selected chunk is too big, then:
00163 
00164          9a If this is the second split request for nb bytes in a row,
00165              use this chunk to preallocate up to MAX_PREALLOCS
00166              additional chunks of size nb and place them on the
00167              returned chunk list.  (Placing them here rather than in
00168              bins speeds up the most common case where the user
00169              program requests an uninterrupted series of identically
00170              sized chunks. If this is not true, the chunks will be
00171              binned in step 3 next time.)
00172 
00173          9b Split off the remainder and place in last_remainder.
00174              Because of all the above, the remainder is always a
00175              `clean' chunk.
00176 
00177      10.  Return the chunk.
00178 
00179 
00180   Free: 
00181     Deallocation (free) consists only of placing the chunk on a list
00182     of returned chunks. free(0) has no effect.  Because freed chunks
00183     may be overwritten with link fields, this malloc will often die
00184     when freed memory is overwritten by user programs.  This can be
00185     very effective (albeit in an annoying way) in helping users track
00186     down dangling pointers.
00187 
00188   Realloc:
00189     Reallocation proceeds in the usual way. If a chunk can be extended,
00190     it is, else a malloc-copy-free sequence is taken. 
00191 
00192   Memalign, valloc:
00193     memalign arequests more than enough space from malloc, finds a spot
00194     within that chunk that meets the alignment request, and then
00195     possibly frees the leading and trailing space. Overreliance on
00196     memalign is a sure way to fragment space.
00197 
00198 * Other implementation notes
00199 
00200   This malloc is NOT designed to work in multiprocessing applications.
00201   No semaphores or other concurrency control are provided to ensure
00202   that multiple malloc or free calls don't run at the same time, which
00203   could be disasterous. A single semaphore could be used across malloc,
00204   realloc, and free. It would be hard to obtain finer granularity.
00205 
00206   The implementation is in straight, hand-tuned ANSI C.  Among other
00207   consequences, it uses a lot of macros. These would be nicer as
00208   inlinable procedures, but using macros allows use with non-inlining
00209   compilers, and also makes it a bit easier to control when they
00210   should be expanded out by selectively embedding them in other macros
00211   and procedures. (According to profile information, it is almost, but
00212   not quite always best to expand.)
00213 
00214 */
00215 
00216 
00217 /* TUNABLE PARAMETERS */
00218 
00219 /* 
00220   SBRK_UNIT is a good power of two to call sbrk with It should
00221   normally be system page size or a multiple thereof.  If sbrk is very
00222   slow on a system, it pays to increase this.  Otherwise, it should
00223   not matter too much.
00224 */
00225 
00226 #define SBRK_UNIT 8192
00227 
00228 /* 
00229   MAX_PREALLOCS is the maximum number of chunks to preallocate.  The
00230   actual number to prealloc depends on the available space in a
00231   selected victim, so typical numbers will be less than the maximum.
00232   Because of this, the exact value seems not to matter too much, at
00233   least within values from around 1 to 100.  Since preallocation is
00234   heuristic, making it too huge doesn't help though. It may blindly
00235   create a lot of chunks when it turns out not to need any more, and
00236   then consolidate them all back again immediatetly. While this is
00237   pretty fast, it is better to avoid it.
00238 */
00239 
00240 #define MAX_PREALLOCS 5
00241 
00242 /* preliminaries */
00243 
00244 #ifndef __STD_C
00245 #ifdef __STDC__
00246 #define __STD_C         1
00247 #else
00248 #if __cplusplus
00249 #define __STD_C         1
00250 #else
00251 #define __STD_C         0
00252 #endif /*__cplusplus*/
00253 #endif /*__STDC__*/
00254 #endif /*__STD_C*/
00255 
00256 
00257 #ifndef _BEGIN_EXTERNS_
00258 #ifdef __cplusplus
00259 #define _BEGIN_EXTERNS_ extern "C" {
00260 #define _END_EXTERNS_   }
00261 #else
00262 #define _BEGIN_EXTERNS_
00263 #define _END_EXTERNS_
00264 #endif
00265 #endif /*_BEGIN_EXTERNS_*/
00266 
00267 #ifndef _ARG_
00268 #if __STD_C
00269 #define _ARG_(x)        x
00270 #else
00271 #define _ARG_(x)        ()
00272 #endif
00273 #endif /*_ARG_*/
00274 
00275 #ifndef Void_t
00276 #if __STD_C
00277 #define Void_t          void
00278 #else
00279 #define Void_t          char
00280 #endif
00281 #endif /*Void_t*/
00282 
00283 #ifndef NIL
00284 #define NIL(type)       ((type)0)
00285 #endif /*NIL*/
00286 
00287 #if __STD_C
00288 #include <stddef.h>   /* for size_t */
00289 #else
00290 #include        <sys/types.h>
00291 #endif
00292 #include <stdio.h>    /* needed for malloc_stats */
00293 
00294 #include "dlmalloc.h"
00295 
00296 #define DLMALLOC_PHEAP_BASE 0xc00000000
00297 #define DLMALLOC_PHEAP_SIZE (512*1024*1024)
00298 
00299 #ifdef __cplusplus
00300 extern "C" {
00301 #endif
00302 
00303 /* mechanics for getpagesize; adapted from bsd/gnu getpagesize.h */
00304 
00305 #if defined(BSD) || defined(DGUX) || defined(sun) || defined(HAVE_GETPAGESIZE)
00306    extern size_t getpagesize();
00307 #  define malloc_getpagesize getpagesize()
00308 #else
00309 #  include <sys/param.h>
00310 #  ifdef EXEC_PAGESIZE
00311 #    define malloc_getpagesize EXEC_PAGESIZE
00312 #  else
00313 #    ifdef NBPG
00314 #      ifndef CLSIZE
00315 #        define malloc_getpagesize NBPG
00316 #      else
00317 #        define malloc_getpagesize (NBPG * CLSIZE)
00318 #      endif
00319 #    else 
00320 #      ifdef NBPC
00321 #        define malloc_getpagesize NBPC
00322 #      else
00323 #        define malloc_getpagesize SBRK_UNIT    /* just guess */
00324 #      endif
00325 #    endif 
00326 #  endif
00327 #endif 
00328 
00329 #ifdef __cplusplus
00330 }  /* end of extern "C" */
00331 #endif
00332 
00333 #include <mnemosyne.h>
00334 #include <stdint.h>
00335 #include <stdlib.h>
00336 #include <sys/mman.h>
00337 #include <pcm.h>
00338 
00339 
00340 /*  CHUNKS */
00341 
00342 
00343 struct malloc_chunk
00344 {
00345         uint64_t             size; /* Size in bytes, including overhead. Or'ed with INUSE if in use. */
00346         struct malloc_chunk* fd;   /* double links -- used only if free. */
00347         struct malloc_chunk* bk;
00348 
00349 };
00350 
00351 typedef struct malloc_chunk* mchunkptr;
00352 
00353 /*  sizes, alignments */
00354 
00355 #define SIZE_SZ              (sizeof(size_t))
00356 #define MALLOC_MIN_OVERHEAD  (SIZE_SZ + SIZE_SZ)
00357 #define MALLOC_ALIGN_MASK    (MALLOC_MIN_OVERHEAD - 1)
00358 #define MINSIZE              (sizeof(struct malloc_chunk) + SIZE_SZ)
00359 
00360 
00361 /* pad request bytes into a usable size */
00362 
00363 #define request2size(req) \
00364   (((long)(req) <= 0) ?  MINSIZE : \
00365     (((req) + MALLOC_MIN_OVERHEAD + MALLOC_ALIGN_MASK) \
00366       & ~(MALLOC_ALIGN_MASK)))
00367 
00368 
00369 /* Check if m has acceptable alignment */
00370 
00371 #define aligned_OK(m)    (((size_t)((m)) & (MALLOC_ALIGN_MASK)) == 0)
00372 
00373 
00374 /* Check if a chunk is immediately usable */
00375 
00376 #define exact_fit(ptr, req) ((unsigned)((ptr)->size - (req)) < MINSIZE)
00377 
00378 /* maintaining INUSE via size field */
00379 
00380 #define INUSE  0x1     /* size field is or'd with INUSE when in use */
00381                        /* INUSE must be exactly 1, so can coexist with size */
00382 
00383 #define inuse(p)       ((p)->size & INUSE)
00384 #define set_inuse(p)   ((p)->size |= INUSE)
00385 #define clear_inuse(p) ((p)->size &= ~INUSE)
00386 
00387 
00388 
00389 /* Physical chunk operations  */
00390 
00391 /* Ptr to next physical malloc_chunk. */
00392 
00393 #define next_chunk(p)\
00394   ((mchunkptr)( ((char*)(p)) + ((p)->size & ~INUSE) ))
00395 
00396 /* Ptr to previous physical malloc_chunk */
00397 
00398 #define prev_chunk(p)\
00399   ((mchunkptr)( ((char*)(p)) - ( *((size_t*)((char*)(p) - SIZE_SZ)) & ~INUSE)))
00400 
00401 /* place size at front and back of chunk */
00402 
00403 #define set_size(P, Sz)                                                                                                           \
00404 {                                                                                                                                                         \
00405   size_t Sss = (Sz);                                                                                                              \
00406   (P)->size = *((size_t*)((char*)(P) + Sss - SIZE_SZ)) = Sss;                             \
00407 }                                                                                                                                                         \
00408 
00409 
00410 /* conversion from malloc headers to user pointers, and back */
00411 
00412 #define chunk2mem(p)   ((Void_t*)((char*)(p) + SIZE_SZ))
00413 #define mem2chunk(mem) ((mchunkptr)((char*)(mem) - SIZE_SZ))
00414 
00415 
00416 
00417 
00418 /* BINS */
00419 
00420 struct malloc_bin
00421 {
00422   struct malloc_chunk dhd;   /* dirty list header */
00423   struct malloc_chunk chd;   /* clean list header */
00424 };
00425 
00426 typedef struct malloc_bin* mbinptr;
00427 
00428 
00429 /* field-extraction macros */
00430 
00431 #define clean_head(b)  (&((b)->chd))
00432 #define first_clean(b) ((b)->chd.fd)
00433 #define last_clean(b)  ((b)->chd.bk)
00434 
00435 #define dirty_head(b)  (&((b)->dhd))
00436 #define first_dirty(b) ((b)->dhd.fd)
00437 #define last_dirty(b)  ((b)->dhd.bk)
00438 
00439 
00440 
00441 
00442 /* The bins, initialized to have null double linked lists */
00443 
00444 #define NBINS     128             /* for 32 bit addresses */
00445 #define LASTBIN   (&(av[NBINS-1]))
00446 #define FIRSTBIN  (&(av[2]))      /* 1st 2 bins unused but simplify indexing */
00447 
00448 /* Bins < MAX_SMALLBIN_OFFSET are special-cased since they are 8 bytes apart */
00449 
00450 #define MAX_SMALLBIN_OFFSET  18
00451 #define MAX_SMALLBIN_SIZE   144  /* Max size for which small bin rules apply */
00452 
00453 /* Helper macro to initialize bins */
00454 #define IAV(i)\
00455   {{ 0, &(av[i].dhd),  &(av[i].dhd) }, { 0, &(av[i].chd),  &(av[i].chd) }}
00456 
00457 __attribute__ ((section("PERSISTENT"))) uint64_t           dlmalloc_pheap = 0x0;
00458 __attribute__ ((section("PERSISTENT"))) size_t             sbrk_limit = 0; 
00459 __attribute__ ((section("PERSISTENT"))) int                init_done = 0; 
00460 __attribute__ ((section("PERSISTENT"))) struct malloc_bin  *av;
00461 
00462 /* The end of memory returned from previous sbrk call */
00463 __attribute__ ((section("PERSISTENT"))) size_t* last_sbrk_end = 0; 
00464 __attribute__ ((section("PERSISTENT"))) size_t sbrked_mem = 0; /* Keep track of total mem for malloc_stats */
00465 
00466 /* Keep track of the maximum actually used clean bin, to make loops faster */
00467 /* (Not worth it to do the same for dirty ones) */
00468 __attribute__ ((section("PERSISTENT"))) mbinptr maxClean;
00469 
00470 
00471 TM_CALLABLE static 
00472 void *
00473 persistent_sbrk(size_t size) 
00474 {
00475         sbrk_limit += size;
00476         return (void *) (dlmalloc_pheap + sbrk_limit);
00477 }       
00478 
00479 TM_PURE static inline
00480 size_t
00481 init_bin_lists(pcm_storeset_t *set, uintptr_t av_base)
00482 {
00483         int i;
00484 
00485         av = (struct malloc_bin *) av_base;
00486         for (i=0; i<NBINS; i++) {
00487                 PCM_NT_STORE(set, (volatile pcm_word_t *) &av[i].dhd.size, (pcm_word_t) 0);
00488                 PCM_NT_STORE(set, (volatile pcm_word_t *) &av[i].dhd.fd, (pcm_word_t) &(av[i].dhd));
00489                 PCM_NT_STORE(set, (volatile pcm_word_t *) &av[i].dhd.bk, (pcm_word_t) &(av[i].dhd));
00490                 PCM_NT_STORE(set, (volatile pcm_word_t *) &av[i].chd.size, (pcm_word_t) 0);
00491                 PCM_NT_STORE(set, (volatile pcm_word_t *) &av[i].chd.fd, (pcm_word_t) &(av[i].chd));
00492                 PCM_NT_STORE(set, (volatile pcm_word_t *) &av[i].chd.bk, (pcm_word_t) &(av[i].chd));
00493         }
00494         return NBINS*sizeof(struct malloc_bin);
00495 }
00496 
00497 TM_PURE static inline
00498 void
00499 init(void)
00500 {
00501         size_t         av_size;
00502         pcm_storeset_t *set;
00503 
00504         if (init_done) {
00505                 return;
00506         }
00507 
00508         set = pcm_storeset_get ();
00509 
00510         if (dlmalloc_pheap == 0x0) {
00511                 // FIXME: How do you guarantee the atomicity of the mnemosyne_segment_create ? */
00512             TM_WAIVER {
00513                         dlmalloc_pheap = (uint64_t) m_pmap((void *) DLMALLOC_PHEAP_BASE, DLMALLOC_PHEAP_SIZE, PROT_READ|PROT_WRITE, 0);
00514                 }       
00515                 if ((void *) dlmalloc_pheap == (void *) -1) {
00516                         TM_WAIVER {
00517                                 abort();
00518                         }       
00519                 }
00520         }
00521 
00522         av_size = init_bin_lists(set, dlmalloc_pheap);
00523         maxClean = FIRSTBIN;
00524 
00525         /* Advance the sbrk_limit by av_size + MINSIZE to ensure no memory is 
00526          * allocated over the av table.
00527          */
00528         persistent_sbrk(av_size + 2*MINSIZE);
00529         last_sbrk_end = (size_t *) (av_size + dlmalloc_pheap + MINSIZE);
00530         *last_sbrk_end = SIZE_SZ | INUSE;
00531         PCM_NT_FLUSH(set);
00532         init_done = 1;
00533 }
00534 
00535 
00536 
00537 /* 
00538   Auxiliary lists 
00539 
00540   Even though they use bk/fd ptrs, neither of these are doubly linked!
00541   They are null-terminated since only the first is ever accessed.
00542   returned_list is just singly linked for speed in free().
00543   last_remainder currently has length of at most one.
00544 
00545 */
00546 
00547 __attribute__ ((section("PERSISTENT"))) mchunkptr returned_list = 0;  /* List of (unbinned) returned chunks */
00548 __attribute__ ((section("PERSISTENT"))) mchunkptr last_remainder = 0; /* last remaindered chunk from malloc */
00549 
00550 /* 
00551   Indexing into bins 
00552   
00553   Funny-looking mechanics: 
00554     For small bins, the index is just size/8.
00555     For others, first find index corresponding to the power of 2
00556         closest to size, using a variant of standard base-2 log
00557         calculation that starts with the first non-small index and
00558         adjusts the size so that zero corresponds with it. On each
00559         iteration, the index is incremented across the four quadrants
00560         per power of two. (This loop runs a max of 27 iterations;
00561         usually much less.) After the loop, the remainder is quartered
00562         to find quadrant. The offsets for loop termination and
00563         quartering allow bins to start, not end at powers.
00564 */
00565 
00566 
00567 #define findbin(Sizefb, Bfb)                                                                                              \
00568 {                                                                                                                                                         \
00569   size_t Sfb = (Sizefb);                                                                                                          \
00570   if (Sfb < MAX_SMALLBIN_SIZE)                                                                                            \
00571     (Bfb) = (av + (Sfb >> 3));                                                                                            \
00572   else                                                                                                                                            \
00573   {                                                                                                                                                       \
00574     /* Offset wrt small bins */                                                                                           \
00575     size_t Ifb = MAX_SMALLBIN_OFFSET;                                                                             \
00576     Sfb >>= 3;                                                                                                                            \
00577         /* find power of 2 */                                                                                                     \
00578     while (Sfb >= (MINSIZE * 2)) { Ifb += 4; Sfb >>= 1; }                                         \
00579         /* adjust for quadrant */                                                                                                 \
00580     Ifb += (Sfb - MINSIZE) >> 2;                                                          \
00581     (Bfb) = av + Ifb;                                                                                                             \
00582   }                                                                                                                                                       \
00583 }                                                                                                                                                         \
00584 
00585 
00586 
00587 
00588 #define reset_maxClean                                                                                                            \
00589 {                                                                                                                                                         \
00590   while (maxClean > FIRSTBIN && clean_head(maxClean)==last_clean(maxClean))       \
00591     --maxClean;                                                                                                                           \
00592 }                                                                                                                                                         \
00593 
00594 
00595 /* Macros for linking and unlinking chunks */
00596 
00597 /* take a chunk off a list */
00598 
00599 #define unlink(Qul)                                                                                                                       \
00600 {                                                                                                                                                         \
00601   mchunkptr Bul = (Qul)->bk;                                                                                              \
00602   mchunkptr Ful = (Qul)->fd;                                                                                              \
00603   Ful->bk = Bul;  Bul->fd = Ful;                                                                                          \
00604 }                                                                                                                                                         \
00605 
00606 
00607 /* place a chunk on the dirty list of its bin */
00608 
00609 #define dirtylink(Qdl)                                                                                                            \
00610 {                                                                                                                                                         \
00611   mchunkptr Pdl = (Qdl);                                                                                                          \
00612   mbinptr   Bndl;                                                                                                                         \
00613   mchunkptr Hdl, Fdl;                                                                                                             \
00614                                                                                                                                                           \
00615   findbin(Pdl->size, Bndl);                                                                                                       \
00616   Hdl  = dirty_head(Bndl);                                                                                                        \
00617   Fdl  = Hdl->fd;                                                                                                                         \
00618                                                                                                                                                           \
00619   Pdl->bk = Hdl;  Pdl->fd = Fdl;  Fdl->bk = Hdl->fd = Pdl;                                        \
00620 }                                                                                                                                                         \
00621 
00622 
00623 
00624 /* Place a consolidated chunk on a clean list */
00625 
00626 #define cleanlink(Qcl)                                                                                                            \
00627 {                                                                                                                                                         \
00628   mchunkptr Pcl = (Qcl);                                                                                                          \
00629   mbinptr Bcl;                                                                                                                            \
00630   mchunkptr Hcl, Fcl;                                                                                                             \
00631                                                                                                                                                           \
00632   findbin(Qcl->size, Bcl);                                                                                                        \
00633   Hcl  = clean_head(Bcl);                                                                                                         \
00634   Fcl  = Hcl->fd;                                                                                                                         \
00635   if (Hcl == Fcl && Bcl > maxClean) maxClean = Bcl;                                                       \
00636                                                                                                                                                           \
00637   Pcl->bk = Hcl;  Pcl->fd = Fcl;  Fcl->bk = Hcl->fd = Pcl;                                        \
00638 }                                                                                                                                                         \
00639 
00640 
00641 
00642 /* consolidate one chunk */
00643 
00644 #define consolidate(Qc)                                                                                                           \
00645 {                                                                                                                                                         \
00646   for (;;)                                                                                                                                        \
00647   {                                                                                                                                                       \
00648     mchunkptr Pc = prev_chunk(Qc);                                                                                        \
00649     if (!inuse(Pc))                                                                                                                       \
00650     {                                                                                                                                             \
00651       unlink(Pc);                                                                                                                         \
00652       set_size(Pc, Pc->size + (Qc)->size);                                                                        \
00653       (Qc) = Pc;                                                                                                                          \
00654     }                                                                                                                                             \
00655     else break;                                                                                                                           \
00656   }                                                                                                                                                       \
00657   for (;;)                                                                                                                                        \
00658   {                                                                                                                                                       \
00659     mchunkptr Nc = next_chunk(Qc);                                                                                        \
00660     if (!inuse(Nc))                                                                                                                       \
00661     {                                                                                                                                             \
00662       unlink(Nc);                                                                                                                         \
00663       set_size((Qc), (Qc)->size + Nc->size);                                                              \
00664     }                                                                                                                                             \
00665     else break;                                                                                                                           \
00666   }                                                                                                                                                       \
00667 }                                                                                                                                                         \
00668 
00669 
00670 
00671 /* Place the held remainder in its bin */
00672 /* This MUST be invoked prior to ANY consolidation */
00673 
00674 #define clear_last_remainder                                                                                              \
00675 {                                                                                                                                                         \
00676   if (last_remainder != 0)                                                                                                        \
00677   {                                                                                                                                                       \
00678     cleanlink(last_remainder);                                                                                            \
00679     last_remainder = 0;                                                                                                           \
00680   }                                                                                                                                                       \
00681 }                                                                                                                                                         \
00682 
00683 
00684 /* Place a freed chunk on the returned_list */
00685 
00686 #define return_chunk(Prc)                                                                                                         \
00687 {                                                                                                                                                         \
00688   (Prc)->fd = returned_list;                                                                                              \
00689   returned_list = (Prc);                                                                                                          \
00690 }                                                                                                                                                         \
00691 
00692 
00693 /* Misc utilities */
00694 
00695 /* A helper for realloc */
00696 
00697 TM_CALLABLE static void free_returned_list()
00698 {
00699   clear_last_remainder;
00700   while (returned_list != 0)
00701   {
00702     mchunkptr p = returned_list;
00703     returned_list = p->fd;
00704     clear_inuse(p);
00705     dirtylink(p);
00706   }
00707 }
00708 
00709 /* Utilities needed below for memalign */
00710 /* Standard greatest common divisor algorithm */
00711 
00712 TM_PURE static size_t gcd(size_t a, size_t b)
00713 {
00714   size_t tmp;
00715   
00716   if (b > a)
00717   {
00718     tmp = a; a = b; b = tmp;
00719   }
00720   for(;;)
00721   {
00722     if (b == 0)
00723       return a;
00724     else if (b == 1)
00725       return b;
00726     else
00727     {
00728       tmp = b;
00729       b = a % b;
00730       a = tmp;
00731     }
00732   }
00733 }
00734 
00735 TM_PURE static size_t  lcm(size_t x, size_t y)
00736 {
00737   return x / gcd(x, y) * y;
00738 }
00739 
00740 
00741 
00742 
00743 
00744 /* Dealing with sbrk */
00745 /* This is one step of malloc; broken out for simplicity */
00746 
00747 TM_CALLABLE static mchunkptr malloc_from_sys(size_t nb)
00748 {
00749   mchunkptr p;            /* Will hold a usable chunk */
00750   size_t*   ip;           /* to traverse sbrk ptr in size_t units */
00751   char*     cp;           /* result of sbrk call */
00752   
00753   /* Find a good size to ask sbrk for.  */
00754   /* Minimally, we need to pad with enough space */
00755   /* to place dummy size/use fields to ends if needed */
00756 
00757   size_t sbrk_size = ((nb + SBRK_UNIT - 1 + SIZE_SZ + SIZE_SZ) 
00758                        / SBRK_UNIT) * SBRK_UNIT;
00759 
00760   cp = (char*)(persistent_sbrk(sbrk_size));
00761   if (cp == (char*)(-1)) /* sbrk returns -1 on failure */
00762     return 0;
00763 
00764   ip = (size_t*)cp;
00765 
00766   sbrked_mem += sbrk_size;
00767 
00768   if (last_sbrk_end != &ip[-1]) /* Is this chunk continguous with last? */
00769   {                             
00770     /* It's either first time through or someone else called sbrk. */
00771     /* Arrange end-markers at front & back */
00772 
00773     /* Shouldn't be necessary, but better to be safe */
00774     while (!aligned_OK(ip)) { ++ip; sbrk_size -= SIZE_SZ; }
00775 
00776     /* Mark the front as in use to prevent merging. (End done below.) */
00777     /* Note we can get away with only 1 word, not MINSIZE overhead here */
00778 
00779     *ip++ = SIZE_SZ | INUSE;
00780     
00781     p = (mchunkptr)ip;
00782     set_size(p,sbrk_size - (SIZE_SZ + SIZE_SZ)); 
00783     
00784   }
00785   else 
00786   {
00787     mchunkptr l;  
00788 
00789     /* We can safely make the header start at end of prev sbrked chunk. */
00790     /* We will still have space left at the end from a previous call */
00791     /* to place the end marker, below */
00792 
00793     p = (mchunkptr)(last_sbrk_end);
00794     set_size(p, sbrk_size);
00795 
00796     /* Even better, maybe we can merge with last fragment: */
00797 
00798     l = prev_chunk(p);
00799     if (!inuse(l))  
00800     {
00801       unlink(l);
00802       set_size(l, p->size + l->size);
00803       p = l;
00804     }
00805 
00806   }
00807 
00808   /* mark the end of sbrked space as in use to prevent merging */
00809 
00810   last_sbrk_end = (size_t*)((char*)p + p->size);
00811   *last_sbrk_end = SIZE_SZ | INUSE;
00812 
00813   return p;
00814 }
00815 
00816 
00817 /* Consolidate dirty chunks until create one big enough for current req. */
00818 /* Call malloc_from_sys if can't create one. */
00819 /* This is just one phase of malloc, but broken out for sanity */
00820 
00821 TM_CALLABLE static mchunkptr malloc_find_space(size_t nb)
00822 {
00823   /* Circularly traverse bins so as not to pick on any one too much */
00824   static int rover_init = 0;
00825   static mbinptr rover;        /* Circular roving ptr */
00826 
00827   if (rover_init == 0) {
00828                 rover = LASTBIN;
00829                 rover_init = 1;
00830   }
00831   mbinptr origin = rover;
00832   mbinptr b      = rover;
00833 
00834   /* Preliminaries.  */
00835   clear_last_remainder;
00836   reset_maxClean;
00837 
00838   do
00839   {
00840     mchunkptr p;
00841 
00842     while ( (p = last_dirty(b)) != dirty_head(b))
00843     {
00844       unlink(p);
00845       consolidate(p);
00846 
00847       if (p->size >= nb)
00848       {
00849         rover = b;
00850         return p;
00851       }
00852       else
00853         cleanlink(p);
00854     }
00855 
00856     b = (b == FIRSTBIN)? LASTBIN : b - 1;      /* circularly sweep down */
00857 
00858   } while (b != origin);
00859 
00860   /* If no return above, chain to the next step of malloc */
00861   return  malloc_from_sys(nb);
00862 }
00863 
00864 
00865 /* Clear out dirty chunks from a bin, along with the free list. */
00866 /* Invoked from malloc when things look too fragmented */
00867 
00868 TM_CALLABLE static void malloc_clean_bin(mbinptr bin)
00869 {
00870   mchunkptr p;
00871 
00872   clear_last_remainder;
00873   
00874   while ( (p = last_dirty(bin)) != dirty_head(bin))
00875   {
00876     unlink(p);
00877     consolidate(p);
00878     cleanlink(p);
00879   }
00880 
00881   while (returned_list != 0)
00882   {
00883     p = returned_list;
00884     returned_list = p->fd;
00885     clear_inuse(p);
00886     consolidate(p);
00887     cleanlink(p);
00888   }
00889 }
00890 
00891 
00892 /*   Finally, the user-level functions  */
00893 
00894 TM_CALLABLE Void_t* PDL_MALLOC(size_t bytes)
00895 {
00896   static size_t previous_request = 0;  /* To control preallocation */
00897 
00898   size_t    nb = request2size(bytes);  /* padded request size */
00899   mbinptr   bin;                       /* corresponding bin */
00900   mchunkptr victim;                    /* will hold selected chunk */
00901 
00902   init();
00903   /* ----------- Peek at returned_list; hope for luck */
00904 
00905   if ((victim = returned_list) != 0 && 
00906       exact_fit(victim, nb)) /* size check works even though INUSE set */
00907   {
00908     returned_list = victim->fd;
00909     return chunk2mem(victim);
00910   }
00911   
00912   findbin(nb, bin);  /*  Need to know bin for other traversals */
00913 
00914   /* ---------- Scan dirty list of own bin */
00915 
00916      /* Code for small bins special-cased out since */
00917      /* no size check or traversal needed and */
00918      /* clean bins are exact matches so might as well test now */
00919 
00920   if (nb < MAX_SMALLBIN_SIZE)
00921   {
00922     if ( ((victim = first_dirty(bin)) != dirty_head(bin)) ||
00923          ((victim = last_clean(bin))  != clean_head(bin)))
00924     {
00925       unlink(victim);
00926       set_inuse(victim);
00927       return chunk2mem(victim);
00928     }
00929   }
00930   else
00931   {
00932     if ( (victim = first_dirty(bin)) != dirty_head(bin))
00933     {
00934       do
00935       {
00936         if (exact_fit(victim, nb))
00937         {
00938           unlink(victim);
00939           set_inuse(victim);
00940           return chunk2mem(victim);
00941         }
00942         else victim = victim->fd;
00943       } while (victim != dirty_head(bin));
00944       
00945       /* If there were chunks in there but none matched, then */
00946       /* consolidate all chunks in this bin plus those on free list */
00947       /* to prevent further traversals and fragmentation. */
00948       
00949       malloc_clean_bin(bin);
00950     }
00951   }
00952     
00953   /* ------------ Search free list */
00954 
00955   if ( (victim = returned_list) != 0)
00956   {
00957     do
00958     {
00959       mchunkptr next = victim->fd;
00960       if (exact_fit(victim, nb))
00961       {
00962         returned_list = next;
00963         return chunk2mem(victim);
00964       }
00965       else    /* Place unusable chunks in their bins  */
00966       {
00967         clear_inuse(victim);
00968         dirtylink(victim);
00969         victim = next;
00970       }
00971     } while (victim != 0);
00972     returned_list = 0;
00973   }
00974 
00975   /* -------------- Try the remainder from last successful split */
00976 
00977   if ( (victim = last_remainder) != 0 && victim->size >= nb)
00978   {
00979     last_remainder = 0; /* reset for next time */
00980     goto split;
00981   }
00982 
00983   /* -------------- Scan through own clean bin */
00984 
00985       /* (Traversing back-to-front tends to choose `old' */
00986       /*  chunks that could not be further consolidated.) */
00987 
00988   for (victim = last_clean(bin); victim != clean_head(bin); victim=victim->bk)
00989   {
00990     if (victim->size >= nb)
00991     {
00992       unlink(victim); 
00993       goto split;
00994     }
00995   }
00996 
00997   /* -------------- Try all bigger clean bins */
00998 
00999       /* (Scanning upwards is slower but prevents fragmenting big */
01000       /* chunks that we might need later. If there aren't any smaller */
01001       /* ones, most likely we got a big one from last_remainder anyway.) */
01002 
01003   {
01004     mbinptr b;
01005 
01006     for (b = bin + 1; b <= maxClean; ++b)
01007     {
01008       if ( (victim = last_clean(b)) != clean_head(b) ) 
01009       {
01010         unlink(victim);
01011         goto split;
01012       }
01013     }
01014   }
01015 
01016   /* -------------  Consolidate or sbrk */
01017 
01018   victim =  malloc_find_space(nb);
01019 
01020   if (victim == 0)  /* propagate failure */
01021     return 0; 
01022 
01023   /* -------------- Possibly split victim chunk */
01024 
01025  split:  
01026   {
01027     size_t room = victim->size - nb;
01028     if (room >= MINSIZE)     
01029     {
01030       mchunkptr v = victim;  /* Hold so can break up in prealloc */
01031       
01032       set_size(victim, nb);  /* Adjust size of chunk to be returned */
01033       
01034       /* ---------- Preallocate */
01035       
01036           /* Try to preallocate some more of this size if */
01037           /* last (split) req was of same size */
01038       
01039       if (previous_request == nb)
01040       {
01041         int i;
01042         
01043         for (i = 0; i < MAX_PREALLOCS && room >= nb + MINSIZE; ++i)
01044         {
01045           room -= nb;
01046            
01047           v = (mchunkptr)((char*)(v) + nb); 
01048           set_size(v, nb);
01049           set_inuse(v);     /* free-list chunks must have inuse set */
01050           return_chunk(v);  /* add to free list */
01051         } 
01052       }
01053 
01054       previous_request = nb;  /* record for next time */
01055 
01056       /* ---------- Create remainder chunk  */
01057       
01058       /* Get rid of the old one first */
01059       if (last_remainder != 0) cleanlink(last_remainder);
01060       
01061       last_remainder = (mchunkptr)((char*)(v) + nb);
01062       set_size(last_remainder, room);
01063     }
01064 
01065     set_inuse(victim);
01066     return chunk2mem(victim);
01067   }
01068 }
01069 
01070 
01071 TM_CALLABLE void PDL_FREE(Void_t* mem)
01072 {
01073   if (mem != 0)
01074   {
01075     mchunkptr p = mem2chunk(mem);
01076     return_chunk(p);
01077   }
01078 }
01079 
01080  
01081 TM_CALLABLE Void_t* PDL_REALLOC(Void_t* mem, size_t bytes)
01082 {
01083   if (mem == 0) {
01084     return PDL_MALLOC(bytes);
01085   }     
01086   else
01087   {
01088     size_t       nb      = request2size(bytes);
01089     mchunkptr    p       = mem2chunk(mem);
01090     size_t       oldsize;
01091     long         room;
01092     mchunkptr    nxt;
01093 
01094     if (p == returned_list) /* support realloc-last-freed-chunk idiocy */
01095        returned_list = returned_list->fd;
01096 
01097     clear_inuse(p);
01098     oldsize = p->size;
01099 
01100     /* try to expand (even if already big enough), to clean up chunk */
01101 
01102     free_returned_list(); /* make freed chunks available to consolidate */
01103 
01104     while (!inuse(nxt = next_chunk(p))) /* Expand the chunk forward */
01105     {
01106       unlink(nxt);
01107       set_size(p, p->size + nxt->size);
01108     }
01109 
01110     room = p->size - nb;
01111     if (room >= 0)          /* Successful expansion */
01112     {
01113       if (room >= MINSIZE)  /* give some back if possible */
01114       {
01115         mchunkptr remainder = (mchunkptr)((char*)(p) + nb);
01116         set_size(remainder, room);
01117         cleanlink(remainder);
01118         set_size(p, nb);
01119       }
01120       set_inuse(p);
01121       return chunk2mem(p);
01122     }
01123     else /* Could not expand. Get another chunk and copy. */
01124     {
01125       Void_t* newmem;
01126       size_t count;
01127       size_t* src;
01128       size_t* dst;
01129 
01130       set_inuse(p);    /* don't let malloc consolidate us yet! */
01131       newmem = PDL_MALLOC(nb);
01132 
01133       if (newmem != 0) {
01134         /* Copy -- we know that alignment is at least `size_t' */
01135         src = (size_t*) mem;
01136         dst = (size_t*) newmem;
01137         count = (oldsize - SIZE_SZ) / sizeof(size_t);
01138         while (count-- > 0) *dst++ = *src++;
01139       }
01140 
01141       PDL_FREE(mem);
01142       return newmem;
01143     }
01144   }
01145 }
01146 
01147 
01148 /* Return a pointer to space with at least the alignment requested */
01149 /* Alignment argument should be a power of two */
01150 
01151 TM_CALLABLE Void_t* PDL_MEMALIGN(size_t alignment, size_t bytes)
01152 {
01153   mchunkptr p;
01154   size_t    nb = request2size(bytes);
01155   size_t    room;
01156 
01157   /* find an alignment that both we and the user can live with: */
01158   /* least common multiple guarantees mutual happiness */
01159   size_t    align = lcm(alignment, MALLOC_MIN_OVERHEAD);
01160 
01161   /* call malloc with worst case padding to hit alignment; */
01162   /* we will give back extra */
01163 
01164   size_t req = nb + align + MINSIZE;
01165   Void_t*  m = PDL_MALLOC(req);
01166 
01167   if (m == 0) return 0; /* propagate failure */
01168 
01169   p = mem2chunk(m);
01170   clear_inuse(p);
01171 
01172 
01173   if (((size_t)(m) % align) != 0) /* misaligned */
01174   {
01175 
01176     /* find an aligned spot inside chunk */
01177 
01178     mchunkptr ap = (mchunkptr)((((size_t)(m) + align-1) & -align) - SIZE_SZ);
01179 
01180     size_t gap = (size_t)(ap) - (size_t)(p);
01181 
01182     /* we need to give back leading space in a chunk of at least MINSIZE */
01183 
01184     if (gap < MINSIZE)
01185     {
01186       /* This works since align >= MINSIZE */
01187       /* and we've malloc'd enough total room */
01188 
01189       ap = (mchunkptr)( (size_t)(ap) + align );
01190       gap += align;    
01191     }
01192 
01193     room = p->size - gap;
01194 
01195     /* give back leader */
01196     set_size(p, gap);
01197     dirtylink(p); /* Don't really know if clean or dirty; be safe */
01198 
01199     /* use the rest */
01200     p = ap;
01201     set_size(p, room);
01202   }
01203 
01204   /* also give back spare room at the end */
01205 
01206   room = p->size - nb;
01207   if (room >= MINSIZE)
01208   {
01209     mchunkptr remainder = (mchunkptr)((char*)(p) + nb);
01210     set_size(remainder, room);
01211     dirtylink(remainder); /* Don't really know; be safe */
01212     set_size(p, nb);
01213   }
01214 
01215   set_inuse(p);
01216   return chunk2mem(p);
01217 
01218 }
01219 
01220 
01221 /* Derivatives */
01222 
01223 TM_CALLABLE Void_t* PDL_VALLOC(size_t bytes)
01224 {
01225   /* Cache result of getpagesize */
01226   static size_t malloc_pagesize = 0;
01227 
01228   if (malloc_pagesize == 0) malloc_pagesize = malloc_getpagesize;
01229   return PDL_MEMALIGN (malloc_pagesize, bytes);
01230 }
01231 
01232 
01233 TM_CALLABLE Void_t* PDL_CALLOC(size_t n, size_t elem_size)
01234 {
01235   size_t sz = n * elem_size;
01236   Void_t* p = PDL_MALLOC(sz);
01237   char* q = (char*) p;
01238   while (sz-- > 0) *q++ = 0;
01239   return p;
01240 }
01241 
01242 TM_CALLABLE void PDL_CFREE(Void_t *mem)
01243 {
01244   PDL_FREE(mem);
01245 }
01246 
01247 TM_CALLABLE size_t PDL_GET_USABLE_SIZE(Void_t* mem)
01248 {
01249   if (mem == 0)
01250     return 0;
01251   else
01252   {
01253     mchunkptr p = (mchunkptr)((char*)(mem) - SIZE_SZ); 
01254     size_t sz = p->size & ~(INUSE);
01255     /* report zero if not in use or detectably corrupt */
01256     if (p->size == sz || sz != *((size_t*)((char*)(p) + sz - SIZE_SZ)))
01257       return 0;
01258     else
01259       return sz - MALLOC_MIN_OVERHEAD;
01260   }
01261 }
01262     
01263 TM_CALLABLE void PDL_MALLOC_STATS()
01264 {
01265 
01266   /* Traverse through and count all sizes of all chunks */
01267 
01268   size_t avail = 0;
01269   size_t malloced_mem;
01270 
01271   mbinptr b;
01272 
01273   free_returned_list();
01274 
01275   for (b = FIRSTBIN; b <= LASTBIN; ++b)
01276   {
01277     mchunkptr p;
01278 
01279     for (p = first_dirty(b); p != dirty_head(b); p = p->fd)
01280       avail += p->size;
01281 
01282     for (p = first_clean(b); p != clean_head(b); p = p->fd)
01283       avail += p->size;
01284   }
01285 
01286   malloced_mem = sbrked_mem - avail;
01287 
01288   TM_WAIVER {
01289     fprintf(stderr, "total mem = %10u\n", (unsigned int) sbrked_mem);
01290     fprintf(stderr, "in use    = %10u\n", (unsigned int) malloced_mem);
01291   }     
01292 
01293 }

Generated on Sat Apr 23 11:43:35 2011 for Mnemosyne by  doxygen 1.4.7