mmalloc.c

Go to the documentation of this file.
00001 /* @(#)root/clib:$Id: mmalloc.c 31251 2009-11-17 20:00:28Z rdm $ */
00002 /* Author: */
00003 
00004 /* Memory allocator `malloc'.
00005    Copyright 1990, 1991, 1992 Free Software Foundation
00006 
00007    Written May 1989 by Mike Haertel.
00008    Heavily modified Mar 1992 by Fred Fish for mmap'd version.
00009 
00010 The GNU C Library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU Library General Public License as
00012 published by the Free Software Foundation; either version 2 of the
00013 License, or (at your option) any later version.
00014 
00015 The GNU C Library is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 Library General Public License for more details.
00019 
00020 You should have received a copy of the GNU Library General Public
00021 License along with the GNU C Library; see the file COPYING.LIB.  If
00022 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023 Boston, MA 02111-1307, USA.
00024 
00025    The author may be reached (Email) at the address mike@ai.mit.edu,
00026    or (US mail) as Mike Haertel c/o Free Software Foundation. */
00027 
00028 #include <string.h>     /* Prototypes for memcpy, memmove, memset, etc */
00029 
00030 #include "mmprivate.h"
00031 
00032 /* Prototypes for local functions */
00033 
00034 static int initialize PARAMS ((struct mdesc *));
00035 static PTR morecore PARAMS ((struct mdesc *, size_t));
00036 static PTR align PARAMS ((struct mdesc *, size_t));
00037 
00038 /* Aligned allocation.  */
00039 
00040 static PTR
00041 align (mdp, size)
00042   struct mdesc *mdp;
00043   size_t size;
00044 {
00045   PTR result;
00046   unsigned long int adj;
00047 
00048   result = mdp -> morecore (mdp, size);
00049   adj = RESIDUAL (result, BLOCKSIZE);
00050   if (adj != 0)
00051     {
00052       adj = BLOCKSIZE - adj;
00053       mdp -> morecore (mdp, adj);
00054       result = (char *) result + adj;
00055     }
00056   return (result);
00057 }
00058 
00059 /* Set everything up and remember that we have.  */
00060 
00061 static int
00062 initialize (mdp)
00063   struct mdesc *mdp;
00064 {
00065   mdp -> heapsize = HEAP / BLOCKSIZE;
00066   mdp -> heapinfo = (mmalloc_info *)
00067     align (mdp, mdp -> heapsize * sizeof (mmalloc_info));
00068   if (mdp -> heapinfo == NULL)
00069     {
00070       return (0);
00071     }
00072   memset ((PTR)mdp -> heapinfo, 0, mdp -> heapsize * sizeof (mmalloc_info));
00073   mdp -> heapinfo[0].free.size = 0;
00074   mdp -> heapinfo[0].free.next = mdp -> heapinfo[0].free.prev = 0;
00075   mdp -> heapindex = 0;
00076   mdp -> heapbase = (char *) mdp -> heapinfo;
00077   mdp -> flags |= MMALLOC_INITIALIZED;
00078   return (1);
00079 }
00080 
00081 /* Get neatly aligned memory, initializing or
00082    growing the heap info table as necessary. */
00083 
00084 static PTR
00085 morecore (mdp, size)
00086   struct mdesc *mdp;
00087   size_t size;
00088 {
00089   PTR result;
00090   mmalloc_info *newinfo, *oldinfo;
00091   size_t newsize;
00092 
00093   result = align (mdp, size);
00094   if (result == NULL)
00095     {
00096       return (NULL);
00097     }
00098 
00099   /* Check if we need to grow the info table.  */
00100   if ((size_t) BLOCK ((char *) result + size) > mdp -> heapsize)
00101     {
00102       newsize = mdp -> heapsize;
00103       while ((size_t) BLOCK ((char *) result + size) > newsize)
00104         {
00105           newsize *= 2;
00106         }
00107       newinfo = (mmalloc_info *) align (mdp, newsize * sizeof (mmalloc_info));
00108       if (newinfo == NULL)
00109         {
00110           mdp -> morecore (mdp, -(ptrdiff_t)size);
00111           return (NULL);
00112         }
00113       memset ((PTR) newinfo, 0, newsize * sizeof (mmalloc_info));
00114       memcpy ((PTR) newinfo, (PTR) mdp -> heapinfo,
00115               mdp -> heapsize * sizeof (mmalloc_info));
00116       oldinfo = mdp -> heapinfo;
00117       newinfo[BLOCK (oldinfo)].busy.type = 0;
00118       newinfo[BLOCK (oldinfo)].busy.info.size
00119         = BLOCKIFY (mdp -> heapsize * sizeof (mmalloc_info));
00120       mdp -> heapinfo = newinfo;
00121       __mmalloc_free (mdp, (PTR)oldinfo);
00122       mdp -> heapsize = newsize;
00123     }
00124 
00125   mdp -> heaplimit = BLOCK ((char *) result + size);
00126   return (result);
00127 }
00128 
00129 /* Allocate memory from the heap.  */
00130 
00131 PTR
00132 mmalloc (md, size)
00133   PTR md;
00134   size_t size;
00135 {
00136   struct mdesc *mdp;
00137   PTR result;
00138   size_t block, blocks, lastblocks, start;
00139   register size_t i;
00140   struct mmlist *next;
00141   register size_t log;
00142 
00143   if (size == 0)
00144     {
00145       return (NULL);
00146     }
00147 
00148   mdp = MD_TO_MDP (md);
00149 
00150   if (mdp -> mmalloc_hook != NULL)
00151     {
00152       return ((*mdp -> mmalloc_hook) (md, size));
00153     }
00154 
00155   if (!(mdp -> flags & MMALLOC_INITIALIZED))
00156     {
00157       if (!initialize (mdp))
00158         {
00159           return (NULL);
00160         }
00161     }
00162 
00163   if (size < sizeof (struct mmlist))
00164     {
00165       size = sizeof (struct mmlist);
00166     }
00167 
00168   /* Determine the allocation policy based on the request size.  */
00169   if (size <= BLOCKSIZE / 2)
00170     {
00171       /* Small allocation to receive a fragment of a block.
00172          Determine the logarithm to base two of the fragment size. */
00173       log = 1;
00174       --size;
00175       while ((size /= 2) != 0)
00176         {
00177           ++log;
00178         }
00179 
00180       /* Look in the fragment lists for a
00181          free fragment of the desired size. */
00182       next = mdp -> fraghead[log].next;
00183       if (next != NULL)
00184         {
00185           /* There are free fragments of this size.
00186              Pop a fragment out of the fragment list and return it.
00187              Update the block's nfree and first counters. */
00188           result = (PTR) next;
00189           next -> prev -> next = next -> next;
00190           if (next -> next != NULL)
00191             {
00192               next -> next -> prev = next -> prev;
00193             }
00194           block = BLOCK (result);
00195           if (--mdp -> heapinfo[block].busy.info.frag.nfree != 0)
00196             {
00197               mdp -> heapinfo[block].busy.info.frag.first =
00198                 RESIDUAL (next -> next, BLOCKSIZE) >> log;
00199             }
00200 
00201           /* Update the statistics.  */
00202           mdp -> heapstats.chunks_used++;
00203           mdp -> heapstats.bytes_used += 1 << log;
00204           mdp -> heapstats.chunks_free--;
00205           mdp -> heapstats.bytes_free -= 1 << log;
00206         }
00207       else
00208         {
00209           /* No free fragments of the desired size, so get a new block
00210              and break it into fragments, returning the first.  */
00211           result = mmalloc (md, BLOCKSIZE);
00212           if (result == NULL)
00213             {
00214               return (NULL);
00215             }
00216 
00217           /* Link all fragments but the first into the free list.  */
00218           for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
00219             {
00220               next = (struct mmlist *) ((char *) result + (i << log));
00221               next -> next = mdp -> fraghead[log].next;
00222               next -> prev = &mdp -> fraghead[log];
00223               next -> prev -> next = next;
00224               if (next -> next != NULL)
00225                 {
00226                   next -> next -> prev = next;
00227                 }
00228             }
00229 
00230           /* Initialize the nfree and first counters for this block.  */
00231           block = BLOCK (result);
00232           mdp -> heapinfo[block].busy.type = log;
00233           mdp -> heapinfo[block].busy.info.frag.nfree = i - 1;
00234           mdp -> heapinfo[block].busy.info.frag.first = i - 1;
00235 
00236           mdp -> heapstats.chunks_free += (BLOCKSIZE >> log) - 1;
00237           mdp -> heapstats.bytes_free += BLOCKSIZE - (1 << log);
00238           mdp -> heapstats.bytes_used -= BLOCKSIZE - (1 << log);
00239         }
00240     }
00241   else
00242     {
00243       /* Large allocation to receive one or more blocks.
00244          Search the free list in a circle starting at the last place visited.
00245          If we loop completely around without finding a large enough
00246          space we will have to get more memory from the system.  */
00247       blocks = BLOCKIFY(size);
00248       start = block = MALLOC_SEARCH_START;
00249       while (mdp -> heapinfo[block].free.size < blocks)
00250         {
00251           block = mdp -> heapinfo[block].free.next;
00252           if (block == start)
00253             {
00254               /* Need to get more from the system.  Check to see if
00255                  the new core will be contiguous with the final free
00256                  block; if so we don't need to get as much.  */
00257               block = mdp -> heapinfo[0].free.prev;
00258               lastblocks = mdp -> heapinfo[block].free.size;
00259               if (mdp -> heaplimit != 0 &&
00260                   block + lastblocks == mdp -> heaplimit &&
00261                   mdp -> morecore (mdp, 0) == ADDRESS(block + lastblocks) &&
00262                   (morecore (mdp, (blocks - lastblocks) * BLOCKSIZE)) != NULL)
00263                 {
00264                   /* Which block we are extending (the `final free
00265                      block' referred to above) might have changed, if
00266                      it got combined with a freed info table.  */
00267                   block = mdp -> heapinfo[0].free.prev;
00268 
00269                   mdp -> heapinfo[block].free.size += (blocks - lastblocks);
00270                   mdp -> heapstats.bytes_free +=
00271                       (blocks - lastblocks) * BLOCKSIZE;
00272                   continue;
00273                 }
00274               result = morecore(mdp, blocks * BLOCKSIZE);
00275               if (result == NULL)
00276                 {
00277                   return (NULL);
00278                 }
00279               block = BLOCK (result);
00280               mdp -> heapinfo[block].busy.type = 0;
00281               mdp -> heapinfo[block].busy.info.size = blocks;
00282               mdp -> heapstats.chunks_used++;
00283               mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
00284               return (result);
00285             }
00286         }
00287 
00288       /* At this point we have found a suitable free list entry.
00289          Figure out how to remove what we need from the list. */
00290       result = ADDRESS(block);
00291       if (mdp -> heapinfo[block].free.size > blocks)
00292         {
00293           /* The block we found has a bit left over,
00294              so relink the tail end back into the free list. */
00295           mdp -> heapinfo[block + blocks].free.size
00296             = mdp -> heapinfo[block].free.size - blocks;
00297           mdp -> heapinfo[block + blocks].free.next
00298             = mdp -> heapinfo[block].free.next;
00299           mdp -> heapinfo[block + blocks].free.prev
00300             = mdp -> heapinfo[block].free.prev;
00301           mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
00302             = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
00303               = mdp -> heapindex = block + blocks;
00304         }
00305       else
00306         {
00307           /* The block exactly matches our requirements,
00308              so just remove it from the list. */
00309           mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
00310             = mdp -> heapinfo[block].free.prev;
00311           mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
00312             = mdp -> heapindex = mdp -> heapinfo[block].free.next;
00313           mdp -> heapstats.chunks_free--;
00314         }
00315 
00316       mdp -> heapinfo[block].busy.type = 0;
00317       mdp -> heapinfo[block].busy.info.size = blocks;
00318       mdp -> heapstats.chunks_used++;
00319       mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
00320       mdp -> heapstats.bytes_free -= blocks * BLOCKSIZE;
00321     }
00322 
00323   return (result);
00324 }
00325 
00326 /* When using this package, provide a version of malloc/realloc/free built
00327    on top of it, so that if we use the default sbrk() region we will not
00328    collide with another malloc package trying to do the same thing, if
00329    the application contains any "hidden" calls to malloc/realloc/free (such
00330    as inside a system library). */
00331 
00332 #ifndef NO_SBRK_MALLOC
00333 
00334 PTR
00335 malloc (size)
00336   size_t size;
00337 {
00338   return (mmalloc ((PTR) NULL, size));
00339 }
00340 
00341 #endif

Generated on Tue Jul 5 14:11:25 2011 for ROOT_528-00b_version by  doxygen 1.5.1