malloc.c

Go to the documentation of this file.
00001 /* $Header: /opt/proj/minix/cvsroot/src/lib/ansi/malloc.c,v 1.1.1.1 2005/04/21 14:56:05 beng Exp $ */
00002 
00003 /* replace undef by define */
00004 #undef   DEBUG          /* check assertions */
00005 #undef   SLOWDEBUG      /* some extra test loops (requires DEBUG) */
00006 
00007 #ifndef DEBUG
00008 #define NDEBUG
00009 #endif
00010 
00011 #include        <stdlib.h>
00012 #include        <string.h>
00013 #include        <errno.h>
00014 #include        <assert.h>
00015 
00016 #if _EM_WSIZE == _EM_PSIZE
00017 #define ptrint          int
00018 #else
00019 #define ptrint          long
00020 #endif
00021 
00022 #if     _EM_PSIZE == 2
00023 #define BRKSIZE         1024
00024 #else
00025 #define BRKSIZE         4096
00026 #endif
00027 #define PTRSIZE         ((int) sizeof(void *))
00028 #define Align(x,a)      (((x) + (a - 1)) & ~(a - 1))
00029 #define NextSlot(p)     (* (void **) ((p) - PTRSIZE))
00030 #define NextFree(p)     (* (void **) (p))
00031 
00032 /*
00033  * A short explanation of the data structure and algorithms.
00034  * An area returned by malloc() is called a slot. Each slot
00035  * contains the number of bytes requested, but preceeded by
00036  * an extra pointer to the next the slot in memory.
00037  * '_bottom' and '_top' point to the first/last slot.
00038  * More memory is asked for using brk() and appended to top.
00039  * The list of free slots is maintained to keep malloc() fast.
00040  * '_empty' points the the first free slot. Free slots are
00041  * linked together by a pointer at the start of the
00042  * user visable part, so just after the next-slot pointer.
00043  * Free slots are merged together by free().
00044  */
00045 
00046 extern void *_sbrk(int);
00047 extern int _brk(void *);
00048 static void *_bottom, *_top, *_empty;
00049 
00050 static int grow(size_t len)
00051 {
00052   register char *p;
00053 
00054   assert(NextSlot((char *)_top) == 0);
00055   if ((char *) _top + len < (char *) _top
00056       || (p = (char *)Align((ptrint)_top + len, BRKSIZE)) < (char *) _top ) {
00057         errno = ENOMEM;
00058         return(0);
00059   }
00060   if (_brk(p) != 0)
00061         return(0);
00062   NextSlot((char *)_top) = p;
00063   NextSlot(p) = 0;
00064   free(_top);
00065   _top = p;
00066   return 1;
00067 }
00068 
00069 void *
00070 malloc(size_t size)
00071 {
00072   register char *prev, *p, *next, *new;
00073   register unsigned len, ntries;
00074 
00075   if (size == 0)
00076         return NULL;
00077 
00078   for (ntries = 0; ntries < 2; ntries++) {
00079         if ((len = Align(size, PTRSIZE) + PTRSIZE) < 2 * PTRSIZE) {
00080                 errno = ENOMEM;
00081                 return NULL;
00082         }
00083         if (_bottom == 0) {
00084                 if ((p = _sbrk(2 * PTRSIZE)) == (char *) -1)
00085                         return NULL;
00086                 p = (char *) Align((ptrint)p, PTRSIZE);
00087                 p += PTRSIZE;
00088                 _top = _bottom = p;
00089                 NextSlot(p) = 0;
00090         }
00091 #ifdef SLOWDEBUG
00092         for (p = _bottom; (next = NextSlot(p)) != 0; p = next)
00093                 assert(next > p);
00094         assert(p == _top);
00095 #endif
00096         for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
00097                 next = NextSlot(p);
00098                 new = p + len;  /* easily overflows!! */
00099                 if (new > next || new <= p)
00100                         continue;               /* too small */
00101                 if (new + PTRSIZE < next) {     /* too big, so split */
00102                         /* + PTRSIZE avoids tiny slots on free list */
00103                         NextSlot(new) = next;
00104                         NextSlot(p) = new;
00105                         NextFree(new) = NextFree(p);
00106                         NextFree(p) = new;
00107                 }
00108                 if (prev)
00109                         NextFree(prev) = NextFree(p);
00110                 else
00111                         _empty = NextFree(p);
00112                 return p;
00113         }
00114         if (grow(len) == 0)
00115                 break;
00116   }
00117   assert(ntries != 2);
00118   return NULL;
00119 }
00120 
00121 void *
00122 realloc(void *oldp, size_t size)
00123 {
00124   register char *prev, *p, *next, *new;
00125   char *old = oldp;
00126   register size_t len, n;
00127 
00128   if (old == 0)
00129         return malloc(size);
00130   if (size == 0) {
00131         free(old);
00132         return NULL;
00133   }
00134   len = Align(size, PTRSIZE) + PTRSIZE;
00135   next = NextSlot(old);
00136   n = (int)(next - old);                        /* old length */
00137   /*
00138    * extend old if there is any free space just behind it
00139    */
00140   for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
00141         if (p > next)
00142                 break;
00143         if (p == next) {        /* 'next' is a free slot: merge */
00144                 NextSlot(old) = NextSlot(p);
00145                 if (prev)
00146                         NextFree(prev) = NextFree(p);
00147                 else
00148                         _empty = NextFree(p);
00149                 next = NextSlot(old);
00150                 break;
00151         }
00152   }
00153   new = old + len;
00154   /*
00155    * Can we use the old, possibly extended slot?
00156    */
00157   if (new <= next && new >= old) {              /* it does fit */
00158         if (new + PTRSIZE < next) {             /* too big, so split */
00159                 /* + PTRSIZE avoids tiny slots on free list */
00160                 NextSlot(new) = next;
00161                 NextSlot(old) = new;
00162                 free(new);
00163         }
00164         return old;
00165   }
00166   if ((new = malloc(size)) == NULL)             /* it didn't fit */
00167         return NULL;
00168   memcpy(new, old, n);                          /* n < size */
00169   free(old);
00170   return new;
00171 }
00172 
00173 void
00174 free(void *ptr)
00175 {
00176   register char *prev, *next;
00177   char *p = ptr;
00178 
00179   if (p == 0)
00180         return;
00181 
00182   assert(NextSlot(p) > p);
00183   for (prev = 0, next = _empty; next != 0; prev = next, next = NextFree(next))
00184         if (p < next)
00185                 break;
00186   NextFree(p) = next;
00187   if (prev)
00188         NextFree(prev) = p;
00189   else
00190         _empty = p;
00191   if (next) {
00192         assert(NextSlot(p) <= next);
00193         if (NextSlot(p) == next) {              /* merge p and next */
00194                 NextSlot(p) = NextSlot(next);
00195                 NextFree(p) = NextFree(next);
00196         }
00197   }
00198   if (prev) {
00199         assert(NextSlot(prev) <= p);
00200         if (NextSlot(prev) == p) {              /* merge prev and p */
00201                 NextSlot(prev) = NextSlot(p);
00202                 NextFree(prev) = NextFree(p);
00203         }
00204   }
00205 }

Generated on Fri Apr 14 22:56:41 2006 for minix by  doxygen 1.4.6