conv-core/memory-gnuold.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * $Source: /cvsroot/charm/src/conv-core/memory-gnuold.c,v $
00003  * $Author: olawlor $
00004  * $Date: 2003-08-05 23:46:15 $
00005  * $Revision: 2.1 $
00006  *****************************************************************************/
00007 
00008 #define malloc   mm_malloc
00009 #define free     mm_free
00010 #define calloc   mm_calloc
00011 #define cfree    mm_cfree
00012 #define realloc  mm_realloc
00013 #define memalign mm_memalign
00014 #define valloc   mm_valloc
00015 #define MM_LINK static
00016 
00017 #undef sun /* I don't care if it's a sun, dangit.  No special treatment. */
00018 #undef BSD /* I don't care if it's BSD.  Same thing. */
00019 #if CMK_GETPAGESIZE_AVAILABLE
00020 #define HAVE_GETPAGESIZE
00021 #endif
00022 
00023 
00024 /* 
00025   - static linkage qualifiers by Orion
00026   - bugfix by Josh (fixed sbrk alignment)
00027 
00028 
00029   A version of malloc/free/realloc written by Doug Lea and released to the 
00030   public domain. 
00031 
00032   VERSION 2.5.3b 
00033     (Mon Jun 12 07:45:17 1995: Changed status from unreleased to 
00034      released to reflect reality!)
00035 
00036 * History:
00037     Based loosely on libg++-1.2X malloc. (It retains some of the overall 
00038        structure of old version,  but most details differ.)
00039 
00040     Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
00041     V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
00042       * removed potential for odd address access in prev_chunk
00043       * removed dependency on getpagesize.h
00044       * misc cosmetics and a bit more internal documentation
00045       * anticosmetics: mangled names in macros to evade debugger strangeness
00046       * tested on sparc, hp-700, dec-mips, rs6000 
00047           with gcc & native cc (hp, dec only) allowing
00048           Detlefs & Zorn comparison study (to appear, SIGPLAN Notices.)
00049 
00050     V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
00051       * faster bin computation & slightly different binning
00052       * merged all consolidations to one part of malloc proper
00053          (eliminating old malloc_find_space & malloc_clean_bin)
00054       * Scan 2 returns chunks (not just 1)
00055 
00056      Sat Apr  2 06:51:25 1994  Doug Lea  (dl at g)
00057       * Propagate failure in realloc if malloc returns 0
00058       * Add stuff to allow compilation on non-ANSI compilers 
00059           from kpv@research.att.com
00060      
00061     V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
00062       * realloc: try to expand in both directions
00063       * malloc: swap order of clean-bin strategy;
00064       * realloc: only conditionally expand backwards
00065       * Try not to scavenge used bins
00066       * Use bin counts as a guide to preallocation
00067       * Occasionally bin return list chunks in first scan
00068       * Add a few optimizations from colin@nyx10.cs.du.edu
00069 
00070     V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
00071 
00072 * Overview
00073 
00074   This malloc, like any other, is a compromised design. 
00075 
00076   Chunks of memory are maintained using a `boundary tag' method as
00077   described in e.g., Knuth or Standish.  The size of the chunk is
00078   stored both in the front of the chunk and at the end.  This makes
00079   consolidating fragmented chunks into bigger chunks very fast.  The
00080   size field also hold a bit representing whether a chunk is free or
00081   in use.
00082 
00083   Malloced chunks have space overhead of 8 bytes: The preceding and
00084   trailing size fields.  When a chunk is freed, 8 additional bytes are
00085   needed for free list pointers. Thus, the minimum allocatable size is
00086   16 bytes.  8 byte alignment is currently hardwired into the design.
00087   This seems to suffice for all current machines and C compilers.
00088   Calling memalign will return a chunk that is both 8-byte aligned
00089   and meets the requested (power of two) alignment.
00090 
00091   It is assumed that 32 bits suffice to represent chunk sizes.  The
00092   maximum size chunk is 2^31 - 8 bytes.  malloc(0) returns a pointer
00093   to something of the minimum allocatable size.  Requests for negative
00094   sizes (when size_t is signed) or with the highest bit set (when
00095   unsigned) will also return a minimum-sized chunk.
00096 
00097   Available chunks are kept in doubly linked lists. The lists are
00098   maintained in an array of bins using approximately proportionally
00099   spaced bins.  There are a lot of bins (128). This may look
00100   excessive, but works very well in practice.  The use of very fine
00101   bin sizes closely approximates the use of one bin per actually used
00102   size, without necessitating the overhead of locating such bins. It
00103   is especially desirable in common applications where large numbers
00104   of identically-sized blocks are malloced/freed in some dynamic
00105   manner, and then later are all freed.  The finer bin sizes make
00106   finding blocks fast, with little wasted overallocation. The
00107   consolidation methods ensure that once the collection of blocks is
00108   no longer useful, fragments are gathered into bigger chunks awaiting
00109   new roles.
00110 
00111   The bins av[i] serve as heads of the lists. Bins contain a dummy
00112   header for the chunk lists. Each bin has two lists. The `dirty' list
00113   holds chunks that have been returned (freed) and not yet either
00114   re-malloc'ed or consolidated. (A third free-standing list `returns'
00115   contains returned chunks that have not yet been processed at all;
00116   they must be kept with their `inuse' bits set.) The `clean' list
00117   holds split-off fragments and consolidated space. All procedures
00118   maintain the invariant that no clean chunk physically borders
00119   another clean chunk. Thus, clean chunks never need to be scanned
00120   during consolidation.  Also, dirty chunks of bad sizes (even if too
00121   big) are never used without being first consolidated:
00122 
00123   The otherwise unused size field of the bin heads are used to record
00124   preallocation use. When a chunk is preallocated, an approximation of
00125   the number of preallocated chunks is recorded.  Other scans try to
00126   avoid `stealing' such chunks, but also decrement these counts so
00127   that they age down across time.
00128 
00129 * Algorithms
00130 
00131   Malloc:
00132 
00133     This is a very heavily disguised first-fit algorithm.
00134     Most of the heuristics are designed to maximize the likelihood
00135     that a usable chunk will most often be found very quickly,
00136     while still minimizing fragmentation and overhead.
00137 
00138     The allocation strategy has several phases. 
00139 
00140       0. Convert the request size into a usable form. This currently
00141          means to add 8 bytes overhead plus possibly more to obtain
00142          8-byte alignment. Call this size `nb'.
00143 
00144 
00145       1. Check if either of the last 2 returned (free()'d) or
00146          preallocated chunk are of the exact size nb. If so, use one.
00147          `Exact' means no more than MINSIZE (currently 16) bytes
00148          larger than nb. This cannot be reduced, since a chunk with
00149          size < MINSIZE cannot be created to hold the remainder.
00150 
00151          This check need not fire very often to be effective.  It
00152          reduces overhead for sequences of requests for the same
00153          preallocated size to a dead minimum.  Exactly 2 peeks of the
00154          return list is empirically the best tradeoff between wasting
00155          time scanning unusaable chunks and the high temporal
00156          correlation of chunk sizes in user programs. 
00157 
00158 
00159       2. Look for a chunk in the bin associated with nb.
00160 
00161          If a chunk was found here but not in return list, and the
00162          same thing happened previously, then place the first chunk on
00163          the return list in its bin. (This tends to prevent future
00164          useless rescans in cases where step 3 is not hit often enough
00165          because chunks are found in in bins.)
00166 
00167       3. Pull other requests off the returned chunk list, using one if
00168          it is of exact size, else distributing into the appropriate
00169          (dirty) bins.
00170 
00171       4. Look in the last scavenged bigger bin found in a previous
00172          step 5, and proceed to possibly split it in step 10.
00173 
00174       5. Scan through the clean lists of all larger bins, selecting
00175          any chunk at all. (It will surely be big enough since it is
00176          in a bigger bin.). The scan goes upward from small bins to
00177          large to avoid fragmenting big bins we might need later.
00178 
00179       6. Try to use a chunk remaindered during a previous malloc.
00180          These chunks are kept separately in `last_remainder' to avoid
00181          useless re-binning during repeated splits. Its use also tends
00182          to make the scan in step 5 shorter. It must be binned prior
00183          to any other consolidation.
00184 
00185          If the chunk is usable, proceed to split, else bin it.
00186 
00187       7. (No longer a step 7!)
00188 
00189       8. Consolidate chunks in other dirty bins until a large enough
00190          chunk is created. Break out and split when one is found.
00191 
00192          Bins are selected for consolidation in a circular fashion
00193          spanning across malloc calls. This very crudely approximates
00194          LRU scanning -- it is an effective enough approximation for
00195          these purposes.
00196 
00197          After consolidating a bin, its use count decremented.
00198 
00199     Step 9 is taken if all else fails:
00200          
00201       9. Get space from the system using sbrk.
00202 
00203          Memory is gathered from the system (via sbrk) in a way that
00204          allows chunks obtained across different sbrk calls to be
00205          consolidated, but does not require contiguous memory. Thus,
00206          it should be safe to intersperse mallocs with other sbrk
00207          calls.
00208 
00209       Step 10 can be hit from any of steps 2,4-9:
00210 
00211       10. If the selected chunk is too big, then:
00212 
00213          * If this is the second split request for a size in a row or
00214            for a size not recently found in return lists, then use
00215            this chunk to preallocate up to min {bin_use(bin)+1,
00216            MAX_PREALLOCS} additional chunks of size nb and place them
00217            on the returned chunk list.  (Placing them here rather than
00218            in bins speeds up the most common case where the user
00219            program requests an uninterrupted series of identically
00220            sized chunks. If this is not true, the chunks will be
00221            binned in step 4 soon.)
00222 
00223            The actual number to prealloc depends on the available space
00224            in a selected victim, so typical numbers will be less than
00225            the bin_use.
00226 
00227          * Split off the remainder and place in last_remainder
00228            (first binning the old one, if applicable.)
00229 
00230 
00231      10.  Return the chunk.
00232 
00233 
00234   Free: 
00235     Deallocation (free) consists only of placing the chunk on a list
00236     of returned chunks. free(0) has no effect.  Because freed chunks
00237     may be overwritten with link fields, this malloc will often die
00238     when freed memory is overwritten by user programs.  This can be
00239     very effective (albeit in an annoying way) in helping users track
00240     down dangling pointers.
00241 
00242   Realloc:
00243     Reallocation proceeds in the usual way. If a chunk can be extended,
00244     it is, else a malloc-copy-free sequence is taken. 
00245 
00246     The old unix realloc convention of allowing the last-free'd chunk
00247     to be used as an argument to realloc is half-heartedly supported.
00248     It may in fact be used, but may have some old contents overwritten.
00249 
00250   Memalign, valloc:
00251     memalign arequests more than enough space from malloc, finds a spot
00252     within that chunk that meets the alignment request, and then
00253     possibly frees the leading and trailing space. Overreliance on
00254     memalign is a sure way to fragment space.
00255 
00256 * Other implementation notes
00257 
00258   This malloc is NOT designed to work in multiprocessing applications.
00259   No semaphores or other concurrency control are provided to ensure
00260   that multiple malloc or free calls don't run at the same time, which
00261   could be disasterous. A single semaphore could be used across malloc,
00262   realloc, and free. It would be hard to obtain finer granularity.
00263 
00264   The implementation is in straight, hand-tuned ANSI C.  Among other
00265   consequences, it uses a lot of macros. These would be nicer as
00266   inlinable procedures, but using macros allows use with non-inlining
00267   compilers, and also makes it a bit easier to control when they
00268   should be expanded out by selectively embedding them in other macros
00269   and procedures. (According to profile information, it is almost, but
00270   not quite always best to expand.) Also, because there are so many
00271   different twisty paths through malloc steps, the code is not exactly
00272   elegant.
00273 
00274 */
00275 
00276 
00277 
00278 /* TUNABLE PARAMETERS */
00279 
00280 /* 
00281   SBRK_UNIT is a good power of two to call sbrk with. It should
00282   normally be system page size or a multiple thereof.  If sbrk is very
00283   slow on a system, it pays to increase this.  Otherwise, it should
00284   not matter too much. Also, if a program needs a certain minimum
00285   amount of memory, this amount can be malloc'ed then immediately
00286   free'd before starting to avoid calling sbrk so often.
00287 */
00288 
00289 #define SBRK_UNIT 8192 
00290 
00291 /* 
00292   MAX_PREALLOCS is the maximum number of chunks to preallocate.  
00293   Overrides bin use stats to avoid ridiculous preallocations.
00294 */
00295 
00296 #define MAX_PREALLOCS 64
00297 
00298 /* preliminaries */
00299 
00300 #ifndef __STD_C
00301 #ifdef __STDC__
00302 #define __STD_C         1
00303 #else
00304 #if __cplusplus
00305 #define __STD_C         1
00306 #else
00307 #define __STD_C         0
00308 #endif /*__cplusplus*/
00309 #endif /*__STDC__*/
00310 #endif /*__STD_C*/
00311 
00312 #ifndef _BEGIN_EXTERNS_
00313 #if __cplusplus
00314 #define _BEGIN_EXTERNS_ extern "C" {
00315 #define _END_EXTERNS_   }
00316 #else
00317 #define _BEGIN_EXTERNS_
00318 #define _END_EXTERNS_
00319 #endif
00320 #endif /*_BEGIN_EXTERNS_*/
00321 
00322 #ifndef _ARG_
00323 #if __STD_C
00324 #define _ARG_(x)        x
00325 #else
00326 #define _ARG_(x)        ()
00327 #endif
00328 #endif /*_ARG_*/
00329 
00330 
00331 
00332 #ifndef Void_t
00333 #if __STD_C
00334 #define Void_t          void
00335 #else
00336 #define Void_t          char
00337 #endif
00338 #endif /*Void_t*/
00339 
00340 #ifndef NIL
00341 #define NIL(type)       ((type)0)
00342 #endif /*NIL*/
00343 
00344 #if __STD_C
00345 #include <stddef.h>   /* for size_t */
00346 #else
00347 #include <sys/types.h>
00348 #endif
00349 
00350 #include <stdio.h>    /* needed for malloc_stats */
00351 
00352 #ifdef __cplusplus
00353 extern "C" {
00354 #endif
00355 
00356 /* mechanics for getpagesize; adapted from bsd/gnu getpagesize.h */
00357 
00358 #if defined(BSD) || defined(DGUX) || defined(sun) || defined(_WIN32) || defined(HAVE_GETPAGESIZE)
00359 #  define malloc_getpagesize getpagesize()
00360 #else
00361 #  include <sys/param.h>
00362 #  ifdef EXEC_PAGESIZE
00363 #    define malloc_getpagesize EXEC_PAGESIZE
00364 #  else
00365 #    ifdef NBPG
00366 #      ifndef CLSIZE
00367 #        define malloc_getpagesize NBPG
00368 #      else
00369 #        define malloc_getpagesize (NBPG * CLSIZE)
00370 #      endif
00371 #    else 
00372 #      ifdef NBPC
00373 #        define malloc_getpagesize NBPC
00374 #      else
00375 #        define malloc_getpagesize SBRK_UNIT    /* just guess */
00376 #      endif
00377 #    endif 
00378 #  endif
00379 #endif 
00380 
00381 #ifdef __cplusplus
00382 };  /* end of extern "C" */
00383 #endif
00384 
00385 
00386 
00387 /*  CHUNKS */
00388 
00389 
00390 struct malloc_chunk
00391 {
00392   size_t size;               /* Size in bytes, including overhead. */
00393                              /* Or'ed with INUSE if in use. */
00394 
00395   struct malloc_chunk* fd;   /* double links -- used only if free. */
00396   struct malloc_chunk* bk;
00397 
00398 };
00399 
00400 typedef struct malloc_chunk* mchunkptr;
00401 
00402 /*  sizes, alignments */
00403 
00404 #define SIZE_SZ              (sizeof(size_t))
00405 #define MALLOC_MIN_OVERHEAD  (SIZE_SZ + SIZE_SZ)
00406 #define MALLOC_ALIGN_MASK    (MALLOC_MIN_OVERHEAD - 1)
00407 #define MINSIZE              (sizeof(struct malloc_chunk) + SIZE_SZ)
00408 
00409 
00410 /* pad request bytes into a usable size */
00411 
00412 #define request2size(req) \
00413   (((long)(req) <= 0) ?  MINSIZE : \
00414     (((req) + MALLOC_MIN_OVERHEAD + MALLOC_ALIGN_MASK) \
00415       & ~(MALLOC_ALIGN_MASK)))
00416 
00417 #define fastrequest2size(req) \
00418     ((req) + MALLOC_MIN_OVERHEAD + MALLOC_ALIGN_MASK) \
00419       & ~(MALLOC_ALIGN_MASK)
00420 
00421 
00422 /* Check if a chunk is immediately usable */
00423 
00424 #define exact_fit(ptr, req) ((unsigned long)((ptr)->size - (req)) < MINSIZE)
00425 
00426 /* maintaining INUSE via size field */
00427 
00428 #define INUSE  0x1     /* size field is or'd with INUSE when in use */
00429                        /* INUSE must be exactly 1, so can coexist with size */
00430 
00431 #define inuse(p)       ((p)->size & INUSE)
00432 #define set_inuse(p)   ((p)->size |= INUSE)
00433 #define clear_inuse(p) ((p)->size &= ~INUSE)
00434 
00435 
00436 
00437 /* Physical chunk operations  */
00438 
00439 /* Ptr to next physical malloc_chunk. */
00440 
00441 #define next_chunk(p)\
00442   ((mchunkptr)( ((char*)(p)) + ((p)->size & ~INUSE) ))
00443 
00444 /* Ptr to previous physical malloc_chunk */
00445 
00446 #define prev_chunk(p)\
00447   ((mchunkptr)( ((char*)(p)) - ( *((size_t*)((char*)(p) - SIZE_SZ)) & ~INUSE)))
00448 
00449 /* place size at front and back of chunk */
00450 
00451 #define set_size(P, Sz)                                                                                                           \
00452 {                                                                                                                                                         \
00453   size_t Sss = (Sz);                                                                                                              \
00454   (P)->size = *((size_t*)((char*)(P) + Sss - SIZE_SZ)) = Sss;                             \
00455 }                                                                                                                                                         \
00456 
00457 /* set size & inuse at same time */
00458 #define set_inuse_size(P, Sz)                                                                                             \
00459 {                                                                                                                                                         \
00460   size_t Sss = (Sz);                                                                                                              \
00461   *((size_t*)((char*)(P) + Sss - SIZE_SZ)) = Sss;         \
00462   (P)->size = Sss | INUSE;        \
00463 }                                                                                                                                                         \
00464 
00465 
00466 /* conversion from malloc headers to user pointers, and back */
00467 
00468 #define chunk2mem(p)   ((Void_t*)((char*)(p) + SIZE_SZ))
00469 #define mem2chunk(mem) ((mchunkptr)((char*)(mem) - SIZE_SZ))
00470 
00471 
00472 
00473 
00474 /* BINS */
00475 
00476 struct malloc_bin
00477 {
00478   struct malloc_chunk dhd;   /* dirty list header */
00479   struct malloc_chunk chd;   /* clean list header */
00480 };
00481 
00482 typedef struct malloc_bin* mbinptr;
00483 
00484 
00485 /* field-extraction macros */
00486 
00487 #define clean_head(b)  (&((b)->chd))
00488 #define first_clean(b) ((b)->chd.fd)
00489 #define last_clean(b)  ((b)->chd.bk)
00490 
00491 #define dirty_head(b)  (&((b)->dhd))
00492 #define first_dirty(b) ((b)->dhd.fd)
00493 #define last_dirty(b)  ((b)->dhd.bk)
00494 
00495 /* size field of dirty head tracks whether bin is used */
00496 
00497 #define bin_use(b)         ((b)->dhd.size)
00498 #define add_bin_use(b, nu) ((b)->dhd.size += (nu))
00499 #define inc_bin_use(b)     ((b)->dhd.size++)
00500 #define halve_bin_use(b)   ((b)->dhd.size=(unsigned long)((b)->dhd.size) >> 1)
00501 #define clr_bin_use(b)     ((b)->dhd.size = 0)
00502 #define set_bin_use(b)     ((b)->dhd.size = 1)
00503 
00504 #define prealloc_size(b)     ((b)->chd.size)
00505 #define set_prealloc_size(b, sz)  ((b)->chd.size = (sz))
00506 
00507 
00508 
00509 /* The bins, initialized to have null double linked lists */
00510 
00511 #define NBINS     128
00512 /* first 2 and last 1 bin unused but simplify indexing */
00513 #define FIRSTBIN     (&(av[2]))      
00514 #define LASTBIN      (&(av[NBINS-2])) 
00515 
00516 #define PRE_FIRSTBIN (&(av[1]))      
00517 #define POST_LASTBIN (&(av[NBINS-1])) 
00518 
00519 
00520 /* sizes < MAX_SMALLBIN_SIZE are special-cased since bins are 8 bytes apart */
00521 
00522 #define MAX_SMALLBIN_SIZE   512 
00523 #define SMALLBIN_SIZE         8
00524 
00525 /* Helper macro to initialize bins */
00526 #define IAV(i)\
00527   {{ 0, &(av[i].dhd),  &(av[i].dhd) }, { 0, &(av[i].chd),  &(av[i].chd) }}
00528 
00529 static struct malloc_bin  av[NBINS] = 
00530 {
00531   IAV(0),   IAV(1),   IAV(2),   IAV(3),   IAV(4), 
00532   IAV(5),   IAV(6),   IAV(7),   IAV(8),   IAV(9),
00533   IAV(10),  IAV(11),  IAV(12),  IAV(13),  IAV(14), 
00534   IAV(15),  IAV(16),  IAV(17),  IAV(18),  IAV(19),
00535   IAV(20),  IAV(21),  IAV(22),  IAV(23),  IAV(24), 
00536   IAV(25),  IAV(26),  IAV(27),  IAV(28),  IAV(29),
00537   IAV(30),  IAV(31),  IAV(32),  IAV(33),  IAV(34), 
00538   IAV(35),  IAV(36),  IAV(37),  IAV(38),  IAV(39),
00539   IAV(40),  IAV(41),  IAV(42),  IAV(43),  IAV(44), 
00540   IAV(45),  IAV(46),  IAV(47),  IAV(48),  IAV(49),
00541   IAV(50),  IAV(51),  IAV(52),  IAV(53),  IAV(54), 
00542   IAV(55),  IAV(56),  IAV(57),  IAV(58),  IAV(59),
00543   IAV(60),  IAV(61),  IAV(62),  IAV(63),  IAV(64), 
00544   IAV(65),  IAV(66),  IAV(67),  IAV(68),  IAV(69),
00545   IAV(70),  IAV(71),  IAV(72),  IAV(73),  IAV(74), 
00546   IAV(75),  IAV(76),  IAV(77),  IAV(78),  IAV(79),
00547   IAV(80),  IAV(81),  IAV(82),  IAV(83),  IAV(84), 
00548   IAV(85),  IAV(86),  IAV(87),  IAV(88),  IAV(89),
00549   IAV(90),  IAV(91),  IAV(92),  IAV(93),  IAV(94), 
00550   IAV(95),  IAV(96),  IAV(97),  IAV(98),  IAV(99),
00551   IAV(100), IAV(101), IAV(102), IAV(103), IAV(104), 
00552   IAV(105), IAV(106), IAV(107), IAV(108), IAV(109),
00553   IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), 
00554   IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
00555   IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), 
00556   IAV(125), IAV(126), IAV(127)
00557 };
00558 
00559 
00560 
00561 /* 
00562   Auxiliary globals 
00563 
00564   Returns hold list of (unbinned) returned chunks
00565 
00566   Even though it uses bk/fd ptrs, returns is NOT doubly linked!
00567   It is singly-linked and null-terminated it is only they are
00568   accessed sequentially.
00569 
00570 */
00571 
00572 static mchunkptr returns = 0;  
00573 
00574 /* 
00575   last_remainder holds for the remainder of the most recently split chunk
00576 */
00577 
00578 
00579 static mchunkptr last_remainder = 0; 
00580 
00581 
00582 
00583 /* 
00584   minClean and maxClean keep track of the minimum/maximum actually used 
00585   clean bin, to make loops faster 
00586 */
00587 
00588 static mbinptr maxClean = PRE_FIRSTBIN;
00589 static mbinptr minClean = POST_LASTBIN;
00590 
00591 
00592 
00593 
00594 /* 
00595   Indexing into bins 
00596 
00597   Bins are log-spaced:
00598 
00599   64 bins of size       8
00600   32 bins of size      64
00601   16 bins of size     512
00602    8 bins of size    4096
00603    4 bins of size   32768
00604    2 bins of size  262144
00605    1 bin  of size what's left
00606 
00607   There is actually a little bit of slop in the numbers in findbin()
00608   for the sake of speed. This makes no difference elsewhere.
00609 */
00610 
00611 #define findbin(Sizefb, Bfb)                                                                                              \
00612 {                                                                                                                                                         \
00613   unsigned long  Ofb = (Sizefb) >> 3;                                                                             \
00614   unsigned long  Nfb = Ofb >> 6;                                                                                          \
00615   if (Nfb != 0)  {                                                                                                                        \
00616     if      (Nfb <    5)  Ofb = (Ofb >>  3) +  56;                                                        \
00617     else if (Nfb <   21)  Ofb = (Ofb >>  6) +  91;                                                \
00618     else if (Nfb <   85)  Ofb = (Ofb >>  9) + 110;                                                \
00619     else if (Nfb <  341)  Ofb = (Ofb >> 12) + 119;                                                \
00620     else if (Nfb < 1365)  Ofb = (Ofb >> 15) + 124;                                                \
00621     else                  Ofb = 126;                                                                              \
00622   }                                                                                                                                                       \
00623   (Bfb) = av + Ofb;                                                                                                                       \
00624 }                                                                                                                                                         \
00625 
00626 /* Special case for known small bins */
00627 
00628 #define smallfindbin(Sizefb, Bfb) (Bfb) = av + ((unsigned long)(Sizefb) >> 3)
00629 
00630 
00631 
00632 
00633 
00634 
00635 
00636 /* Macros for linking and unlinking chunks */
00637 
00638 /* take a chunk off a list */
00639 
00640 #define unlink(Qul)                                                                                                                       \
00641 {                                                                                                                                                         \
00642   mchunkptr Bul = (Qul)->bk;                                                                                              \
00643   mchunkptr Ful = (Qul)->fd;                                                                                              \
00644   Ful->bk = Bul;  Bul->fd = Ful;                                                                                          \
00645 }                                                                                                                                                         \
00646 
00647 
00648 /* place a chunk on the dirty list of its bin */
00649 
00650 #define dirtylink(Qdl)                                                                                                            \
00651 {                                                                                                                                                         \
00652   mchunkptr Pdl = (Qdl);                                                                                                          \
00653   mbinptr   Bndl;                                                                                                                         \
00654   mchunkptr Hdl, Fdl;                                                                                                             \
00655   clear_inuse(Pdl);                                                                                                                       \
00656   findbin(Pdl->size, Bndl);                                                                                                       \
00657   Hdl  = dirty_head(Bndl);                                                                                                        \
00658   Fdl  = Hdl->fd;                                                                                                                         \
00659   Pdl->bk = Hdl;  Pdl->fd = Fdl;  Fdl->bk = Hdl->fd = Pdl;                                        \
00660 }                                                                                                                                                         \
00661 
00662 
00663 /* Place a consolidated chunk on a clean list */
00664 
00665 #define cleanlink(Qcl)                                                                                                            \
00666 {                                                                                                                                                         \
00667   mchunkptr Pcl = (Qcl);                                                                                                          \
00668   mbinptr Bcl;                                                                                                                            \
00669   mchunkptr Hcl, Fcl;                                                                                                             \
00670                                                                                                                                                           \
00671   findbin(Qcl->size, Bcl);                                                                                                        \
00672   Hcl  = clean_head(Bcl);                                                                                                         \
00673   Fcl  = Hcl->fd;                                                                                                                         \
00674   if (Hcl == Fcl) {                                                           \
00675     if (Bcl < minClean) minClean = Bcl;                                       \
00676     if (Bcl > maxClean) maxClean = Bcl;                                       \
00677   }                                                                                                       \
00678   Pcl->bk = Hcl;  Pcl->fd = Fcl;  Fcl->bk = Hcl->fd = Pcl;                                        \
00679 }                                                                                                                                                         \
00680 
00681 
00682 #if __STD_C
00683 static void callcleanlink(mchunkptr p) 
00684 #else
00685 static void callcleanlink(p) mchunkptr p;
00686 #endif
00687 { 
00688   cleanlink(p); 
00689 }
00690 
00691 
00692 
00693 /* consolidate one chunk */
00694 
00695 #define consolidate(Qc)                                                                                                           \
00696 {                                                                                                                                                         \
00697   for (;;)                                                                                                                                        \
00698   {                                                                                                                                                       \
00699     mchunkptr Pc = prev_chunk(Qc);                                                                                        \
00700     if (!inuse(Pc))                                                                                                                       \
00701     {                                                                                                                                             \
00702       unlink(Pc);                                                                                                                         \
00703       set_size(Pc, Pc->size + (Qc)->size);                                                                        \
00704       (Qc) = Pc;                                                                                                                          \
00705     }                                                                                                                                             \
00706     else break;                                                                                                                           \
00707   }                                                                                                                                                       \
00708   for (;;)                                                                                                                                        \
00709   {                                                                                                                                                       \
00710     mchunkptr Nc = next_chunk(Qc);                                                                                        \
00711     if (!inuse(Nc))                                                                                                                       \
00712     {                                                                                                                                             \
00713       unlink(Nc);                                                                                                                         \
00714       set_size((Qc), (Qc)->size + Nc->size);                                                              \
00715     }                                                                                                                                             \
00716     else break;                                                                                                                           \
00717   }                                                                                                                                                       \
00718 }                                                                                                                                                         \
00719 
00720 
00721 /* Place a freed chunk on the returns */
00722 
00723 #define returnlink(Prc)                                                                                                   \
00724 {                                                                                                                                                         \
00725   (Prc)->fd = returns;                                                                                            \
00726   returns = (Prc);                                                                                                        \
00727 }                                                                                                                                                         \
00728 
00729 
00730 
00731 /* Misc utilities */
00732 
00733 /* A helper for realloc */
00734 
00735 static void clear_aux_lists()
00736 {
00737   if (last_remainder != 0)
00738   {                             
00739     cleanlink(last_remainder);
00740     last_remainder = 0;
00741   }                                                             
00742 
00743   while (returns != 0)
00744   {
00745     mchunkptr p = returns;
00746     returns = p->fd;
00747     dirtylink(p);
00748   }
00749 }
00750 
00751 
00752 
00753 
00754 /* Dealing with sbrk */
00755 /* This is one step of malloc; broken out for simplicity */
00756 
00757 static size_t sbrked_mem = 0; /* Keep track of total mem for malloc_stats */
00758 
00759 #if __STD_C
00760 static mchunkptr malloc_from_sys(size_t nb)
00761 #else
00762 static mchunkptr malloc_from_sys(nb) size_t nb;
00763 #endif
00764 {
00765 
00766   /* The end of memory returned from previous sbrk call */
00767   static size_t* last_sbrk_end = 0; 
00768 
00769   mchunkptr p;            /* Will hold a usable chunk */
00770   size_t*   ip;           /* to traverse sbrk ptr in size_t units */
00771   char*     cp;           /* result of sbrk call */
00772   int       offs;         /* bytes must add for alignment */
00773   
00774   /* Find a good size to ask sbrk for.  */
00775   /* Minimally, we need to pad with enough space */
00776   /* to place dummy size/use fields to ends if needed */
00777 
00778   size_t sbrk_size = ((nb + SBRK_UNIT - 1 + SIZE_SZ + SIZE_SZ) 
00779                        / SBRK_UNIT) * SBRK_UNIT;
00780 
00781   cp = (char*)(sbrk(sbrk_size));
00782   if (cp == (char*)(-1)) /* sbrk returns -1 on failure */
00783     return 0;
00784   sbrked_mem += sbrk_size;
00785 
00786   if (((size_t)cp) & MALLOC_ALIGN_MASK) {
00787     offs = ((size_t)cp) & MALLOC_ALIGN_MASK;
00788     cp += MALLOC_MIN_OVERHEAD - offs;
00789     sbrk_size -= MALLOC_MIN_OVERHEAD;
00790     sbrk(- offs);
00791   }
00792     
00793   ip = (size_t*)cp;
00794 
00795   if (last_sbrk_end != &ip[-1]) /* Is this chunk continguous with last? */
00796   {                             
00797     /* It's either first time through or someone else called sbrk. */
00798     /* Arrange end-markers at front & back */
00799 
00800     /* Mark the front as in use to prevent merging. (End done below.) */
00801     /* Note we can get away with only 1 word, not MINSIZE overhead here */
00802 
00803     *ip++ = SIZE_SZ | INUSE;
00804     
00805     p = (mchunkptr)ip;
00806     set_size(p,sbrk_size - (SIZE_SZ + SIZE_SZ)); 
00807     
00808   }
00809   else 
00810   {
00811     mchunkptr l;  
00812 
00813     /* We can safely make the header start at end of prev sbrked chunk. */
00814     /* We will still have space left at the end from a previous call */
00815     /* to place the end marker, below */
00816 
00817     p = (mchunkptr)(last_sbrk_end);
00818     set_size(p, sbrk_size);
00819 
00820     /* Even better, maybe we can merge with last fragment: */
00821 
00822     l = prev_chunk(p);
00823     if (!inuse(l))  
00824     {
00825       unlink(l);
00826       set_size(l, p->size + l->size);
00827       p = l;
00828     }
00829 
00830   }
00831 
00832   /* mark the end of sbrked space as in use to prevent merging */
00833 
00834   last_sbrk_end = (size_t*)((char*)p + p->size);
00835   *last_sbrk_end = SIZE_SZ | INUSE;
00836 
00837   return p;
00838 }
00839 
00840 
00841 
00842 /* The less-frequent steps of malloc broken out as a procedure. */
00843 /* (Allows compilers to better optimize main steps.) */
00844  
00845 #if __STD_C
00846 static mchunkptr malloc_consolidate(size_t nb)
00847 #else
00848 static mchunkptr malloc_consolidate(nb) size_t nb;
00849 #endif
00850 {
00851   static mbinptr rover = LASTBIN;        /* Circular ptr for consolidation */
00852 
00853   mbinptr origin, b;
00854 
00855   /* Consolidate last remainder first. */
00856   /* It must be binned before any other consolidations, so might as well */
00857   /* consolidate it too.  This also helps make up for false-alarm  */
00858   /* preallocations */
00859 
00860   mchunkptr victim = last_remainder;
00861   last_remainder = 0;
00862 
00863   if (victim != 0)
00864   {
00865     consolidate(victim);
00866     
00867     if (victim->size >= nb)
00868       return victim;
00869     else
00870       cleanlink(victim);
00871   }
00872 
00873   /* -------------- Sweep through and consolidate other dirty bins */
00874 
00875   origin = rover;     /* Start where left off last time. */
00876   b      = rover;
00877   do
00878   {
00879     halve_bin_use(b);  /* decr use counts while traversing */
00880     
00881     while ( (victim = last_dirty(b)) != dirty_head(b))
00882     {
00883       unlink(victim);
00884       consolidate(victim);
00885       
00886       if (victim->size >= nb)
00887       {
00888         rover = b;
00889         return victim;
00890       }
00891       else
00892         cleanlink(victim);
00893     }
00894     
00895     
00896     b = (b <= FIRSTBIN)? LASTBIN : b - 1;      /* circularly sweep */
00897     
00898   } while (b != origin);
00899 
00900   
00901   /* -------------  Nothing available; get some from sys */
00902 
00903   return malloc_from_sys(nb);
00904 }
00905 
00906 
00907 #if __STD_C
00908 MM_LINK Void_t* malloc(size_t bytes)
00909 #else
00910 MM_LINK Void_t* malloc(bytes) size_t bytes;
00911 #endif
00912 {
00913   static mchunkptr bad_rl_chunk = 0;     /* last scanned return-list chunk */
00914   static mbinptr prevClean = FIRSTBIN;  /* likely clean bin to use */
00915 
00916   mchunkptr victim;                      /* will hold selected chunk */
00917   mbinptr   bin;                         /* corresponding bin */
00918 
00919   /* ----------- Peek (twice) at returns; hope for luck */
00920 
00921   mchunkptr rl = returns;                /* local for speed/simplicity */
00922   size_t nb = request2size(bytes)    ;   /* padded request size; */
00923 
00924   if (rl != 0)
00925   {
00926     mchunkptr snd = rl->fd;
00927     if (exact_fit(rl, nb)) /* size check works even though INUSE set */
00928     {
00929       returns = snd;
00930       return chunk2mem(rl);
00931     }
00932     else if (snd != 0 && exact_fit(snd, nb))
00933     {
00934       returns->fd = snd->fd;
00935       return chunk2mem(snd);
00936     }
00937     else if (rl == bad_rl_chunk)     /* If we keep failing, bin one */
00938     {
00939       dirtylink(rl);
00940       returns = rl = snd;
00941     }
00942     bad_rl_chunk = rl;
00943   }
00944 
00945 
00946 
00947   /* ---------- Scan own dirty bin */
00948 
00949   if (nb < (MAX_SMALLBIN_SIZE - SMALLBIN_SIZE))
00950   {
00951     /* Small bins special-cased since no size check or traversal needed. */
00952     /* Also because of MINSIZE slop, next dirty bin is exact fit too */
00953 
00954     smallfindbin(nb, bin);
00955 
00956     if ( ((victim = last_dirty(bin)) != dirty_head(bin)) ||
00957          ((victim = last_clean(bin)) != clean_head(bin)) ||
00958          ((victim = last_dirty(bin+1)) != dirty_head(bin+1)))
00959     {
00960       unlink(victim);
00961       set_inuse(victim);
00962       return chunk2mem(victim);
00963     }
00964 
00965   }
00966   else
00967   {
00968     findbin(nb, bin);
00969 
00970     for (victim=last_dirty(bin); victim != dirty_head(bin); victim=victim->bk)
00971     {
00972       if (exact_fit(victim, nb))     /* Can use exact matches only here */
00973       {
00974         unlink(victim);
00975         set_inuse(victim);
00976         return chunk2mem(victim);
00977       }
00978     }
00979 
00980     for (victim=last_clean(bin); victim != clean_head(bin); victim=victim->bk)
00981     {
00982       if (victim->size >= nb)
00983       {
00984         unlink(victim); 
00985         goto split;
00986       }
00987     }
00988   }
00989 
00990 
00991   /* ------------ Search return list, placing unusable chunks in their bins  */
00992 
00993 
00994   if (rl != 0)
00995   {
00996     victim = rl;  
00997     rl = rl->fd;
00998     for (;;)
00999     {
01000       dirtylink(victim);
01001       if (rl == 0)
01002       {
01003         returns = rl;
01004         break;
01005       }
01006       victim = rl;
01007       rl = rl->fd;
01008       if (exact_fit(victim, nb))
01009       {
01010         bad_rl_chunk = returns = rl;
01011         return chunk2mem(victim);
01012       }
01013     }
01014   }
01015 
01016   if (bin < maxClean)
01017   {
01018     mbinptr b;
01019 
01020     /* -------------- First try last successful clean bin  */
01021 
01022     if (bin < prevClean) 
01023     {
01024       if ( (victim = last_clean(prevClean)) != clean_head(prevClean) ) 
01025       {
01026         unlink(victim);
01027         goto split;
01028       }
01029     }
01030 
01031 
01032     /* -------------- Scan others  */
01033 
01034     for (b = (bin < minClean)? minClean : (bin + 1); b <= maxClean; ++b)
01035     {
01036       if ( (victim = last_clean(b)) != clean_head(b) ) 
01037       {
01038         /* If more, record  */
01039         if (bin_use(b) == 0 && victim->bk != clean_head(b)) prevClean = b;
01040         else { halve_bin_use(b); prevClean = FIRSTBIN; }
01041 
01042         unlink(victim);
01043         if (bin < minClean) minClean = b;         /* b must be <= true min */
01044         goto split;
01045       }
01046     }
01047 
01048     /* --------------  If fall through, recompute bounds for next time */
01049 
01050     while (maxClean >= FIRSTBIN && clean_head(maxClean)==last_clean(maxClean))
01051       --maxClean;
01052     if (maxClean < FIRSTBIN) /* reset at endpoints if no clean bins */
01053       minClean = POST_LASTBIN;
01054     else
01055     {
01056       while (minClean < maxClean && clean_head(minClean)==last_clean(minClean))
01057         ++minClean;
01058     }
01059 
01060     prevClean = FIRSTBIN;
01061 
01062   }
01063 
01064 
01065   /* -------------- Try remainder from previous split */
01066     
01067   if ( (victim = last_remainder) != 0)
01068   {
01069     if (victim->size >= nb)
01070     {
01071       last_remainder = 0;
01072       goto split;
01073     }
01074   }
01075 
01076 
01077   /* -------------- Other steps called via malloc_consolidate */
01078 
01079   victim = malloc_consolidate(nb);
01080   if (victim == 0) return 0;   /* propagate failure */
01081 
01082 
01083   /* -------------- Possibly split victim chunk */
01084 
01085  split:  
01086   {
01087     size_t room = victim->size - nb;
01088 
01089     if (room < MINSIZE)
01090     {
01091       set_inuse(victim);
01092       return chunk2mem(victim);
01093     }
01094     else    /* must create remainder */ 
01095     {
01096       mchunkptr remainder;
01097       int desired;
01098 
01099       set_inuse_size(victim, nb);
01100       remainder = (mchunkptr)((char*)(victim) + nb);
01101 
01102       desired = inc_bin_use(bin);
01103 
01104       /* ---------- Preallocate more of this size */
01105 
01106       if (nb < MAX_SMALLBIN_SIZE && room >= nb + MINSIZE && desired != 0) 
01107       {
01108         int actual = 1;
01109 
01110         /* place in ascending order on ret list */
01111         mchunkptr first = remainder;
01112         mchunkptr last = remainder;
01113         set_inuse_size(remainder, nb);
01114         remainder = (mchunkptr)((char*)(remainder) + nb);
01115         
01116         if (desired > MAX_PREALLOCS)  desired = MAX_PREALLOCS;
01117         
01118         while ( (room -= nb) >= nb + MINSIZE && actual < desired)
01119         {
01120           ++actual;
01121           set_inuse_size(remainder, nb);
01122           last->fd = remainder; 
01123           last = remainder; 
01124           remainder = (mchunkptr)((char*)(remainder) + nb);
01125         }
01126         
01127         last->fd = returns;
01128         returns = first;
01129         
01130         add_bin_use(bin, actual); 
01131       }
01132 
01133       /* ---------- Put away remainder chunk  */
01134 
01135       set_size(remainder, room);
01136 
01137       /* get rid of old one */
01138       if (last_remainder != 0) callcleanlink(last_remainder);
01139       last_remainder = remainder;
01140 
01141       return chunk2mem(victim);
01142 
01143     }
01144   }
01145 }
01146 
01147 
01148 
01149 
01150 #if __STD_C
01151 MM_LINK void free(Void_t* mem)
01152 #else
01153 MM_LINK void free(mem) Void_t* mem;
01154 #endif
01155 {
01156   if (mem != 0)
01157   {
01158     mchunkptr p = mem2chunk(mem);
01159     returnlink(p);
01160   }
01161 }
01162 
01163  
01164 
01165 
01166 /* Special-purpose copy for realloc */
01167 /* Copy bytes in size_t units, adjusting for chunk header */
01168 
01169 #define SCopy(SCs,SCd,SCc)                                                                                                        \
01170 {                                                                                                                                                         \
01171   size_t * SCsrc = (size_t*) SCs;                                                                                         \
01172   size_t * SCdst = (size_t*) SCd;                                                                                         \
01173   size_t SCcount = (SCc - SIZE_SZ) / sizeof(size_t);                                              \
01174   do { *SCdst++ = *SCsrc++; } while (--SCcount > 0);                                              \
01175 }
01176 
01177 
01178 #if __STD_C
01179 MM_LINK Void_t* realloc(Void_t* mem, size_t bytes)
01180 #else
01181 MM_LINK Void_t* realloc(mem, bytes) Void_t* mem; size_t bytes;
01182 #endif
01183 {
01184   if (mem == 0) 
01185     return malloc(bytes);
01186   else
01187   {
01188     size_t       nb      = request2size(bytes);
01189     mchunkptr    p       = mem2chunk(mem);
01190     size_t       oldsize;
01191     Void_t*      newmem;
01192     size_t       room;
01193     int          back_expanded = 0;
01194 
01195     if (p == returns) /* sorta support realloc-last-freed-chunk idiocy */
01196        returns = returns->fd;
01197 
01198     clear_inuse(p);
01199     oldsize = p->size;
01200 
01201     /* try to expand. */
01202 
01203     clear_aux_lists();     /* make freed chunks available to consolidate */
01204 
01205     if (p->size < nb)      /* forward as far as possible */
01206     {
01207       for (;;)
01208       {
01209         mchunkptr nxt = next_chunk(p);
01210         if (!inuse(nxt))
01211         {
01212           unlink(nxt);
01213           set_size(p, p->size + nxt->size);
01214         }
01215         else break;
01216       }
01217     }
01218 
01219     while (p->size < nb)  /* backward only if and as far as necessary */
01220     {
01221       mchunkptr prv = prev_chunk(p);
01222       if (!inuse(prv))                                  
01223       {
01224         back_expanded = 1;
01225         unlink(prv);
01226         set_size(prv, prv->size + p->size);
01227         p = prv;
01228       }
01229       else break;
01230     }
01231 
01232     if (p->size < nb)    /* Could not expand. Get another chunk. */
01233     {
01234       mchunkptr    newp;
01235 
01236       set_inuse(p);      /* don't let malloc consolidate p yet! */
01237       newmem = malloc(nb);
01238       newp = mem2chunk(newmem); 
01239 
01240       /* Avoid copy if newp is next chunk after oldp. */
01241       /* This can only happen when new chunk is sbrk'ed, */
01242       /* which is common enough in reallocs to deal with here. */
01243 
01244       if (newp == next_chunk(p)) 
01245       {
01246 
01247         if (back_expanded) /* Must copy first anyway; still worth it */
01248           SCopy(mem, chunk2mem(p), oldsize);
01249 
01250         clear_inuse(p);
01251         clear_inuse(newp);
01252         set_size(p, p->size + newp->size);
01253 
01254         room = p->size - nb;
01255         if (room >= MINSIZE)  /* give some back */
01256         {
01257           mchunkptr remainder = (mchunkptr)((char*)(p) + nb);
01258           set_size(remainder, room);
01259           set_size(p, nb);
01260 
01261           /* clean up remainder; it must be start of new sbrked space */
01262           clear_aux_lists();   /* Clear, in case malloc preallocated */
01263           for (;;)
01264           {
01265             mchunkptr nxt = next_chunk(remainder);
01266             if (!inuse(nxt))
01267             {
01268               unlink(nxt);
01269               set_size(remainder, remainder->size + nxt->size);
01270             }
01271             else break;
01272           }
01273           last_remainder = remainder;
01274         }
01275 
01276         set_inuse(p);
01277         return chunk2mem(p);
01278       }
01279       else
01280       {
01281         if (newmem != 0) SCopy(mem, newmem, oldsize);
01282         returnlink(p);
01283         return newmem;
01284       }
01285     }
01286     else
01287     {
01288       room = p->size - nb;
01289       newmem = chunk2mem(p);
01290 
01291       if (back_expanded) SCopy(mem, newmem, oldsize);
01292         
01293       if (room >= MINSIZE)  /* give some back if possible */
01294       {
01295         mchunkptr remainder = (mchunkptr)((char*)(p) + nb);
01296         set_size(remainder, room);
01297         dirtylink(remainder); /* not sure; be saf