diff options
| author | wdenk <wdenk> | 2000-07-19 14:09:16 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2000-07-19 14:09:16 +0000 | 
| commit | 40c855574cff21a97c01d8f8d2ee2b8436eebce2 (patch) | |
| tree | 8a38e01d35fed05ea6e752642cc8eb3a4fa564ab | |
| parent | 7309612797ed5e6b3b20027e28bca970b4f6b8fd (diff) | |
| download | olio-uboot-2014.01-40c855574cff21a97c01d8f8d2ee2b8436eebce2.tar.xz olio-uboot-2014.01-40c855574cff21a97c01d8f8d2ee2b8436eebce2.zip | |
Initial revision
| -rw-r--r-- | common/dlmalloc.src | 3276 | ||||
| -rw-r--r-- | include/ppc_defs.h | 91 | ||||
| -rw-r--r-- | lib_generic/ctype.c | 56 | ||||
| -rw-r--r-- | lib_ppc/ppcstring.S | 216 | 
4 files changed, 3639 insertions, 0 deletions
| diff --git a/common/dlmalloc.src b/common/dlmalloc.src new file mode 100644 index 000000000..12b85bb83 --- /dev/null +++ b/common/dlmalloc.src @@ -0,0 +1,3276 @@ +/* ---------- To make a malloc.h, start cutting here ------------ */ + +/* +  A version of malloc/free/realloc written by Doug Lea and released to the +  public domain.  Send questions/comments/complaints/performance data +  to dl@cs.oswego.edu + +* VERSION 2.6.6  Sun Mar  5 19:10:03 2000  Doug Lea  (dl at gee) + +   Note: There may be an updated version of this malloc obtainable at +           ftp://g.oswego.edu/pub/misc/malloc.c +         Check before installing! + +* Why use this malloc? + +  This is not the fastest, most space-conserving, most portable, or +  most tunable malloc ever written. However it is among the fastest +  while also being among the most space-conserving, portable and tunable. +  Consistent balance across these factors results in a good general-purpose +  allocator. For a high-level description, see +     http://g.oswego.edu/dl/html/malloc.html + +* Synopsis of public routines + +  (Much fuller descriptions are contained in the program documentation below.) + +  malloc(size_t n); +     Return a pointer to a newly allocated chunk of at least n bytes, or null +     if no space is available. +  free(Void_t* p); +     Release the chunk of memory pointed to by p, or no effect if p is null. +  realloc(Void_t* p, size_t n); +     Return a pointer to a chunk of size n that contains the same data +     as does chunk p up to the minimum of (n, p's size) bytes, or null +     if no space is available. The returned pointer may or may not be +     the same as p. If p is null, equivalent to malloc.  Unless the +     #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a +     size argument of zero (re)allocates a minimum-sized chunk. +  memalign(size_t alignment, size_t n); +     Return a pointer to a newly allocated chunk of n bytes, aligned +     in accord with the alignment argument, which must be a power of +     two. +  valloc(size_t n); +     Equivalent to memalign(pagesize, n), where pagesize is the page +     size of the system (or as near to this as can be figured out from +     all the includes/defines below.) +  pvalloc(size_t n); +     Equivalent to valloc(minimum-page-that-holds(n)), that is, +     round up n to nearest pagesize. +  calloc(size_t unit, size_t quantity); +     Returns a pointer to quantity * unit bytes, with all locations +     set to zero. +  cfree(Void_t* p); +     Equivalent to free(p). +  malloc_trim(size_t pad); +     Release all but pad bytes of freed top-most memory back +     to the system. Return 1 if successful, else 0. +  malloc_usable_size(Void_t* p); +     Report the number usable allocated bytes associated with allocated +     chunk p. This may or may not report more bytes than were requested, +     due to alignment and minimum size constraints. +  malloc_stats(); +     Prints brief summary statistics on stderr. +  mallinfo() +     Returns (by copy) a struct containing various summary statistics. +  mallopt(int parameter_number, int parameter_value) +     Changes one of the tunable parameters described below. Returns +     1 if successful in changing the parameter, else 0. + +* Vital statistics: + +  Alignment:                            8-byte +       8 byte alignment is currently hardwired into the design.  This +       seems to suffice for all current machines and C compilers. + +  Assumed pointer representation:       4 or 8 bytes +       Code for 8-byte pointers is untested by me but has worked +       reliably by Wolfram Gloger, who contributed most of the +       changes supporting this. + +  Assumed size_t  representation:       4 or 8 bytes +       Note that size_t is allowed to be 4 bytes even if pointers are 8. + +  Minimum overhead per allocated chunk: 4 or 8 bytes +       Each malloced chunk has a hidden overhead of 4 bytes holding size +       and status information. + +  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead) +                          8-byte ptrs:  24/32 bytes (including, 4/8 overhead) + +       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte +       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are +       needed; 4 (8) for a trailing size field +       and 8 (16) bytes for free list pointers. Thus, the minimum +       allocatable size is 16/24/32 bytes. + +       Even a request for zero bytes (i.e., malloc(0)) returns a +       pointer to something of the minimum allocatable size. + +  Maximum allocated size: 4-byte size_t: 2^31 -  8 bytes +                          8-byte size_t: 2^63 - 16 bytes + +       It is assumed that (possibly signed) size_t bit values suffice to +       represent chunk sizes. `Possibly signed' is due to the fact +       that `size_t' may be defined on a system as either a signed or +       an unsigned type. To be conservative, values that would appear +       as negative numbers are avoided. +       Requests for sizes with a negative sign bit when the request +       size is treaded as a long will return null. + +  Maximum overhead wastage per allocated chunk: normally 15 bytes + +       Alignnment demands, plus the minimum allocatable size restriction +       make the normal worst-case wastage 15 bytes (i.e., up to 15 +       more bytes will be allocated than were requested in malloc), with +       two exceptions: +         1. Because requests for zero bytes allocate non-zero space, +            the worst case wastage for a request of zero bytes is 24 bytes. +         2. For requests >= mmap_threshold that are serviced via +            mmap(), the worst case wastage is 8 bytes plus the remainder +            from a system page (the minimal mmap unit); typically 4096 bytes. + +* Limitations + +    Here are some features that are NOT currently supported + +    * No user-definable hooks for callbacks and the like. +    * No automated mechanism for fully checking that all accesses +      to malloced memory stay within their bounds. +    * No support for compaction. + +* Synopsis of compile-time options: + +    People have reported using previous versions of this malloc on all +    versions of Unix, sometimes by tweaking some of the defines +    below. It has been tested most extensively on Solaris and +    Linux. It is also reported to work on WIN32 platforms. +    People have also reported adapting this malloc for use in +    stand-alone embedded systems. + +    The implementation is in straight, hand-tuned ANSI C.  Among other +    consequences, it uses a lot of macros.  Because of this, to be at +    all usable, this code should be compiled using an optimizing compiler +    (for example gcc -O2) that can simplify expressions and control +    paths. + +  __STD_C                  (default: derived from C compiler defines) +     Nonzero if using ANSI-standard C compiler, a C++ compiler, or +     a C compiler sufficiently close to ANSI to get away with it. +  DEBUG                    (default: NOT defined) +     Define to enable debugging. Adds fairly extensive assertion-based +     checking to help track down memory errors, but noticeably slows down +     execution. +  REALLOC_ZERO_BYTES_FREES (default: NOT defined) +     Define this if you think that realloc(p, 0) should be equivalent +     to free(p). Otherwise, since malloc returns a unique pointer for +     malloc(0), so does realloc(p, 0). +  HAVE_MEMCPY               (default: defined) +     Define if you are not otherwise using ANSI STD C, but still +     have memcpy and memset in your C library and want to use them. +     Otherwise, simple internal versions are supplied. +  USE_MEMCPY               (default: 1 if HAVE_MEMCPY is defined, 0 otherwise) +     Define as 1 if you want the C library versions of memset and +     memcpy called in realloc and calloc (otherwise macro versions are used). +     At least on some platforms, the simple macro versions usually +     outperform libc versions. +  HAVE_MMAP                 (default: defined as 1) +     Define to non-zero to optionally make malloc() use mmap() to +     allocate very large blocks. +  HAVE_MREMAP                 (default: defined as 0 unless Linux libc set) +     Define to non-zero to optionally make realloc() use mremap() to +     reallocate very large blocks. +  malloc_getpagesize        (default: derived from system #includes) +     Either a constant or routine call returning the system page size. +  HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined) +     Optionally define if you are on a system with a /usr/include/malloc.h +     that declares struct mallinfo. It is not at all necessary to +     define this even if you do, but will ensure consistency. +  INTERNAL_SIZE_T           (default: size_t) +     Define to a 32-bit type (probably `unsigned int') if you are on a +     64-bit machine, yet do not want or need to allow malloc requests of +     greater than 2^31 to be handled. This saves space, especially for +     very small chunks. +  INTERNAL_LINUX_C_LIB      (default: NOT defined) +     Defined only when compiled as part of Linux libc. +     Also note that there is some odd internal name-mangling via defines +     (for example, internally, `malloc' is named `mALLOc') needed +     when compiling in this case. These look funny but don't otherwise +     affect anything. +  WIN32                     (default: undefined) +     Define this on MS win (95, nt) platforms to compile in sbrk emulation. +  LACKS_UNISTD_H            (default: undefined if not WIN32) +     Define this if your system does not have a <unistd.h>. +  LACKS_SYS_PARAM_H         (default: undefined if not WIN32) +     Define this if your system does not have a <sys/param.h>. +  MORECORE                  (default: sbrk) +     The name of the routine to call to obtain more memory from the system. +  MORECORE_FAILURE          (default: -1) +     The value returned upon failure of MORECORE. +  MORECORE_CLEARS           (default 1) +     True (1) if the routine mapped to MORECORE zeroes out memory (which +     holds for sbrk). +  DEFAULT_TRIM_THRESHOLD +  DEFAULT_TOP_PAD +  DEFAULT_MMAP_THRESHOLD +  DEFAULT_MMAP_MAX +     Default values of tunable parameters (described in detail below) +     controlling interaction with host system routines (sbrk, mmap, etc). +     These values may also be changed dynamically via mallopt(). The +     preset defaults are those that give best performance for typical +     programs/systems. +  USE_DL_PREFIX             (default: undefined) +     Prefix all public routines with the string 'dl'.  Useful to +     quickly avoid procedure declaration conflicts and linker symbol +     conflicts with existing memory allocation routines. + + +*/ + + + + +/* Preliminaries */ + +#ifndef __STD_C +#ifdef __STDC__ +#define __STD_C     1 +#else +#if __cplusplus +#define __STD_C     1 +#else +#define __STD_C     0 +#endif /*__cplusplus*/ +#endif /*__STDC__*/ +#endif /*__STD_C*/ + +#ifndef Void_t +#if (__STD_C || defined(WIN32)) +#define Void_t      void +#else +#define Void_t      char +#endif +#endif /*Void_t*/ + +#if __STD_C +#include <stddef.h>   /* for size_t */ +#else +#include <sys/types.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h>    /* needed for malloc_stats */ + + +/* +  Compile-time options +*/ + + +/* +    Debugging: + +    Because freed chunks may be overwritten with link fields, this +    malloc will often die when freed memory is overwritten by user +    programs.  This can be very effective (albeit in an annoying way) +    in helping track down dangling pointers. + +    If you compile with -DDEBUG, a number of assertion checks are +    enabled that will catch more memory errors. You probably won't be +    able to make much sense of the actual assertion errors, but they +    should help you locate incorrectly overwritten memory.  The +    checking is fairly extensive, and will slow down execution +    noticeably. Calling malloc_stats or mallinfo with DEBUG set will +    attempt to check every non-mmapped allocated and free chunk in the +    course of computing the summmaries. (By nature, mmapped regions +    cannot be checked very much automatically.) + +    Setting DEBUG may also be helpful if you are trying to modify +    this code. The assertions in the check routines spell out in more +    detail the assumptions and invariants underlying the algorithms. + +*/ + +#if DEBUG +#include <assert.h> +#else +#define assert(x) ((void)0) +#endif + + +/* +  INTERNAL_SIZE_T is the word-size used for internal bookkeeping +  of chunk sizes. On a 64-bit machine, you can reduce malloc +  overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' +  at the expense of not being able to handle requests greater than +  2^31. This limitation is hardly ever a concern; you are encouraged +  to set this. However, the default version is the same as size_t. +*/ + +#ifndef INTERNAL_SIZE_T +#define INTERNAL_SIZE_T size_t +#endif + +/* +  REALLOC_ZERO_BYTES_FREES should be set if a call to +  realloc with zero bytes should be the same as a call to free. +  Some people think it should. Otherwise, since this malloc +  returns a unique pointer for malloc(0), so does realloc(p, 0). +*/ + + +/*   #define REALLOC_ZERO_BYTES_FREES */ + + +/* +  WIN32 causes an emulation of sbrk to be compiled in +  mmap-based options are not currently supported in WIN32. +*/ + +/* #define WIN32 */ +#ifdef WIN32 +#define MORECORE wsbrk +#define HAVE_MMAP 0 + +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H + +/* +  Include 'windows.h' to get the necessary declarations for the +  Microsoft Visual C++ data structures and routines used in the 'sbrk' +  emulation. + +  Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft +  Visual C++ header files are included. +*/ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + + +/* +  HAVE_MEMCPY should be defined if you are not otherwise using +  ANSI STD C, but still have memcpy and memset in your C library +  and want to use them in calloc and realloc. Otherwise simple +  macro versions are defined here. + +  USE_MEMCPY should be defined as 1 if you actually want to +  have memset and memcpy called. People report that the macro +  versions are often enough faster than libc versions on many +  systems that it is better to use them. + +*/ + +#define HAVE_MEMCPY + +#ifndef USE_MEMCPY +#ifdef HAVE_MEMCPY +#define USE_MEMCPY 1 +#else +#define USE_MEMCPY 0 +#endif +#endif + +#if (__STD_C || defined(HAVE_MEMCPY)) + +#if __STD_C +void* memset(void*, int, size_t); +void* memcpy(void*, const void*, size_t); +#else +#ifdef WIN32 +// On Win32 platforms, 'memset()' and 'memcpy()' are already declared in +// 'windows.h' +#else +Void_t* memset(); +Void_t* memcpy(); +#endif +#endif +#endif + +#if USE_MEMCPY + +/* The following macros are only invoked with (2n+1)-multiples of +   INTERNAL_SIZE_T units, with a positive integer n. This is exploited +   for fast inline execution when n is small. */ + +#define MALLOC_ZERO(charp, nbytes)                                            \ +do {                                                                          \ +  INTERNAL_SIZE_T mzsz = (nbytes);                                            \ +  if(mzsz <= 9*sizeof(mzsz)) {                                                \ +    INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp);                         \ +    if(mzsz >= 5*sizeof(mzsz)) {     *mz++ = 0;                               \ +                                     *mz++ = 0;                               \ +      if(mzsz >= 7*sizeof(mzsz)) {   *mz++ = 0;                               \ +                                     *mz++ = 0;                               \ +        if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0;                               \ +                                     *mz++ = 0; }}}                           \ +                                     *mz++ = 0;                               \ +                                     *mz++ = 0;                               \ +                                     *mz   = 0;                               \ +  } else memset((charp), 0, mzsz);                                            \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes)                                          \ +do {                                                                          \ +  INTERNAL_SIZE_T mcsz = (nbytes);                                            \ +  if(mcsz <= 9*sizeof(mcsz)) {                                                \ +    INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src);                        \ +    INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest);                       \ +    if(mcsz >= 5*sizeof(mcsz)) {     *mcdst++ = *mcsrc++;                     \ +                                     *mcdst++ = *mcsrc++;                     \ +      if(mcsz >= 7*sizeof(mcsz)) {   *mcdst++ = *mcsrc++;                     \ +                                     *mcdst++ = *mcsrc++;                     \ +        if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++;                     \ +                                     *mcdst++ = *mcsrc++; }}}                 \ +                                     *mcdst++ = *mcsrc++;                     \ +                                     *mcdst++ = *mcsrc++;                     \ +                                     *mcdst   = *mcsrc  ;                     \ +  } else memcpy(dest, src, mcsz);                                             \ +} while(0) + +#else /* !USE_MEMCPY */ + +/* Use Duff's device for good zeroing/copying performance. */ + +#define MALLOC_ZERO(charp, nbytes)                                            \ +do {                                                                          \ +  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \ +  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \ +  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \ +  switch (mctmp) {                                                            \ +    case 0: for(;;) { *mzp++ = 0;                                             \ +    case 7:           *mzp++ = 0;                                             \ +    case 6:           *mzp++ = 0;                                             \ +    case 5:           *mzp++ = 0;                                             \ +    case 4:           *mzp++ = 0;                                             \ +    case 3:           *mzp++ = 0;                                             \ +    case 2:           *mzp++ = 0;                                             \ +    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \ +  }                                                                           \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes)                                          \ +do {                                                                          \ +  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \ +  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \ +  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \ +  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \ +  switch (mctmp) {                                                            \ +    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \ +    case 7:           *mcdst++ = *mcsrc++;                                    \ +    case 6:           *mcdst++ = *mcsrc++;                                    \ +    case 5:           *mcdst++ = *mcsrc++;                                    \ +    case 4:           *mcdst++ = *mcsrc++;                                    \ +    case 3:           *mcdst++ = *mcsrc++;                                    \ +    case 2:           *mcdst++ = *mcsrc++;                                    \ +    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \ +  }                                                                           \ +} while(0) + +#endif + + +/* +  Define HAVE_MMAP to optionally make malloc() use mmap() to +  allocate very large blocks.  These will be returned to the +  operating system immediately after a free(). +*/ + +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif + +/* +  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate +  large blocks.  This is currently only possible on Linux with +  kernel versions newer than 1.3.77. +*/ + +#ifndef HAVE_MREMAP +#ifdef INTERNAL_LINUX_C_LIB +#define HAVE_MREMAP 1 +#else +#define HAVE_MREMAP 0 +#endif +#endif + +#if HAVE_MMAP + +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + +#endif /* HAVE_MMAP */ + +/* +  Access to system page size. To the extent possible, this malloc +  manages memory from the system in page-size units. + +  The following mechanics for getpagesize were adapted from +  bsd/gnu getpagesize.h +*/ + +#ifndef LACKS_UNISTD_H +#  include <unistd.h> +#endif + +#ifndef malloc_getpagesize +#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */ +#    ifndef _SC_PAGE_SIZE +#      define _SC_PAGE_SIZE _SC_PAGESIZE +#    endif +#  endif +#  ifdef _SC_PAGE_SIZE +#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +#  else +#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) +       extern size_t getpagesize(); +#      define malloc_getpagesize getpagesize() +#    else +#      ifdef WIN32 +#        define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */ +#      else +#        ifndef LACKS_SYS_PARAM_H +#          include <sys/param.h> +#        endif +#        ifdef EXEC_PAGESIZE +#          define malloc_getpagesize EXEC_PAGESIZE +#        else +#          ifdef NBPG +#            ifndef CLSIZE +#              define malloc_getpagesize NBPG +#            else +#              define malloc_getpagesize (NBPG * CLSIZE) +#            endif +#          else +#            ifdef NBPC +#              define malloc_getpagesize NBPC +#            else +#              ifdef PAGESIZE +#                define malloc_getpagesize PAGESIZE +#              else +#                define malloc_getpagesize (4096) /* just guess */ +#              endif +#            endif +#          endif +#        endif +#      endif +#    endif +#  endif +#endif + + + +/* + +  This version of malloc supports the standard SVID/XPG mallinfo +  routine that returns a struct containing the same kind of +  information you can get from malloc_stats. It should work on +  any SVID/XPG compliant system that has a /usr/include/malloc.h +  defining struct mallinfo. (If you'd like to install such a thing +  yourself, cut out the preliminary declarations as described above +  and below and save them in a malloc.h file. But there's no +  compelling reason to bother to do this.) + +  The main declaration needed is the mallinfo struct that is returned +  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a +  bunch of fields, most of which are not even meaningful in this +  version of malloc. Some of these fields are are instead filled by +  mallinfo() with other numbers that might possibly be of interest. + +  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a +  /usr/include/malloc.h file that includes a declaration of struct +  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant +  version is declared below.  These must be precisely the same for +  mallinfo() to work. + +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#if HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else + +/* SVID2/XPG mallinfo structure */ + +struct mallinfo { +  int arena;    /* total space allocated from system */ +  int ordblks;  /* number of non-inuse chunks */ +  int smblks;   /* unused -- always zero */ +  int hblks;    /* number of mmapped regions */ +  int hblkhd;   /* total space in mmapped regions */ +  int usmblks;  /* unused -- always zero */ +  int fsmblks;  /* unused -- always zero */ +  int uordblks; /* total allocated space */ +  int fordblks; /* total non-inuse space */ +  int keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +/* SVID2/XPG mallopt options */ + +#define M_MXFAST  1    /* UNUSED in this malloc */ +#define M_NLBLKS  2    /* UNUSED in this malloc */ +#define M_GRAIN   3    /* UNUSED in this malloc */ +#define M_KEEP    4    /* UNUSED in this malloc */ + +#endif + +/* mallopt options that actually do something */ + +#define M_TRIM_THRESHOLD    -1 +#define M_TOP_PAD           -2 +#define M_MMAP_THRESHOLD    -3 +#define M_MMAP_MAX          -4 + + + +#ifndef DEFAULT_TRIM_THRESHOLD +#define DEFAULT_TRIM_THRESHOLD (128 * 1024) +#endif + +/* +    M_TRIM_THRESHOLD is the maximum amount of unused top-most memory +      to keep before releasing via malloc_trim in free(). + +      Automatic trimming is mainly useful in long-lived programs. +      Because trimming via sbrk can be slow on some systems, and can +      sometimes be wasteful (in cases where programs immediately +      afterward allocate more large chunks) the value should be high +      enough so that your overall system performance would improve by +      releasing. + +      The trim threshold and the mmap control parameters (see below) +      can be traded off with one another. Trimming and mmapping are +      two different ways of releasing unused memory back to the +      system. Between these two, it is often possible to keep +      system-level demands of a long-lived program down to a bare +      minimum. For example, in one test suite of sessions measuring +      the XF86 X server on Linux, using a trim threshold of 128K and a +      mmap threshold of 192K led to near-minimal long term resource +      consumption. + +      If you are using this malloc in a long-lived program, it should +      pay to experiment with these values.  As a rough guide, you +      might set to a value close to the average size of a process +      (program) running on your system.  Releasing this much memory +      would allow such a process to run in memory.  Generally, it's +      worth it to tune for trimming rather tham memory mapping when a +      program undergoes phases where several large chunks are +      allocated and released in ways that can reuse each other's +      storage, perhaps mixed with phases where there are no such +      chunks at all.  And in well-behaved long-lived programs, +      controlling release of large blocks via trimming versus mapping +      is usually faster. + +      However, in most programs, these parameters serve mainly as +      protection against the system-level effects of carrying around +      massive amounts of unneeded memory. Since frequent calls to +      sbrk, mmap, and munmap otherwise degrade performance, the default +      parameters are set to relatively high values that serve only as +      safeguards. + +      The default trim value is high enough to cause trimming only in +      fairly extreme (by current memory consumption standards) cases. +      It must be greater than page size to have any useful effect.  To +      disable trimming completely, you can set to (unsigned long)(-1); + + +*/ + + +#ifndef DEFAULT_TOP_PAD +#define DEFAULT_TOP_PAD        (0) +#endif + +/* +    M_TOP_PAD is the amount of extra `padding' space to allocate or +      retain whenever sbrk is called. It is used in two ways internally: + +      * When sbrk is called to extend the top of the arena to satisfy +        a new malloc request, this much padding is added to the sbrk +        request. + +      * When malloc_trim is called automatically from free(), +        it is used as the `pad' argument. + +      In both cases, the actual amount of padding is rounded +      so that the end of the arena is always a system page boundary. + +      The main reason for using padding is to avoid calling sbrk so +      often. Having even a small pad greatly reduces the likelihood +      that nearly every malloc request during program start-up (or +      after trimming) will invoke sbrk, which needlessly wastes +      time. + +      Automatic rounding-up to page-size units is normally sufficient +      to avoid measurable overhead, so the default is 0.  However, in +      systems where sbrk is relatively slow, it can pay to increase +      this value, at the expense of carrying around more memory than +      the program needs. + +*/ + + +#ifndef DEFAULT_MMAP_THRESHOLD +#define DEFAULT_MMAP_THRESHOLD (128 * 1024) +#endif + +/* + +    M_MMAP_THRESHOLD is the request size threshold for using mmap() +      to service a request. Requests of at least this size that cannot +      be allocated using already-existing space will be serviced via mmap. +      (If enough normal freed space already exists it is used instead.) + +      Using mmap segregates relatively large chunks of memory so that +      they can be individually obtained and released from the host +      system. A request serviced through mmap is never reused by any +      other request (at least not directly; the system may just so +      happen to remap successive requests to the same locations). + +      Segregating space in this way has the benefit that mmapped space +      can ALWAYS be individually released back to the system, which +      helps keep the system level memory demands of a long-lived +      program low. Mapped memory can never become `locked' between +      other chunks, as can happen with normally allocated chunks, which +      menas that even trimming via malloc_trim would not release them. + +      However, it has the disadvantages that: + +         1. The space cannot be reclaimed, consolidated, and then +            used to service later requests, as happens with normal chunks. +         2. It can lead to more wastage because of mmap page alignment +            requirements +         3. It causes malloc performance to be more dependent on host +            system memory management support routines which may vary in +            implementation quality and may impose arbitrary +            limitations. Generally, servicing a request via normal +            malloc steps is faster than going through a system's mmap. + +      All together, these considerations should lead you to use mmap +      only for relatively large requests. + + +*/ + + + +#ifndef DEFAULT_MMAP_MAX +#if HAVE_MMAP +#define DEFAULT_MMAP_MAX       (64) +#else +#define DEFAULT_MMAP_MAX       (0) +#endif +#endif + +/* +    M_MMAP_MAX is the maximum number of requests to simultaneously +      service using mmap. This parameter exists because: + +         1. Some systems have a limited number of internal tables for +            use by mmap. +         2. In most systems, overreliance on mmap can degrade overall +            performance. +         3. If a program allocates many large regions, it is probably +            better off using normal sbrk-based allocation routines that +            can reclaim and reallocate normal heap memory. Using a +            small value allows transition into this mode after the +            first few allocations. + +      Setting to 0 disables all use of mmap.  If HAVE_MMAP is not set, +      the default value is 0, and attempts to set it to non-zero values +      in mallopt will fail. +*/ + + + + +/* +    USE_DL_PREFIX will prefix all public routines with the string 'dl'. +      Useful to quickly avoid procedure declaration conflicts and linker +      symbol conflicts with existing memory allocation routines. + +*/ + +/* #define USE_DL_PREFIX */ + + + + +/* + +  Special defines for linux libc + +  Except when compiled using these special defines for Linux libc +  using weak aliases, this malloc is NOT designed to work in +  multithreaded applications.  No semaphores or other concurrency +  control are provided to ensure that multiple malloc or free calls +  don't run at the same time, which could be disasterous. A single +  semaphore could be used across malloc, realloc, and free (which is +  essentially the effect of the linux weak alias approach). It would +  be hard to obtain finer granularity. + +*/ + + +#ifdef INTERNAL_LINUX_C_LIB + +#if __STD_C + +Void_t * __default_morecore_init (ptrdiff_t); +Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init; + +#else + +Void_t * __default_morecore_init (); +Void_t *(*__morecore)() = __default_morecore_init; + +#endif + +#define MORECORE (*__morecore) +#define MORECORE_FAILURE 0 +#define MORECORE_CLEARS 1 + +#else /* INTERNAL_LINUX_C_LIB */ + +#if __STD_C +extern Void_t*     sbrk(ptrdiff_t); +#else +extern Void_t*     sbrk(); +#endif + +#ifndef MORECORE +#define MORECORE sbrk +#endif + +#ifndef MORECORE_FAILURE +#define MORECORE_FAILURE -1 +#endif + +#ifndef MORECORE_CLEARS +#define MORECORE_CLEARS 1 +#endif + +#endif /* INTERNAL_LINUX_C_LIB */ + +#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__) + +#define cALLOc		__libc_calloc +#define fREe		__libc_free +#define mALLOc		__libc_malloc +#define mEMALIGn	__libc_memalign +#define rEALLOc		__libc_realloc +#define vALLOc		__libc_valloc +#define pvALLOc		__libc_pvalloc +#define mALLINFo	__libc_mallinfo +#define mALLOPt		__libc_mallopt + +#pragma weak calloc = __libc_calloc +#pragma weak free = __libc_free +#pragma weak cfree = __libc_free +#pragma weak malloc = __libc_malloc +#pragma weak memalign = __libc_memalign +#pragma weak realloc = __libc_realloc +#pragma weak valloc = __libc_valloc +#pragma weak pvalloc = __libc_pvalloc +#pragma weak mallinfo = __libc_mallinfo +#pragma weak mallopt = __libc_mallopt + +#else + +#ifdef USE_DL_PREFIX +#define cALLOc		dlcalloc +#define fREe		dlfree +#define mALLOc		dlmalloc +#define mEMALIGn	dlmemalign +#define rEALLOc		dlrealloc +#define vALLOc		dlvalloc +#define pvALLOc		dlpvalloc +#define mALLINFo	dlmallinfo +#define mALLOPt		dlmallopt +#else /* USE_DL_PREFIX */ +#define cALLOc		calloc +#define fREe		free +#define mALLOc		malloc +#define mEMALIGn	memalign +#define rEALLOc		realloc +#define vALLOc		valloc +#define pvALLOc		pvalloc +#define mALLINFo	mallinfo +#define mALLOPt		mallopt +#endif /* USE_DL_PREFIX */ + +#endif + +/* Public routines */ + +#if __STD_C + +Void_t* mALLOc(size_t); +void    fREe(Void_t*); +Void_t* rEALLOc(Void_t*, size_t); +Void_t* mEMALIGn(size_t, size_t); +Void_t* vALLOc(size_t); +Void_t* pvALLOc(size_t); +Void_t* cALLOc(size_t, size_t); +void    cfree(Void_t*); +int     malloc_trim(size_t); +size_t  malloc_usable_size(Void_t*); +void    malloc_stats(); +int     mALLOPt(int, int); +struct mallinfo mALLINFo(void); +#else +Void_t* mALLOc(); +void    fREe(); +Void_t* rEALLOc(); +Void_t* mEMALIGn(); +Void_t* vALLOc(); +Void_t* pvALLOc(); +Void_t* cALLOc(); +void    cfree(); +int     malloc_trim(); +size_t  malloc_usable_size(); +void    malloc_stats(); +int     mALLOPt(); +struct mallinfo mALLINFo(); +#endif + + +#ifdef __cplusplus +};  /* end of extern "C" */ +#endif + +/* ---------- To make a malloc.h, end cutting here ------------ */ + + +/* +  Emulation of sbrk for WIN32 +  All code within the ifdef WIN32 is untested by me. + +  Thanks to Martin Fong and others for supplying this. +*/ + + +#ifdef WIN32 + +#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \ +~(malloc_getpagesize-1)) +#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1)) + +/* resrve 64MB to insure large contiguous space */ +#define RESERVED_SIZE (1024*1024*64) +#define NEXT_SIZE (2048*1024) +#define TOP_MEMORY ((unsigned long)2*1024*1024*1024) + +struct GmListElement; +typedef struct GmListElement GmListElement; + +struct GmListElement +{ +	GmListElement* next; +	void* base; +}; + +static GmListElement* head = 0; +static unsigned int gNextAddress = 0; +static unsigned int gAddressBase = 0; +static unsigned int gAllocatedSize = 0; + +static +GmListElement* makeGmListElement (void* bas) +{ +	GmListElement* this; +	this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement)); +	assert (this); +	if (this) +	{ +		this->base = bas; +		this->next = head; +		head = this; +	} +	return this; +} + +void gcleanup () +{ +	BOOL rval; +	assert ( (head == NULL) || (head->base == (void*)gAddressBase)); +	if (gAddressBase && (gNextAddress - gAddressBase)) +	{ +		rval = VirtualFree ((void*)gAddressBase, +							gNextAddress - gAddressBase, +							MEM_DECOMMIT); +        assert (rval); +	} +	while (head) +	{ +		GmListElement* next = head->next; +		rval = VirtualFree (head->base, 0, MEM_RELEASE); +		assert (rval); +		LocalFree (head); +		head = next; +	} +} + +static +void* findRegion (void* start_address, unsigned long size) +{ +	MEMORY_BASIC_INFORMATION info; +	if (size >= TOP_MEMORY) return NULL; + +	while ((unsigned long)start_address + size < TOP_MEMORY) +	{ +		VirtualQuery (start_address, &info, sizeof (info)); +		if ((info.State == MEM_FREE) && (info.RegionSize >= size)) +			return start_address; +		else +		{ +			// Requested region is not available so see if the +			// next region is available.  Set 'start_address' +			// to the next region and call 'VirtualQuery()' +			// again. + +			start_address = (char*)info.BaseAddress + info.RegionSize; + +			// Make sure we start looking for the next region +			// on the *next* 64K boundary.  Otherwise, even if +			// the new region is free according to +			// 'VirtualQuery()', the subsequent call to +			// 'VirtualAlloc()' (which follows the call to +			// this routine in 'wsbrk()') will round *down* +			// the requested address to a 64K boundary which +			// we already know is an address in the +			// unavailable region.  Thus, the subsequent call +			// to 'VirtualAlloc()' will fail and bring us back +			// here, causing us to go into an infinite loop. + +			start_address = +				(void *) AlignPage64K((unsigned long) start_address); +		} +	} +	return NULL; + +} + + +void* wsbrk (long size) +{ +	void* tmp; +	if (size > 0) +	{ +		if (gAddressBase == 0) +		{ +			gAllocatedSize = max (RESERVED_SIZE, AlignPage (size)); +			gNextAddress = gAddressBase = +				(unsigned int)VirtualAlloc (NULL, gAllocatedSize, +											MEM_RESERVE, PAGE_NOACCESS); +		} else if (AlignPage (gNextAddress + size) > (gAddressBase + +gAllocatedSize)) +		{ +			long new_size = max (NEXT_SIZE, AlignPage (size)); +			void* new_address = (void*)(gAddressBase+gAllocatedSize); +			do +			{ +				new_address = findRegion (new_address, new_size); + +				if (new_address == 0) +					return (void*)-1; + +				gAddressBase = gNextAddress = +					(unsigned int)VirtualAlloc (new_address, new_size, +												MEM_RESERVE, PAGE_NOACCESS); +				// repeat in case of race condition +				// The region that we found has been snagged +				// by another thread +			} +			while (gAddressBase == 0); + +			assert (new_address == (void*)gAddressBase); + +			gAllocatedSize = new_size; + +			if (!makeGmListElement ((void*)gAddressBase)) +				return (void*)-1; +		} +		if ((size + gNextAddress) > AlignPage (gNextAddress)) +		{ +			void* res; +			res = VirtualAlloc ((void*)AlignPage (gNextAddress), +								(size + gNextAddress - +								 AlignPage (gNextAddress)), +								MEM_COMMIT, PAGE_READWRITE); +			if (res == 0) +				return (void*)-1; +		} +		tmp = (void*)gNextAddress; +		gNextAddress = (unsigned int)tmp + size; +		return tmp; +	} +	else if (size < 0) +	{ +		unsigned int alignedGoal = AlignPage (gNextAddress + size); +		/* Trim by releasing the virtual memory */ +		if (alignedGoal >= gAddressBase) +		{ +			VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal, +						 MEM_DECOMMIT); +			gNextAddress = gNextAddress + size; +			return (void*)gNextAddress; +		} +		else +		{ +			VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase, +						 MEM_DECOMMIT); +			gNextAddress = gAddressBase; +			return (void*)-1; +		} +	} +	else +	{ +		return (void*)gNextAddress; +	} +} + +#endif + + + +/* +  Type declarations +*/ + + +struct malloc_chunk +{ +  INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ +  INTERNAL_SIZE_T size;      /* Size in bytes, including overhead. */ +  struct malloc_chunk* fd;   /* double links -- used only if free. */ +  struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk* mchunkptr; + +/* + +   malloc_chunk details: + +    (The following includes lightly edited explanations by Colin Plumb.) + +    Chunks of memory are maintained using a `boundary tag' method as +    described in e.g., Knuth or Standish.  (See the paper by Paul +    Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a +    survey of such techniques.)  Sizes of free chunks are stored both +    in the front of each chunk and at the end.  This makes +    consolidating fragmented chunks into bigger chunks very fast.  The +    size fields also hold bits representing whether chunks are free or +    in use. + +    An allocated chunk looks like this: + + +    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             Size of previous chunk, if allocated            | | +            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             Size of chunk, in bytes                         |P| +      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             User data starts here...                          . +            .                                                               . +            .             (malloc_usable_space() bytes)                     . +            .                                                               | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             Size of chunk                                     | +            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +    Where "chunk" is the front of the chunk for the purpose of most of +    the malloc code, but "mem" is the pointer that is returned to the +    user.  "Nextchunk" is the beginning of the next contiguous chunk. + +    Chunks always begin on even word boundries, so the mem portion +    (which is returned to the user) is also on an even word boundary, and +    thus double-word aligned. + +    Free chunks are stored in circular doubly-linked lists, and look like this: + +    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             Size of previous chunk                            | +            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +    `head:' |             Size of chunk, in bytes                         |P| +      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             Forward pointer to next chunk in list             | +            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             Back pointer to previous chunk in list            | +            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +            |             Unused space (may be 0 bytes long)                . +            .                                                               . +            .                                                               | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +    `foot:' |             Size of chunk, in bytes                           | +            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +    The P (PREV_INUSE) bit, stored in the unused low-order bit of the +    chunk size (which is always a multiple of two words), is an in-use +    bit for the *previous* chunk.  If that bit is *clear*, then the +    word before the current chunk size contains the previous chunk +    size, and can be used to find the front of the previous chunk. +    (The very first chunk allocated always has this bit set, +    preventing access to non-existent (or non-owned) memory.) + +    Note that the `foot' of the current chunk is actually represented +    as the prev_size of the NEXT chunk. (This makes it easier to +    deal with alignments etc). + +    The two exceptions to all this are + +     1. The special chunk `top', which doesn't bother using the +        trailing size field since there is no +        next contiguous chunk that would have to index off it. (After +        initialization, `top' is forced to always exist.  If it would +        become less than MINSIZE bytes long, it is replenished via +        malloc_extend_top.) + +     2. Chunks allocated via mmap, which have the second-lowest-order +        bit (IS_MMAPPED) set in their size fields.  Because they are +        never merged or traversed from any other chunk, they have no +        foot size or inuse information. + +    Available chunks are kept in any of several places (all declared below): + +    * `av': An array of chunks serving as bin headers for consolidated +       chunks. Each bin is doubly linked.  The bins are approximately +       proportionally (log) spaced.  There are a lot of these bins +       (128). This may look excessive, but works very well in +       practice.  All procedures maintain the invariant that no +       consolidated chunk physically borders another one. Chunks in +       bins are kept in size order, with ties going to the +       approximately least recently used chunk. + +       The chunks in each bin are maintained in decreasing sorted order by +       size.  This is irrelevant for the small bins, which all contain +       the same-sized chunks, but facilitates best-fit allocation for +       larger chunks. (These lists are just sequential. Keeping them in +       order almost never requires enough traversal to warrant using +       fancier ordered data structures.)  Chunks of the same size are +       linked with the most recently freed at the front, and allocations +       are taken from the back.  This results in LRU or FIFO allocation +       order, which tends to give each chunk an equal opportunity to be +       consolidated with adjacent freed chunks, resulting in larger free +       chunks and less fragmentation. + +    * `top': The top-most available chunk (i.e., the one bordering the +       end of available memory) is treated specially. It is never +       included in any bin, is used only if no other chunk is +       available, and is released back to the system if it is very +       large (see M_TRIM_THRESHOLD). + +    * `last_remainder': A bin holding only the remainder of the +       most recently split (non-top) chunk. This bin is checked +       before other non-fitting chunks, so as to provide better +       locality for runs of sequentially allocated chunks. + +    *  Implicitly, through the host system's memory mapping tables. +       If supported, requests greater than a threshold are usually +       serviced via calls to mmap, and then later released via munmap. + +*/ + + + + + + +/*  sizes, alignments */ + +#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T)) +#define MALLOC_ALIGNMENT       (SIZE_SZ + SIZE_SZ) +#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1) +#define MINSIZE                (sizeof(struct malloc_chunk)) + +/* conversion from malloc headers to user pointers, and back */ + +#define chunk2mem(p)   ((Void_t*)((char*)(p) + 2*SIZE_SZ)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) + +/* pad request bytes into a usable size */ + +#define request2size(req) \ + (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \ +  (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \ +   (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK))) + +/* Check if m has acceptable alignment */ + +#define aligned_OK(m)    (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) + + + + +/* +  Physical chunk operations +*/ + + +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ + +#define PREV_INUSE 0x1 + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ + +#define IS_MMAPPED 0x2 + +/* Bits to mask off when extracting size */ + +#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) + + +/* Ptr to next physical malloc_chunk. */ + +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) + +/* Ptr to previous physical malloc_chunk */ + +#define prev_chunk(p)\ +   ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) + + +/* Treat space at ptr + offset as a chunk */ + +#define chunk_at_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s))) + + + + +/* +  Dealing with use bits +*/ + +/* extract p's inuse bit */ + +#define inuse(p)\ +((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) + +/* extract inuse bit of previous chunk */ + +#define prev_inuse(p)  ((p)->size & PREV_INUSE) + +/* check for mmap()'ed chunk */ + +#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) + +/* set/clear chunk as in use without otherwise disturbing */ + +#define set_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE + +#define clear_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) + +/* check/set/clear inuse bits in known places */ + +#define inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) + +#define set_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) + +#define clear_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) + + + + +/* +  Dealing with size fields +*/ + +/* Get size, ignoring use bits */ + +#define chunksize(p)          ((p)->size & ~(SIZE_BITS)) + +/* Set size at head, without disturbing its use bit */ + +#define set_head_size(p, s)   ((p)->size = (((p)->size & PREV_INUSE) | (s))) + +/* Set size/use ignoring previous bits in header */ + +#define set_head(p, s)        ((p)->size = (s)) + +/* Set size at footer (only when chunk is not in use) */ + +#define set_foot(p, s)   (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) + + + + + +/* +   Bins + +    The bins, `av_' are an array of pairs of pointers serving as the +    heads of (initially empty) doubly-linked lists of chunks, laid out +    in a way so that each pair can be treated as if it were in a +    malloc_chunk. (This way, the fd/bk offsets for linking bin heads +    and chunks are the same). + +    Bins for sizes < 512 bytes contain chunks of all the same size, spaced +    8 bytes apart. Larger bins are approximately logarithmically +    spaced. (See the table below.) The `av_' array is never mentioned +    directly in the code, but instead via bin access macros. + +    Bin layout: + +    64 bins of size       8 +    32 bins of size      64 +    16 bins of size     512 +     8 bins of size    4096 +     4 bins of size   32768 +     2 bins of size  262144 +     1 bin  of size what's left + +    There is actually a little bit of slop in the numbers in bin_index +    for the sake of speed. This makes no difference elsewhere. + +    The special chunks `top' and `last_remainder' get their own bins, +    (this is implemented via yet more trickery with the av_ array), +    although `top' is never properly linked to its bin since it is +    always handled specially. + +*/ + +#define NAV             128   /* number of bins */ + +typedef struct malloc_chunk* mbinptr; + +/* access macros */ + +#define bin_at(i)      ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ)) +#define next_bin(b)    ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr))) +#define prev_bin(b)    ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr))) + +/* +   The first 2 bins are never indexed. The corresponding av_ cells are instead +   used for bookkeeping. This is not to save space, but to simplify +   indexing, maintain locality, and avoid some initialization tests. +*/ + +#define top            (bin_at(0)->fd)   /* The topmost chunk */ +#define last_remainder (bin_at(1))       /* remainder from last split */ + + +/* +   Because top initially points to its own bin with initial +   zero size, thus forcing extension on the first malloc request, +   we avoid having any special code in malloc to check whether +   it even exists yet. But we still need to in malloc_extend_top. +*/ + +#define initial_top    ((mchunkptr)(bin_at(0))) + +/* Helper macro to initialize bins */ + +#define IAV(i)  bin_at(i), bin_at(i) + +static mbinptr av_[NAV * 2 + 2] = { + 0, 0, + IAV(0),   IAV(1),   IAV(2),   IAV(3),   IAV(4),   IAV(5),   IAV(6),   IAV(7), + IAV(8),   IAV(9),   IAV(10),  IAV(11),  IAV(12),  IAV(13),  IAV(14),  IAV(15), + IAV(16),  IAV(17),  IAV(18),  IAV(19),  IAV(20),  IAV(21),  IAV(22),  IAV(23), + IAV(24),  IAV(25),  IAV(26),  IAV(27),  IAV(28),  IAV(29),  IAV(30),  IAV(31), + IAV(32),  IAV(33),  IAV(34),  IAV(35),  IAV(36),  IAV(37),  IAV(38),  IAV(39), + IAV(40),  IAV(41),  IAV(42),  IAV(43),  IAV(44),  IAV(45),  IAV(46),  IAV(47), + IAV(48),  IAV(49),  IAV(50),  IAV(51),  IAV(52),  IAV(53),  IAV(54),  IAV(55), + IAV(56),  IAV(57),  IAV(58),  IAV(59),  IAV(60),  IAV(61),  IAV(62),  IAV(63), + IAV(64),  IAV(65),  IAV(66),  IAV(67),  IAV(68),  IAV(69),  IAV(70),  IAV(71), + IAV(72),  IAV(73),  IAV(74),  IAV(75),  IAV(76),  IAV(77),  IAV(78),  IAV(79), + IAV(80),  IAV(81),  IAV(82),  IAV(83),  IAV(84),  IAV(85),  IAV(86),  IAV(87), + IAV(88),  IAV(89),  IAV(90),  IAV(91),  IAV(92),  IAV(93),  IAV(94),  IAV(95), + IAV(96),  IAV(97),  IAV(98),  IAV(99),  IAV(100), IAV(101), IAV(102), IAV(103), + IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), + IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), + IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +}; + + + +/* field-extraction macros */ + +#define first(b) ((b)->fd) +#define last(b)  ((b)->bk) + +/* +  Indexing into bins +*/ + +#define bin_index(sz)                                                          \ +(((((unsigned long)(sz)) >> 9) ==    0) ?       (((unsigned long)(sz)) >>  3): \ + ((((unsigned long)(sz)) >> 9) <=    4) ?  56 + (((unsigned long)(sz)) >>  6): \ + ((((unsigned long)(sz)) >> 9) <=   20) ?  91 + (((unsigned long)(sz)) >>  9): \ + ((((unsigned long)(sz)) >> 9) <=   84) ? 110 + (((unsigned long)(sz)) >> 12): \ + ((((unsigned long)(sz)) >> 9) <=  340) ? 119 + (((unsigned long)(sz)) >> 15): \ + ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \ +                                          126) +/* +  bins for chunks < 512 are all spaced 8 bytes apart, and hold +  identically sized chunks. This is exploited in malloc. +*/ + +#define MAX_SMALLBIN         63 +#define MAX_SMALLBIN_SIZE   512 +#define SMALLBIN_WIDTH        8 + +#define smallbin_index(sz)  (((unsigned long)(sz)) >> 3) + +/* +   Requests are `small' if both the corresponding and the next bin are small +*/ + +#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH) + + + +/* +    To help compensate for the large number of bins, a one-level index +    structure is used for bin-by-bin searching.  `binblocks' is a +    one-word bitvector recording whether groups of BINBLOCKWIDTH bins +    have any (possibly) non-empty bins, so they can be skipped over +    all at once during during traversals. The bits are NOT always +    cleared as soon as all bins in a block are empty, but instead only +    when all are noticed to be empty during traversal in malloc. +*/ + +#define BINBLOCKWIDTH     4   /* bins per block */ + +#define binblocks      (bin_at(0)->size) /* bitvector of nonempty blocks */ + +/* bin<->block macros */ + +#define idx2binblock(ix)    ((unsigned)1 << (ix / BINBLOCKWIDTH)) +#define mark_binblock(ii)   (binblocks |= idx2binblock(ii)) +#define clear_binblock(ii)  (binblocks &= ~(idx2binblock(ii))) + + + + + +/*  Other static bookkeeping data */ + +/* variables holding tunable values */ + +static unsigned long trim_threshold   = DEFAULT_TRIM_THRESHOLD; +static unsigned long top_pad          = DEFAULT_TOP_PAD; +static unsigned int  n_mmaps_max      = DEFAULT_MMAP_MAX; +static unsigned long mmap_threshold   = DEFAULT_MMAP_THRESHOLD; + +/* The first value returned from sbrk */ +static char* sbrk_base = (char*)(-1); + +/* The maximum memory obtained from system via sbrk */ +static unsigned long max_sbrked_mem = 0; + +/* The maximum via either sbrk or mmap */ +static unsigned long max_total_mem = 0; + +/* internal working copy of mallinfo */ +static struct mallinfo current_mallinfo = {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* The total memory obtained from system via sbrk */ +#define sbrked_mem  (current_mallinfo.arena) + +/* Tracking mmaps */ + +static unsigned int n_mmaps = 0; +static unsigned int max_n_mmaps = 0; +static unsigned long mmapped_mem = 0; +static unsigned long max_mmapped_mem = 0; + + + +/* +  Debugging support +*/ + +#if DEBUG + + +/* +  These routines make a number of assertions about the states +  of data structures that should be true at all times. If any +  are not true, it's very likely that a user program has somehow +  trashed memory. (It's also possible that there is a coding error +  in malloc. In which case, please report it!) +*/ + +#if __STD_C +static void do_check_chunk(mchunkptr p) +#else +static void do_check_chunk(p) mchunkptr p; +#endif +{ +  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + +  /* No checkable chunk is mmapped */ +  assert(!chunk_is_mmapped(p)); + +  /* Check for legal address ... */ +  assert((char*)p >= sbrk_base); +  if (p != top) +    assert((char*)p + sz <= (char*)top); +  else +    assert((char*)p + sz <= sbrk_base + sbrked_mem); + +} + + +#if __STD_C +static void do_check_free_chunk(mchunkptr p) +#else +static void do_check_free_chunk(p) mchunkptr p; +#endif +{ +  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; +  mchunkptr next = chunk_at_offset(p, sz); + +  do_check_chunk(p); + +  /* Check whether it claims to be free ... */ +  assert(!inuse(p)); + +  /* Unless a special marker, must have OK fields */ +  if ((long)sz >= (long)MINSIZE) +  { +    assert((sz & MALLOC_ALIGN_MASK) == 0); +    assert(aligned_OK(chunk2mem(p))); +    /* ... matching footer field */ +    assert(next->prev_size == sz); +    /* ... and is fully consolidated */ +    assert(prev_inuse(p)); +    assert (next == top || inuse(next)); + +    /* ... and has minimally sane links */ +    assert(p->fd->bk == p); +    assert(p->bk->fd == p); +  } +  else /* markers are always of size SIZE_SZ */ +    assert(sz == SIZE_SZ); +} + +#if __STD_C +static void do_check_inuse_chunk(mchunkptr p) +#else +static void do_check_inuse_chunk(p) mchunkptr p; +#endif +{ +  mchunkptr next = next_chunk(p); +  do_check_chunk(p); + +  /* Check whether it claims to be in use ... */ +  assert(inuse(p)); + +  /* ... and is surrounded by OK chunks. +    Since more things can be checked with free chunks than inuse ones, +    if an inuse chunk borders them and debug is on, it's worth doing them. +  */ +  if (!prev_inuse(p)) +  { +    mchunkptr prv = prev_chunk(p); +    assert(next_chunk(prv) == p); +    do_check_free_chunk(prv); +  } +  if (next == top) +  { +    assert(prev_inuse(next)); +    assert(chunksize(next) >= MINSIZE); +  } +  else if (!inuse(next)) +    do_check_free_chunk(next); + +} + +#if __STD_C +static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ +  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; +  long room = sz - s; + +  do_check_inuse_chunk(p); + +  /* Legal size ... */ +  assert((long)sz >= (long)MINSIZE); +  assert((sz & MALLOC_ALIGN_MASK) == 0); +  assert(room >= 0); +  assert(room < (long)MINSIZE); + +  /* ... and alignment */ +  assert(aligned_OK(chunk2mem(p))); + + +  /* ... and was allocated at front of an available chunk */ +  assert(prev_inuse(p)); + +} + + +#define check_free_chunk(P)  do_check_free_chunk(P) +#define check_inuse_chunk(P) do_check_inuse_chunk(P) +#define check_chunk(P) do_check_chunk(P) +#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) +#else +#define check_free_chunk(P) +#define check_inuse_chunk(P) +#define check_chunk(P) +#define check_malloced_chunk(P,N) +#endif + + + +/* +  Macro-based internal utilities +*/ + + +/* +  Linking chunks in bin lists. +  Call these only with variables, not arbitrary expressions, as arguments. +*/ + +/* +  Place chunk p of size s in its bin, in size order, +  putting it ahead of others of same size. +*/ + + +#define frontlink(P, S, IDX, BK, FD)                                          \ +{                                                                             \ +  if (S < MAX_SMALLBIN_SIZE)                                                  \ +  {                                                                           \ +    IDX = smallbin_index(S);                                                  \ +    mark_binblock(IDX);                                                       \ +    BK = bin_at(IDX);                                                         \ +    FD = BK->fd;                                                              \ +    P->bk = BK;                                                               \ +    P->fd = FD;                                                               \ +    FD->bk = BK->fd = P;                                                      \ +  }                                                                           \ +  else                                                                        \ +  {                                                                           \ +    IDX = bin_index(S);                                                       \ +    BK = bin_at(IDX);                                                         \ +    FD = BK->fd;                                                              \ +    if (FD == BK) mark_binblock(IDX);                                         \ +    else                                                                      \ +    {                                                                         \ +      while (FD != BK && S < chunksize(FD)) FD = FD->fd;                      \ +      BK = FD->bk;                                                            \ +    }                                                                         \ +    P->bk = BK;                                                               \ +    P->fd = FD;                                                               \ +    FD->bk = BK->fd = P;                                                      \ +  }                                                                           \ +} + + +/* take a chunk off a list */ + +#define unlink(P, BK, FD)                                                     \ +{                                                                             \ +  BK = P->bk;                                                                 \ +  FD = P->fd;                                                                 \ +  FD->bk = BK;                                                                \ +  BK->fd = FD;                                                                \ +}                                                                             \ + +/* Place p as the last remainder */ + +#define link_last_remainder(P)                                                \ +{                                                                             \ +  last_remainder->fd = last_remainder->bk =  P;                               \ +  P->fd = P->bk = last_remainder;                                             \ +} + +/* Clear the last_remainder bin */ + +#define clear_last_remainder \ +  (last_remainder->fd = last_remainder->bk = last_remainder) + + + + + + +/* Routines dealing with mmap(). */ + +#if HAVE_MMAP + +#if __STD_C +static mchunkptr mmap_chunk(size_t size) +#else +static mchunkptr mmap_chunk(size) size_t size; +#endif +{ +  size_t page_mask = malloc_getpagesize - 1; +  mchunkptr p; + +#ifndef MAP_ANONYMOUS +  static int fd = -1; +#endif + +  if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */ + +  /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because +   * there is no following chunk whose prev_size field could be used. +   */ +  size = (size + SIZE_SZ + page_mask) & ~page_mask; + +#ifdef MAP_ANONYMOUS +  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, +		      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +#else /* !MAP_ANONYMOUS */ +  if (fd < 0) +  { +    fd = open("/dev/zero", O_RDWR); +    if(fd < 0) return 0; +  } +  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); +#endif + +  if(p == (mchunkptr)-1) return 0; + +  n_mmaps++; +  if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps; + +  /* We demand that eight bytes into a page must be 8-byte aligned. */ +  assert(aligned_OK(chunk2mem(p))); + +  /* The offset to the start of the mmapped region is stored +   * in the prev_size field of the chunk; normally it is zero, +   * but that can be changed in memalign(). +   */ +  p->prev_size = 0; +  set_head(p, size|IS_MMAPPED); + +  mmapped_mem += size; +  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) +    max_mmapped_mem = mmapped_mem; +  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) +    max_total_mem = mmapped_mem + sbrked_mem; +  return p; +} + +#if __STD_C +static void munmap_chunk(mchunkptr p) +#else +static void munmap_chunk(p) mchunkptr p; +#endif +{ +  INTERNAL_SIZE_T size = chunksize(p); +  int ret; + +  assert (chunk_is_mmapped(p)); +  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); +  assert((n_mmaps > 0)); +  assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0); + +  n_mmaps--; +  mmapped_mem -= (size + p->prev_size); + +  ret = munmap((char *)p - p->prev_size, size + p->prev_size); + +  /* munmap returns non-zero on failure */ +  assert(ret == 0); +} + +#if HAVE_MREMAP + +#if __STD_C +static mchunkptr mremap_chunk(mchunkptr p, size_t new_size) +#else +static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size; +#endif +{ +  size_t page_mask = malloc_getpagesize - 1; +  INTERNAL_SIZE_T offset = p->prev_size; +  INTERNAL_SIZE_T size = chunksize(p); +  char *cp; + +  assert (chunk_is_mmapped(p)); +  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); +  assert((n_mmaps > 0)); +  assert(((size + offset) & (malloc_getpagesize-1)) == 0); + +  /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */ +  new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask; + +  cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1); + +  if (cp == (char *)-1) return 0; + +  p = (mchunkptr)(cp + offset); + +  assert(aligned_OK(chunk2mem(p))); + +  assert((p->prev_size == offset)); +  set_head(p, (new_size - offset)|IS_MMAPPED); + +  mmapped_mem -= size + offset; +  mmapped_mem += new_size; +  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) +    max_mmapped_mem = mmapped_mem; +  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) +    max_total_mem = mmapped_mem + sbrked_mem; +  return p; +} + +#endif /* HAVE_MREMAP */ + +#endif /* HAVE_MMAP */ + + + + +/* +  Extend the top-most chunk by obtaining memory from system. +  Main interface to sbrk (but see also malloc_trim). +*/ + +#if __STD_C +static void malloc_extend_top(INTERNAL_SIZE_T nb) +#else +static void malloc_extend_top(nb) INTERNAL_SIZE_T nb; +#endif +{ +  char*     brk;                  /* return value from sbrk */ +  INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */ +  INTERNAL_SIZE_T correction;     /* bytes for 2nd sbrk call */ +  char*     new_brk;              /* return of 2nd sbrk call */ +  INTERNAL_SIZE_T top_size;       /* new size of top chunk */ + +  mchunkptr old_top     = top;  /* Record state of old top */ +  INTERNAL_SIZE_T old_top_size = chunksize(old_top); +  char*     old_end      = (char*)(chunk_at_offset(old_top, old_top_size)); + +  /* Pad request with top_pad plus minimal overhead */ + +  INTERNAL_SIZE_T    sbrk_size     = nb + top_pad + MINSIZE; +  unsigned long pagesz    = malloc_getpagesize; + +  /* If not the first time through, round to preserve page boundary */ +  /* Otherwise, we need to correct to a page size below anyway. */ +  /* (We also correct below if an intervening foreign sbrk call.) */ + +  if (sbrk_base != (char*)(-1)) +    sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1); + +  brk = (char*)(MORECORE (sbrk_size)); + +  /* Fail if sbrk failed or if a foreign sbrk call killed our space */ +  if (brk == (char*)(MORECORE_FAILURE) || +      (brk < old_end && old_top != initial_top)) +    return; + +  sbrked_mem += sbrk_size; + +  if (brk == old_end) /* can just add bytes to current top */ +  { +    top_size = sbrk_size + old_top_size; +    set_head(top, top_size | PREV_INUSE); +  } +  else +  { +    if (sbrk_base == (char*)(-1))  /* First time through. Record base */ +      sbrk_base = brk; +    else  /* Someone else called sbrk().  Count those bytes as sbrked_mem. */ +      sbrked_mem += brk - (char*)old_end; + +    /* Guarantee alignment of first new chunk made from this space */ +    front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK; +    if (front_misalign > 0) +    { +      correction = (MALLOC_ALIGNMENT) - front_misalign; +      brk += correction; +    } +    else +      correction = 0; + +    /* Guarantee the next brk will be at a page boundary */ + +    correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) & +                   ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size)); + +    /* Allocate correction */ +    new_brk = (char*)(MORECORE (correction)); +    if (new_brk == (char*)(MORECORE_FAILURE)) return; + +    sbrked_mem += correction; + +    top = (mchunkptr)brk; +    top_size = new_brk - brk + correction; +    set_head(top, top_size | PREV_INUSE); + +    if (old_top != initial_top) +    { + +      /* There must have been an intervening foreign sbrk call. */ +      /* A double fencepost is necessary to prevent consolidation */ + +      /* If not enough space to do this, then user did something very wrong */ +      if (old_top_size < MINSIZE) +      { +        set_head(top, PREV_INUSE); /* will force null return from malloc */ +        return; +      } + +      /* Also keep size a multiple of MALLOC_ALIGNMENT */ +      old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; +      set_head_size(old_top, old_top_size); +      chunk_at_offset(old_top, old_top_size          )->size = +        SIZE_SZ|PREV_INUSE; +      chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size = +        SIZE_SZ|PREV_INUSE; +      /* If possible, release the rest. */ +      if (old_top_size >= MINSIZE) +        fREe(chunk2mem(old_top)); +    } +  } + +  if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem) +    max_sbrked_mem = sbrked_mem; +  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) +    max_total_mem = mmapped_mem + sbrked_mem; + +  /* We always land on a page boundary */ +  assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0); +} + + + + +/* Main public routines */ + + +/* +  Malloc Algorthim: + +    The requested size is first converted into a usable form, `nb'. +    This currently means to add 4 bytes overhead plus possibly more to +    obtain 8-byte alignment and/or to obtain a size of at least +    MINSIZE (currently 16 bytes), the smallest allocatable size. +    (All fits are considered `exact' if they are within MINSIZE bytes.) + +    From there, the first successful of the following steps is taken: + +      1. The bin corresponding to the request size is scanned, and if +         a chunk of exactly the right size is found, it is taken. + +      2. The most recently remaindered chunk is used if it is big +         enough.  This is a form of (roving) first fit, used only in +         the absence of exact fits. Runs of consecutive requests use +         the remainder of the chunk used for the previous such request +         whenever possible. This limited use of a first-fit style +         allocation strategy tends to give contiguous chunks +         coextensive lifetimes, which improves locality and can reduce +         fragmentation in the long run. + +      3. Other bins are scanned in increasing size order, using a +         chunk big enough to fulfill the request, and splitting off +         any remainder.  This search is strictly by best-fit; i.e., +         the smallest (with ties going to approximately the least +         recently used) chunk that fits is selected. + +      4. If large enough, the chunk bordering the end of memory +         (`top') is split off. (This use of `top' is in accord with +         the best-fit search rule.  In effect, `top' is treated as +         larger (and thus less well fitting) than any other available +         chunk since it can be extended to be as large as necessary +         (up to system limitations). + +      5. If the request size meets the mmap threshold and the +         system supports mmap, and there are few enough currently +         allocated mmapped regions, and a call to mmap succeeds, +         the request is allocated via direct memory mapping. + +      6. Otherwise, the top of memory is extended by +         obtaining more space from the system (normally using sbrk, +         but definable to anything else via the MORECORE macro). +         Memory is gathered from the system (in system page-sized +         units) in a way that allows chunks obtained across different +         sbrk calls to be consolidated, but does not require +         contiguous memory. Thus, it should be safe to intersperse +         mallocs with other sbrk calls. + + +      All allocations are made from the the `lowest' part of any found +      chunk. (The implementation invariant is that prev_inuse is +      always true of any allocated chunk; i.e., that each allocated +      chunk borders either a previously allocated and still in-use chunk, +      or the base of its memory arena.) + +*/ + +#if __STD_C +Void_t* mALLOc(size_t bytes) +#else +Void_t* mALLOc(bytes) size_t bytes; +#endif +{ +  mchunkptr victim;                  /* inspected/selected chunk */ +  INTERNAL_SIZE_T victim_size;       /* its size */ +  int       idx;                     /* index for bin traversal */ +  mbinptr   bin;                     /* associated bin */ +  mchunkptr remainder;               /* remainder from a split */ +  long      remainder_size;          /* its size */ +  int       remainder_index;         /* its bin index */ +  unsigned long block;               /* block traverser bit */ +  int       startidx;                /* first bin of a traversed block */ +  mchunkptr fwd;                     /* misc temp for linking */ +  mchunkptr bck;                     /* misc temp for linking */ +  mbinptr q;                         /* misc temp */ + +  INTERNAL_SIZE_T nb; + +  if ((long)bytes < 0) return 0; + +  nb = request2size(bytes);  /* padded request size; */ + +  /* Check for exact match in a bin */ + +  if (is_small_request(nb))  /* Faster version for small requests */ +  { +    idx = smallbin_index(nb); + +    /* No traversal or size check necessary for small bins.  */ + +    q = bin_at(idx); +    victim = last(q); + +    /* Also scan the next one, since it would have a remainder < MINSIZE */ +    if (victim == q) +    { +      q = next_bin(q); +      victim = last(q); +    } +    if (victim != q) +    { +      victim_size = chunksize(victim); +      unlink(victim, bck, fwd); +      set_inuse_bit_at_offset(victim, victim_size); +      check_malloced_chunk(victim, nb); +      return chunk2mem(victim); +    } + +    idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */ + +  } +  else +  { +    idx = bin_index(nb); +    bin = bin_at(idx); + +    for (victim = last(bin); victim != bin; victim = victim->bk) +    { +      victim_size = chunksize(victim); +      remainder_size = victim_size - nb; + +      if (remainder_size >= (long)MINSIZE) /* too big */ +      { +        --idx; /* adjust to rescan below after checking last remainder */ +        break; +      } + +      else if (remainder_size >= 0) /* exact fit */ +      { +        unlink(victim, bck, fwd); +        set_inuse_bit_at_offset(victim, victim_size); +        check_malloced_chunk(victim, nb); +        return chunk2mem(victim); +      } +    } + +    ++idx; + +  } + +  /* Try to use the last split-off remainder */ + +  if ( (victim = last_remainder->fd) != last_remainder) +  { +    victim_size = chunksize(victim); +    remainder_size = victim_size - nb; + +    if (remainder_size >= (long)MINSIZE) /* re-split */ +    { +      remainder = chunk_at_offset(victim, nb); +      set_head(victim, nb | PREV_INUSE); +      link_last_remainder(remainder); +      set_head(remainder, remainder_size | PREV_INUSE); +      set_foot(remainder, remainder_size); +      check_malloced_chunk(victim, nb); +      return chunk2mem(victim); +    } + +    clear_last_remainder; + +    if (remainder_size >= 0)  /* exhaust */ +    { +      set_inuse_bit_at_offset(victim, victim_size); +      check_malloced_chunk(victim, nb); +      return chunk2mem(victim); +    } + +    /* Else place in bin */ + +    frontlink(victim, victim_size, remainder_index, bck, fwd); +  } + +  /* +     If there are any possibly nonempty big-enough blocks, +     search for best fitting chunk by scanning bins in blockwidth units. +  */ + +  if ( (block = idx2binblock(idx)) <= binblocks) +  { + +    /* Get to the first marked block */ + +    if ( (block & binblocks) == 0) +    { +      /* force to an even block boundary */ +      idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH; +      block <<= 1; +      while ((block & binblocks) == 0) +      { +        idx += BINBLOCKWIDTH; +        block <<= 1; +      } +    } + +    /* For each possibly nonempty block ... */ +    for (;;) +    { +      startidx = idx;          /* (track incomplete blocks) */ +      q = bin = bin_at(idx); + +      /* For each bin in this block ... */ +      do +      { +        /* Find and use first big enough chunk ... */ + +        for (victim = last(bin); victim != bin; victim = victim->bk) +        { +          victim_size = chunksize(victim); +          remainder_size = victim_size - nb; + +          if (remainder_size >= (long)MINSIZE) /* split */ +          { +            remainder = chunk_at_offset(victim, nb); +            set_head(victim, nb | PREV_INUSE); +            unlink(victim, bck, fwd); +            link_last_remainder(remainder); +            set_head(remainder, remainder_size | PREV_INUSE); +            set_foot(remainder, remainder_size); +            check_malloced_chunk(victim, nb); +            return chunk2mem(victim); +          } + +          else if (remainder_size >= 0)  /* take */ +          { +            set_inuse_bit_at_offset(victim, victim_size); +            unlink(victim, bck, fwd); +            check_malloced_chunk(victim, nb); +            return chunk2mem(victim); +          } + +        } + +       bin = next_bin(bin); + +      } while ((++idx & (BINBLOCKWIDTH - 1)) != 0); + +      /* Clear out the block bit. */ + +      do   /* Possibly backtrack to try to clear a partial block */ +      { +        if ((startidx & (BINBLOCKWIDTH - 1)) == 0) +        { +          binblocks &= ~block; +          break; +        } +        --startidx; +       q = prev_bin(q); +      } while (first(q) == q); + +      /* Get to the next possibly nonempty block */ + +      if ( (block <<= 1) <= binblocks && (block != 0) ) +      { +        while ((block & binblocks) == 0) +        { +          idx += BINBLOCKWIDTH; +          block <<= 1; +        } +      } +      else +        break; +    } +  } + + +  /* Try to use top chunk */ + +  /* Require that there be a remainder, ensuring top always exists  */ +  if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) +  { + +#if HAVE_MMAP +    /* If big and would otherwise need to extend, try to use mmap instead */ +    if ((unsigned long)nb >= (unsigned long)mmap_threshold && +        (victim = mmap_chunk(nb)) != 0) +      return chunk2mem(victim); +#endif + +    /* Try to extend */ +    malloc_extend_top(nb); +    if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) +      return 0; /* propagate failure */ +  } + +  victim = top; +  set_head(victim, nb | PREV_INUSE); +  top = chunk_at_offset(victim, nb); +  set_head(top, remainder_size | PREV_INUSE); +  check_malloced_chunk(victim, nb); +  return chunk2mem(victim); + +} + + + + +/* + +  free() algorithm : + +    cases: + +       1. free(0) has no effect. + +       2. If the chunk was allocated via mmap, it is release via munmap(). + +       3. If a returned chunk borders the current high end of memory, +          it is consolidated into the top, and if the total unused +          topmost memory exceeds the trim threshold, malloc_trim is +          called. + +       4. Other chunks are consolidated as they arrive, and +          placed in corresponding bins. (This includes the case of +          consolidating with the current `last_remainder'). + +*/ + + +#if __STD_C +void fREe(Void_t* mem) +#else +void fREe(mem) Void_t* mem; +#endif +{ +  mchunkptr p;         /* chunk corresponding to mem */ +  INTERNAL_SIZE_T hd;  /* its head field */ +  INTERNAL_SIZE_T sz;  /* its size */ +  int       idx;       /* its bin index */ +  mchunkptr next;      /* next contiguous chunk */ +  INTERNAL_SIZE_T nextsz; /* its size */ +  INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */ +  mchunkptr bck;       /* misc temp for linking */ +  mchunkptr fwd;       /* misc temp for linking */ +  int       islr;      /* track whether merging with last_remainder */ + +  if (mem == 0)                              /* free(0) has no effect */ +    return; + +  p = mem2chunk(mem); +  hd = p->size; + +#if HAVE_MMAP +  if (hd & IS_MMAPPED)                       /* release mmapped memory. */ +  { +    munmap_chunk(p); +    return; +  } +#endif + +  check_inuse_chunk(p); + +  sz = hd & ~PREV_INUSE; +  next = chunk_at_offset(p, sz); +  nextsz = chunksize(next); + +  if (next == top)                            /* merge with top */ +  { +    sz += nextsz; + +    if (!(hd & PREV_INUSE))                    /* consolidate backward */ +    { +      prevsz = p->prev_size; +      p = chunk_at_offset(p, -((long) prevsz)); +      sz += prevsz; +      unlink(p, bck, fwd); +    } + +    set_head(p, sz | PREV_INUSE); +    top = p; +    if ((unsigned long)(sz) >= (unsigned long)trim_threshold) +      malloc_trim(top_pad); +    return; +  } + +  set_head(next, nextsz);                    /* clear inuse bit */ + +  islr = 0; + +  if (!(hd & PREV_INUSE))                    /* consolidate backward */ +  { +    prevsz = p->prev_size; +    p = chunk_at_offset(p, -((long) prevsz)); +    sz += prevsz; + +    if (p->fd == last_remainder)             /* keep as last_remainder */ +      islr = 1; +    else +      unlink(p, bck, fwd); +  } + +  if (!(inuse_bit_at_offset(next, nextsz)))   /* consolidate forward */ +  { +    sz += nextsz; + +    if (!islr && next->fd == last_remainder)  /* re-insert last_remainder */ +    { +      islr = 1; +      link_last_remainder(p); +    } +    else +      unlink(next, bck, fwd); +  } + + +  set_head(p, sz | PREV_INUSE); +  set_foot(p, sz); +  if (!islr) +    frontlink(p, sz, idx, bck, fwd); +} + + + + + +/* + +  Realloc algorithm: + +    Chunks that were obtained via mmap cannot be extended or shrunk +    unless HAVE_MREMAP is defined, in which case mremap is used. +    Otherwise, if their reallocation is for additional space, they are +    copied.  If for less, they are just left alone. + +    Otherwise, if the reallocation is for additional space, and the +    chunk can be extended, it is, else a malloc-copy-free sequence is +    taken.  There are several different ways that a chunk could be +    extended. All are tried: + +       * Extending forward into following adjacent free chunk. +       * Shifting backwards, joining preceding adjacent space +       * Both shifting backwards and extending forward. +       * Extending into newly sbrked space + +    Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a +    size argument of zero (re)allocates a minimum-sized chunk. + +    If the reallocation is for less space, and the new request is for +    a `small' (<512 bytes) size, then the newly unused space is lopped +    off and freed. + +    The old unix realloc convention of allowing the last-free'd chunk +    to be used as an argument to realloc is no longer supported. +    I don't know of any programs still relying on this feature, +    and allowing it would also allow too many other incorrect +    usages of realloc to be sensible. + + +*/ + + +#if __STD_C +Void_t* rEALLOc(Void_t* oldmem, size_t bytes) +#else +Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; +#endif +{ +  INTERNAL_SIZE_T    nb;      /* padded request size */ + +  mchunkptr oldp;             /* chunk corresponding to oldmem */ +  INTERNAL_SIZE_T    oldsize; /* its size */ + +  mchunkptr newp;             /* chunk to return */ +  INTERNAL_SIZE_T    newsize; /* its size */ +  Void_t*   newmem;           /* corresponding user mem */ + +  mchunkptr next;             /* next contiguous chunk after oldp */ +  INTERNAL_SIZE_T  nextsize;  /* its size */ + +  mchunkptr prev;             /* previous contiguous chunk before oldp */ +  INTERNAL_SIZE_T  prevsize;  /* its size */ + +  mchunkptr remainder;        /* holds split off extra space from newp */ +  INTERNAL_SIZE_T  remainder_size;   /* its size */ + +  mchunkptr bck;              /* misc temp for linking */ +  mchunkptr fwd;              /* misc temp for linking */ + +#ifdef REALLOC_ZERO_BYTES_FREES +  if (bytes == 0) { fREe(oldmem); return 0; } +#endif + +  if ((long)bytes < 0) return 0; + +  /* realloc of null is supposed to be same as malloc */ +  if (oldmem == 0) return mALLOc(bytes); + +  newp    = oldp    = mem2chunk(oldmem); +  newsize = oldsize = chunksize(oldp); + + +  nb = request2size(bytes); + +#if HAVE_MMAP +  if (chunk_is_mmapped(oldp)) +  { +#if HAVE_MREMAP +    newp = mremap_chunk(oldp, nb); +    if(newp) return chunk2mem(newp); +#endif +    /* Note the extra SIZE_SZ overhead. */ +    if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */ +    /* Must alloc, copy, free. */ +    newmem = mALLOc(bytes); +    if (newmem == 0) return 0; /* propagate failure */ +    MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); +    munmap_chunk(oldp); +    return newmem; +  } +#endif + +  check_inuse_chunk(oldp); + +  if ((long)(oldsize) < (long)(nb)) +  { + +    /* Try expanding forward */ + +    next = chunk_at_offset(oldp, oldsize); +    if (next == top || !inuse(next)) +    { +      nextsize = chunksize(next); + +      /* Forward into top only if a remainder */ +      if (next == top) +      { +        if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE)) +        { +          newsize += nextsize; +          top = chunk_at_offset(oldp, nb); +          set_head(top, (newsize - nb) | PREV_INUSE); +          set_head_size(oldp, nb); +          return chunk2mem(oldp); +        } +      } + +      /* Forward into next chunk */ +      else if (((long)(nextsize + newsize) >= (long)(nb))) +      { +        unlink(next, bck, fwd); +        newsize  += nextsize; +        goto split; +      } +    } +    else +    { +      next = 0; +      nextsize = 0; +    } + +    /* Try shifting backwards. */ + +    if (!prev_inuse(oldp)) +    { +      prev = prev_chunk(oldp); +      prevsize = chunksize(prev); + +      /* try forward + backward first to save a later consolidation */ + +      if (next != 0) +      { +        /* into top */ +        if (next == top) +        { +          if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE)) +          { +            unlink(prev, bck, fwd); +            newp = prev; +            newsize += prevsize + nextsize; +            newmem = chunk2mem(newp); +            MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); +            top = chunk_at_offset(newp, nb); +            set_head(top, (newsize - nb) | PREV_INUSE); +            set_head_size(newp, nb); +            return newmem; +          } +        } + +        /* into next chunk */ +        else if (((long)(nextsize + prevsize + newsize) >= (long)(nb))) +        { +          unlink(next, bck, fwd); +          unlink(prev, bck, fwd); +          newp = prev; +          newsize += nextsize + prevsize; +          newmem = chunk2mem(newp); +          MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); +          goto split; +        } +      } + +      /* backward only */ +      if (prev != 0 && (long)(prevsize + newsize) >= (long)nb) +      { +        unlink(prev, bck, fwd); +        newp = prev; +        newsize += prevsize; +        newmem = chunk2mem(newp); +        MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); +        goto split; +      } +    } + +    /* Must allocate */ + +    newmem = mALLOc (bytes); + +    if (newmem == 0)  /* propagate failure */ +      return 0; + +    /* Avoid copy if newp is next chunk after oldp. */ +    /* (This can only happen when new chunk is sbrk'ed.) */ + +    if ( (newp = mem2chunk(newmem)) == next_chunk(oldp)) +    { +      newsize += chunksize(newp); +      newp = oldp; +      goto split; +    } + +    /* Otherwise copy, free, and exit */ +    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); +    fREe(oldmem); +    return newmem; +  } + + + split:  /* split off extra room in old or expanded chunk */ + +  if (newsize - nb >= MINSIZE) /* split off remainder */ +  { +    remainder = chunk_at_offset(newp, nb); +    remainder_size = newsize - nb; +    set_head_size(newp, nb); +    set_head(remainder, remainder_size | PREV_INUSE); +    set_inuse_bit_at_offset(remainder, remainder_size); +    fREe(chunk2mem(remainder)); /* let free() deal with it */ +  } +  else +  { +    set_head_size(newp, newsize); +    set_inuse_bit_at_offset(newp, newsize); +  } + +  check_inuse_chunk(newp); +  return chunk2mem(newp); +} + + + + +/* + +  memalign algorithm: + +    memalign requests more than enough space from malloc, finds a spot +    within that chunk that meets the alignment request, and then +    possibly frees the leading and trailing space. + +    The alignment argument must be a power of two. This property is not +    checked by memalign, so misuse may result in random runtime errors. + +    8-byte alignment is guaranteed by normal malloc calls, so don't +    bother calling memalign with an argument of 8 or less. + +    Overreliance on memalign is a sure way to fragment space. + +*/ + + +#if __STD_C +Void_t* mEMALIGn(size_t alignment, size_t bytes) +#else +Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; +#endif +{ +  INTERNAL_SIZE_T    nb;      /* padded  request size */ +  char*     m;                /* memory returned by malloc call */ +  mchunkptr p;                /* corresponding chunk */ +  char*     brk;              /* alignment point within p */ +  mchunkptr newp;             /* chunk to return */ +  INTERNAL_SIZE_T  newsize;   /* its size */ +  INTERNAL_SIZE_T  leadsize;  /* leading space befor alignment point */ +  mchunkptr remainder;        /* spare room at end to split off */ +  long      remainder_size;   /* its size */ + +  if ((long)bytes < 0) return 0; + +  /* If need less alignment than we give anyway, just relay to malloc */ + +  if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); + +  /* Otherwise, ensure that it is at least a minimum chunk size */ + +  if (alignment <  MINSIZE) alignment = MINSIZE; + +  /* Call malloc with worst case padding to hit alignment. */ + +  nb = request2size(bytes); +  m  = (char*)(mALLOc(nb + alignment + MINSIZE)); + +  if (m == 0) return 0; /* propagate failure */ + +  p = mem2chunk(m); + +  if ((((unsigned long)(m)) % alignment) == 0) /* aligned */ +  { +#if HAVE_MMAP +    if(chunk_is_mmapped(p)) +      return chunk2mem(p); /* nothing more to do */ +#endif +  } +  else /* misaligned */ +  { +    /* +      Find an aligned spot inside chunk. +      Since we need to give back leading space in a chunk of at +      least MINSIZE, if the first calculation places us at +      a spot with less than MINSIZE leader, we can move to the +      next aligned spot -- we've allocated enough total room so that +      this is always possible. +    */ + +    brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment)); +    if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment; + +    newp = (mchunkptr)brk; +    leadsize = brk - (char*)(p); +    newsize = chunksize(p) - leadsize; + +#if HAVE_MMAP +    if(chunk_is_mmapped(p)) +    { +      newp->prev_size = p->prev_size + leadsize; +      set_head(newp, newsize|IS_MMAPPED); +      return chunk2mem(newp); +    } +#endif + +    /* give back leader, use the rest */ + +    set_head(newp, newsize | PREV_INUSE); +    set_inuse_bit_at_offset(newp, newsize); +    set_head_size(p, leadsize); +    fREe(chunk2mem(p)); +    p = newp; + +    assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0); +  } + +  /* Also give back spare room at the end */ + +  remainder_size = chunksize(p) - nb; + +  if (remainder_size >= (long)MINSIZE) +  { +    remainder = chunk_at_offset(p, nb); +    set_head(remainder, remainder_size | PREV_INUSE); +    set_head_size(p, nb); +    fREe(chunk2mem(remainder)); +  } + +  check_inuse_chunk(p); +  return chunk2mem(p); + +} + + + + +/* +    valloc just invokes memalign with alignment argument equal +    to the page size of the system (or as near to this as can +    be figured out from all the includes/defines above.) +*/ + +#if __STD_C +Void_t* vALLOc(size_t bytes) +#else +Void_t* vALLOc(bytes) size_t bytes; +#endif +{ +  return mEMALIGn (malloc_getpagesize, bytes); +} + +/* +  pvalloc just invokes valloc for the nearest pagesize +  that will accommodate request +*/ + + +#if __STD_C +Void_t* pvALLOc(size_t bytes) +#else +Void_t* pvALLOc(bytes) size_t bytes; +#endif +{ +  size_t pagesize = malloc_getpagesize; +  return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1)); +} + +/* + +  calloc calls malloc, then zeroes out the allocated chunk. + +*/ + +#if __STD_C +Void_t* cALLOc(size_t n, size_t elem_size) +#else +Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; +#endif +{ +  mchunkptr p; +  INTERNAL_SIZE_T csz; + +  INTERNAL_SIZE_T sz = n * elem_size; + + +  /* check if expand_top called, in which case don't need to clear */ +#if MORECORE_CLEARS +  mchunkptr oldtop = top; +  INTERNAL_SIZE_T oldtopsize = chunksize(top); +#endif +  Void_t* mem = mALLOc (sz); + +  if ((long)n < 0) return 0; + +  if (mem == 0) +    return 0; +  else +  { +    p = mem2chunk(mem); + +    /* Two optional cases in which clearing not necessary */ + + +#if HAVE_MMAP +    if (chunk_is_mmapped(p)) return mem; +#endif + +    csz = chunksize(p); + +#if MORECORE_CLEARS +    if (p == oldtop && csz > oldtopsize) +    { +      /* clear only the bytes from non-freshly-sbrked memory */ +      csz = oldtopsize; +    } +#endif + +    MALLOC_ZERO(mem, csz - SIZE_SZ); +    return mem; +  } +} + +/* + +  cfree just calls free. It is needed/defined on some systems +  that pair it with calloc, presumably for odd historical reasons. + +*/ + +#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__) +#if __STD_C +void cfree(Void_t *mem) +#else +void cfree(mem) Void_t *mem; +#endif +{ +  fREe(mem); +} +#endif + + + +/* + +    Malloc_trim gives memory back to the system (via negative +    arguments to sbrk) if there is unused memory at the `high' end of +    the malloc pool. You can call this after freeing large blocks of +    memory to potentially reduce the system-level memory requirements +    of a program. However, it cannot guarantee to reduce memory. Under +    some allocation patterns, some large free blocks of memory will be +    locked between two used chunks, so they cannot be given back to +    the system. + +    The `pad' argument to malloc_trim represents the amount of free +    trailing space to leave untrimmed. If this argument is zero, +    only the minimum amount of memory to maintain internal data +    structures will be left (one page or less). Non-zero arguments +    can be supplied to maintain enough trailing space to service +    future expected allocations without having to re-obtain memory +    from the system. + +    Malloc_trim returns 1 if it actually released any memory, else 0. + +*/ + +#if __STD_C +int malloc_trim(size_t pad) +#else +int malloc_trim(pad) size_t pad; +#endif +{ +  long  top_size;        /* Amount of top-most memory */ +  long  extra;           /* Amount to release */ +  char* current_brk;     /* address returned by pre-check sbrk call */ +  char* new_brk;         /* address returned by negative sbrk call */ + +  unsigned long pagesz = malloc_getpagesize; + +  top_size = chunksize(top); +  extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; + +  if (extra < (long)pagesz)  /* Not enough memory to release */ +    return 0; + +  else +  { +    /* Test to make sure no one else called sbrk */ +    current_brk = (char*)(MORECORE (0)); +    if (current_brk != (char*)(top) + top_size) +      return 0;     /* Apparently we don't own memory; must fail */ + +    else +    { +      new_brk = (char*)(MORECORE (-extra)); + +      if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */ +      { +        /* Try to figure out what we have */ +        current_brk = (char*)(MORECORE (0)); +        top_size = current_brk - (char*)top; +        if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */ +        { +          sbrked_mem = current_brk - sbrk_base; +          set_head(top, top_size | PREV_INUSE); +        } +        check_chunk(top); +        return 0; +      } + +      else +      { +        /* Success. Adjust top accordingly. */ +        set_head(top, (top_size - extra) | PREV_INUSE); +        sbrked_mem -= extra; +        check_chunk(top); +        return 1; +      } +    } +  } +} + + + +/* +  malloc_usable_size: + +    This routine tells you how many bytes you can actually use in an +    allocated chunk, which may be more than you requested (although +    often not). You can use this many bytes without worrying about +    overwriting other allocated objects. Not a particularly great +    programming practice, but still sometimes useful. + +*/ + +#if __STD_C +size_t malloc_usable_size(Void_t* mem) +#else +size_t malloc_usable_size(mem) Void_t* mem; +#endif +{ +  mchunkptr p; +  if (mem == 0) +    return 0; +  else +  { +    p = mem2chunk(mem); +    if(!chunk_is_mmapped(p)) +    { +      if (!inuse(p)) return 0; +      check_inuse_chunk(p); +      return chunksize(p) - SIZE_SZ; +    } +    return chunksize(p) - 2*SIZE_SZ; +  } +} + + + + +/* Utility to update current_mallinfo for malloc_stats and mallinfo() */ + +static void malloc_update_mallinfo() +{ +  int i; +  mbinptr b; +  mchunkptr p; +#if DEBUG +  mchunkptr q; +#endif + +  INTERNAL_SIZE_T avail = chunksize(top); +  int   navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0; + +  for (i = 1; i < NAV; ++i) +  { +    b = bin_at(i); +    for (p = last(b); p != b; p = p->bk) +    { +#if DEBUG +      check_free_chunk(p); +      for (q = next_chunk(p); +           q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; +           q = next_chunk(q)) +        check_inuse_chunk(q); +#endif +      avail += chunksize(p); +      navail++; +    } +  } + +  current_mallinfo.ordblks = navail; +  current_mallinfo.uordblks = sbrked_mem - avail; +  current_mallinfo.fordblks = avail; +  current_mallinfo.hblks = n_mmaps; +  current_mallinfo.hblkhd = mmapped_mem; +  current_mallinfo.keepcost = chunksize(top); + +} + + + +/* + +  malloc_stats: + +    Prints on stderr the amount of space obtain from the system (both +    via sbrk and mmap), the maximum amount (which may be more than +    current if malloc_trim and/or munmap got called), the maximum +    number of simultaneous mmap regions used, and the current number +    of bytes allocated via malloc (or realloc, etc) but not yet +    freed. (Note that this is the number of bytes allocated, not the +    number requested. It will be larger than the number requested +    because of alignment and bookkeeping overhead.) + +*/ + +void malloc_stats() +{ +  malloc_update_mallinfo(); +  fprintf(stderr, "max system bytes = %10u\n", +          (unsigned int)(max_total_mem)); +  fprintf(stderr, "system bytes     = %10u\n", +          (unsigned int)(sbrked_mem + mmapped_mem)); +  fprintf(stderr, "in use bytes     = %10u\n", +          (unsigned int)(current_mallinfo.uordblks + mmapped_mem)); +#if HAVE_MMAP +  fprintf(stderr, "max mmap regions = %10u\n", +          (unsigned int)max_n_mmaps); +#endif +} + +/* +  mallinfo returns a copy of updated current mallinfo. +*/ + +struct mallinfo mALLINFo() +{ +  malloc_update_mallinfo(); +  return current_mallinfo; +} + + + + +/* +  mallopt: + +    mallopt is the general SVID/XPG interface to tunable parameters. +    The format is to provide a (parameter-number, parameter-value) pair. +    mallopt then sets the corresponding parameter to the argument +    value if it can (i.e., so long as the value is meaningful), +    and returns 1 if successful else 0. + +    See descriptions of tunable parameters above. + +*/ + +#if __STD_C +int mALLOPt(int param_number, int value) +#else +int mALLOPt(param_number, value) int param_number; int value; +#endif +{ +  switch(param_number) +  { +    case M_TRIM_THRESHOLD: +      trim_threshold = value; return 1; +    case M_TOP_PAD: +      top_pad = value; return 1; +    case M_MMAP_THRESHOLD: +      mmap_threshold = value; return 1; +    case M_MMAP_MAX: +#if HAVE_MMAP +      n_mmaps_max = value; return 1; +#else +      if (value != 0) return 0; else  n_mmaps_max = value; return 1; +#endif + +    default: +      return 0; +  } +} + +/* + +History: + +    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee) +      * return null for negative arguments +      * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com> +         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' +          (e.g. WIN32 platforms) +         * Cleanup up header file inclusion for WIN32 platforms +         * Cleanup code to avoid Microsoft Visual C++ compiler complaints +         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing +           memory allocation routines +         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) +         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to +	   usage of 'assert' in non-WIN32 code +         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to +           avoid infinite loop +      * Always call 'fREe()' rather than 'free()' + +    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee) +      * Fixed ordering problem with boundary-stamping + +    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee) +      * Added pvalloc, as recommended by H.J. Liu +      * Added 64bit pointer support mainly from Wolfram Gloger +      * Added anonymously donated WIN32 sbrk emulation +      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen +      * malloc_extend_top: fix mask error that caused wastage after +        foreign sbrks +      * Add linux mremap support code from HJ Liu + +    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee) +      * Integrated most documentation with the code. +      * Add support for mmap, with help from +        Wolfram Gloger (Gloger@lrz.uni-muenchen.de). +      * Use last_remainder in more cases. +      * Pack bins using idea from  colin@nyx10.cs.du.edu +      * Use ordered bins instead of best-fit threshhold +      * Eliminate block-local decls to simplify tracing and debugging. +      * Support another case of realloc via move into top +      * Fix error occuring when initial sbrk_base not word-aligned. +      * Rely on page size for units instead of SBRK_UNIT to +        avoid surprises about sbrk alignment conventions. +      * Add mallinfo, mallopt. Thanks to Raymond Nijssen +        (raymond@es.ele.tue.nl) for the suggestion. +      * Add `pad' argument to malloc_trim and top_pad mallopt parameter. +      * More precautions for cases where other routines call sbrk, +        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). +      * Added macros etc., allowing use in linux libc from +        H.J. Lu (hjl@gnu.ai.mit.edu) +      * Inverted this history list + +    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee) +      * Re-tuned and fixed to behave more nicely with V2.6.0 changes. +      * Removed all preallocation code since under current scheme +        the work required to undo bad preallocations exceeds +        the work saved in good cases for most test programs. +      * No longer use return list or unconsolidated bins since +        no scheme using them consistently outperforms those that don't +        given above changes. +      * Use best fit for very large chunks to prevent some worst-cases. +      * Added some support for debugging + +    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee) +      * Removed footers when chunks are in use. Thanks to +        Paul Wilson (wilson@cs.texas.edu) for the suggestion. + +    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee) +      * Added malloc_trim, with help from Wolfram Gloger +        (wmglo@Dent.MED.Uni-Muenchen.DE). + +    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g) + +    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g) +      * realloc: try to expand in both directions +      * malloc: swap order of clean-bin strategy; +      * realloc: only conditionally expand backwards +      * Try not to scavenge used bins +      * Use bin counts as a guide to preallocation +      * Occasionally bin return list chunks in first scan +      * Add a few optimizations from colin@nyx10.cs.du.edu + +    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g) +      * faster bin computation & slightly different binning +      * merged all consolidations to one part of malloc proper +         (eliminating old malloc_find_space & malloc_clean_bin) +      * Scan 2 returns chunks (not just 1) +      * Propagate failure in realloc if malloc returns 0 +      * Add stuff to allow compilation on non-ANSI compilers +          from kpv@research.att.com + +    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu) +      * removed potential for odd address access in prev_chunk +      * removed dependency on getpagesize.h +      * misc cosmetics and a bit more internal documentation +      * anticosmetics: mangled names in macros to evade debugger strangeness +      * tested on sparc, hp-700, dec-mips, rs6000 +          with gcc & native cc (hp, dec only) allowing +          Detlefs & Zorn comparison study (in SIGPLAN Notices.) + +    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu) +      * Based loosely on libg++-1.2X malloc. (It retains some of the overall +         structure of old version,  but most details differ.) + +*/ + + diff --git a/include/ppc_defs.h b/include/ppc_defs.h new file mode 100644 index 000000000..8b2b3b5fd --- /dev/null +++ b/include/ppc_defs.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * WARNING! This file is automatically generated - DO NOT EDIT! + */ +#define	KERNELBASE	-1073741824 +#define	STATE	0 +#define	NEXT_TASK	64 +#define	COUNTER	52 +#define	PROCESSOR	916 +#define	SIGPENDING	8 +#define	TSS	576 +#define	MM	880 +#define	TASK_STRUCT_SIZE	928 +#define	KSP	0 +#define	PG_TABLES	4 +#define	PGD	8 +#define	LAST_SYSCALL	20 +#define	PT_REGS	12 +#define	PF_TRACESYS	32 +#define	TASK_FLAGS	4 +#define	TSS_FPR0	24 +#define	TSS_FPSCR	284 +#define	TSS_SMP_FORK_RET	288 +#define	TASK_UNION_SIZE	8192 +#define	STACK_FRAME_OVERHEAD	16 +#define	INT_FRAME_SIZE	192 +#define	GPR0	16 +#define	GPR1	20 +#define	GPR2	24 +#define	GPR3	28 +#define	GPR4	32 +#define	GPR5	36 +#define	GPR6	40 +#define	GPR7	44 +#define	GPR8	48 +#define	GPR9	52 +#define	GPR10	56 +#define	GPR11	60 +#define	GPR12	64 +#define	GPR13	68 +#define	GPR14	72 +#define	GPR15	76 +#define	GPR16	80 +#define	GPR17	84 +#define	GPR18	88 +#define	GPR19	92 +#define	GPR20	96 +#define	GPR21	100 +#define	GPR22	104 +#define	GPR23	108 +#define	GPR24	112 +#define	GPR25	116 +#define	GPR26	120 +#define	GPR27	124 +#define	GPR28	128 +#define	GPR29	132 +#define	GPR30	136 +#define	GPR31	140 +#define	_NIP	144 +#define	_MSR	148 +#define	_CTR	156 +#define	_LINK	160 +#define	_CCR	168 +#define	_XER	164 +#define	_DAR	180 +#define	_DSISR	184 +#define	ORIG_GPR3	152 +#define	RESULT	188 +#define	TRAP	176 diff --git a/lib_generic/ctype.c b/lib_generic/ctype.c new file mode 100644 index 000000000..6ed0468a2 --- /dev/null +++ b/lib_generic/ctype.c @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + *  linux/lib/ctype.c + * + *  Copyright (C) 1991, 1992  Linus Torvalds + */ + +#include <linux/ctype.h> + +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */ diff --git a/lib_ppc/ppcstring.S b/lib_ppc/ppcstring.S new file mode 100644 index 000000000..97023a055 --- /dev/null +++ b/lib_ppc/ppcstring.S @@ -0,0 +1,216 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <ppc_asm.tmpl> +#include <asm/errno.h> + +	.globl	strcpy +strcpy: +	addi	r5,r3,-1 +	addi	r4,r4,-1 +1:	lbzu	r0,1(r4) +	cmpwi	0,r0,0 +	stbu	r0,1(r5) +	bne	1b +	blr + +	.globl	strncpy +strncpy: +	cmpwi	0,r5,0 +	beqlr +	mtctr	r5 +	addi	r6,r3,-1 +	addi	r4,r4,-1 +1:	lbzu	r0,1(r4) +	cmpwi	0,r0,0 +	stbu	r0,1(r6) +	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */ +	blr + +	.globl	strcat +strcat: +	addi	r5,r3,-1 +	addi	r4,r4,-1 +1:	lbzu	r0,1(r5) +	cmpwi	0,r0,0 +	bne	1b +	addi	r5,r5,-1 +1:	lbzu	r0,1(r4) +	cmpwi	0,r0,0 +	stbu	r0,1(r5) +	bne	1b +	blr + +	.globl	strcmp +strcmp: +	addi	r5,r3,-1 +	addi	r4,r4,-1 +1:	lbzu	r3,1(r5) +	cmpwi	1,r3,0 +	lbzu	r0,1(r4) +	subf.	r3,r0,r3 +	beqlr	1 +	beq	1b +	blr + +	.globl	strlen +strlen: +	addi	r4,r3,-1 +1:	lbzu	r0,1(r4) +	cmpwi	0,r0,0 +	bne	1b +	subf	r3,r3,r4 +	blr + +	.globl	memset +memset: +	rlwimi	r4,r4,8,16,23 +	rlwimi	r4,r4,16,0,15 +	addi	r6,r3,-4 +	cmplwi	0,r5,4 +	blt	7f +	stwu	r4,4(r6) +	beqlr +	andi.	r0,r6,3 +	add	r5,r0,r5 +	subf	r6,r0,r6 +	rlwinm	r0,r5,32-2,2,31 +	mtctr	r0 +	bdz	6f +1:	stwu	r4,4(r6) +	bdnz	1b +6:	andi.	r5,r5,3 +7:	cmpwi	0,r5,0 +	beqlr +	mtctr	r5 +	addi	r6,r6,3 +8:	stbu	r4,1(r6) +	bdnz	8b +	blr + +	.globl	bcopy +bcopy: +	mr	r6,r3 +	mr	r3,r4 +	mr	r4,r6 +	b	memcpy + +	.globl	memmove +memmove: +	cmplw	0,r3,r4 +	bgt	backwards_memcpy +	/* fall through */ + +	.globl	memcpy +memcpy: +	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */ +	addi	r6,r3,-4 +	addi	r4,r4,-4 +	beq	2f			/* if less than 8 bytes to do */ +	andi.	r0,r6,3			/* get dest word aligned */ +	mtctr	r7 +	bne	5f +1:	lwz	r7,4(r4) +	lwzu	r8,8(r4) +	stw	r7,4(r6) +	stwu	r8,8(r6) +	bdnz	1b +	andi.	r5,r5,7 +2:	cmplwi	0,r5,4 +	blt	3f +	lwzu	r0,4(r4) +	addi	r5,r5,-4 +	stwu	r0,4(r6) +3:	cmpwi	0,r5,0 +	beqlr +	mtctr	r5 +	addi	r4,r4,3 +	addi	r6,r6,3 +4:	lbzu	r0,1(r4) +	stbu	r0,1(r6) +	bdnz	4b +	blr +5:	subfic	r0,r0,4 +	mtctr	r0 +6:	lbz	r7,4(r4) +	addi	r4,r4,1 +	stb	r7,4(r6) +	addi	r6,r6,1 +	bdnz	6b +	subf	r5,r0,r5 +	rlwinm.	r7,r5,32-3,3,31 +	beq	2b +	mtctr	r7 +	b	1b + +	.globl	backwards_memcpy +backwards_memcpy: +	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */ +	add	r6,r3,r5 +	add	r4,r4,r5 +	beq	2f +	andi.	r0,r6,3 +	mtctr	r7 +	bne	5f +1:	lwz	r7,-4(r4) +	lwzu	r8,-8(r4) +	stw	r7,-4(r6) +	stwu	r8,-8(r6) +	bdnz	1b +	andi.	r5,r5,7 +2:	cmplwi	0,r5,4 +	blt	3f +	lwzu	r0,-4(r4) +	subi	r5,r5,4 +	stwu	r0,-4(r6) +3:	cmpwi	0,r5,0 +	beqlr +	mtctr	r5 +4:	lbzu	r0,-1(r4) +	stbu	r0,-1(r6) +	bdnz	4b +	blr +5:	mtctr	r0 +6:	lbzu	r7,-1(r4) +	stbu	r7,-1(r6) +	bdnz	6b +	subf	r5,r0,r5 +	rlwinm.	r7,r5,32-3,3,31 +	beq	2b +	mtctr	r7 +	b	1b + +	.globl	memcmp +memcmp: +	cmpwi	0,r5,0 +	ble-	2f +	mtctr	r5 +	addi	r6,r3,-1 +	addi	r4,r4,-1 +1:	lbzu	r3,1(r6) +	lbzu	r0,1(r4) +	subf.	r3,r0,r3 +	bdnzt	2,1b +	blr +2:	li	r3,0 +	blr + +	.global	memchr +memchr: +	cmpwi	0,r5,0 +	ble-	2f +	mtctr	r5 +	addi	r3,r3,-1 +1:	lbzu	r0,1(r3) +	cmpw	0,r0,r4 +	bdnzf	2,1b +	beqlr +2:	li	r3,0 +	blr |