1: #ifndef lint
   2: static char sccsid[] = "@(#)malloc.c	4.3 (Berkeley) 9/16/83";
   3: #endif
   4: 
   5: /*
   6:  * malloc.c (Caltech) 2/21/82
   7:  * Chris Kingsley, kingsley@cit-20.
   8:  *
   9:  * This is a very fast storage allocator.  It allocates blocks of a small
  10:  * number of different sizes, and keeps free lists of each size.  Blocks that
  11:  * don't exactly fit are passed up to the next larger size.  In this
  12:  * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
  13:  * This is designed for use in a program that uses vast quantities of memory,
  14:  * but bombs when it runs out.
  15:  */
  16: 
  17: #include <sys/types.h>
  18: 
  19: #define NULL 0
  20: 
  21: /*
  22:  * The overhead on a block is at least 4 bytes.  When free, this space
  23:  * contains a pointer to the next free block, and the bottom two bits must
  24:  * be zero.  When in use, the first byte is set to MAGIC, and the second
  25:  * byte is the size index.  The remaining bytes are for alignment.
  26:  * If range checking is enabled and the size of the block fits
  27:  * in two bytes, then the top two bytes hold the size of the requested block
  28:  * plus the range checking words, and the header word MINUS ONE.
  29:  */
  30: union   overhead {
  31:     union   overhead *ov_next;  /* when free */
  32:     struct {
  33:         u_char  ovu_magic;  /* magic number */
  34:         u_char  ovu_index;  /* bucket # */
  35: #ifdef RCHECK
  36:         u_short ovu_size;   /* actual block size */
  37:         u_int   ovu_rmagic; /* range magic number */
  38: #endif
  39:     } ovu;
  40: #define ov_magic    ovu.ovu_magic
  41: #define ov_index    ovu.ovu_index
  42: #define ov_size     ovu.ovu_size
  43: #define ov_rmagic   ovu.ovu_rmagic
  44: };
  45: 
  46: #define MAGIC       0xff        /* magic # on accounting info */
  47: #define RMAGIC      0x55555555  /* magic # on range info */
  48: #ifdef RCHECK
  49: #define RSLOP       sizeof (u_int)
  50: #else
  51: #define RSLOP       0
  52: #endif
  53: 
  54: /*
  55:  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  56:  * smallest allocatable block is 8 bytes.  The overhead information
  57:  * precedes the data area returned to the user.
  58:  */
  59: #define NBUCKETS 30
  60: static  union overhead *nextf[NBUCKETS];
  61: extern  char *sbrk();
  62: 
  63: #ifdef MSTATS
  64: /*
  65:  * nmalloc[i] is the difference between the number of mallocs and frees
  66:  * for a given block size.
  67:  */
  68: static  u_int nmalloc[NBUCKETS];
  69: #include <stdio.h>
  70: #endif
  71: 
  72: #ifdef debug
  73: #define ASSERT(p)   if (!(p)) botch("p"); else
  74: static
  75: botch(s)
  76:     char *s;
  77: {
  78: 
  79:     printf("assertion botched: %s\n", s);
  80:     abort();
  81: }
  82: #else
  83: #define ASSERT(p)
  84: #endif
  85: 
  86: char *
  87: malloc(nbytes)
  88:     register unsigned nbytes;
  89: {
  90:     register union overhead *p;
  91:     register int bucket = 0;
  92:     register unsigned shiftr;
  93: 
  94:     /*
  95: 	 * Convert amount of memory requested into
  96: 	 * closest block size stored in hash buckets
  97: 	 * which satisfies request.  Account for
  98: 	 * space used per block for accounting.
  99: 	 */
 100:     nbytes += sizeof (union overhead) + RSLOP;
 101:     nbytes = (nbytes + 3) &~ 3;
 102:     shiftr = (nbytes - 1) >> 2;
 103:     /* apart from this loop, this is O(1) */
 104:     while (shiftr >>= 1)
 105:         bucket++;
 106:     /*
 107: 	 * If nothing in hash bucket right now,
 108: 	 * request more memory from the system.
 109: 	 */
 110:     if (nextf[bucket] == NULL)
 111:         morecore(bucket);
 112:     if ((p = (union overhead *)nextf[bucket]) == NULL)
 113:         return (NULL);
 114:     /* remove from linked list */
 115:     nextf[bucket] = nextf[bucket]->ov_next;
 116:     p->ov_magic = MAGIC;
 117:     p->ov_index= bucket;
 118: #ifdef MSTATS
 119:     nmalloc[bucket]++;
 120: #endif
 121: #ifdef RCHECK
 122:     /*
 123: 	 * Record allocated size of block and
 124: 	 * bound space with magic numbers.
 125: 	 */
 126:     if (nbytes <= 0x10000)
 127:         p->ov_size = nbytes - 1;
 128:     p->ov_rmagic = RMAGIC;
 129:     *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
 130: #endif
 131:     return ((char *)(p + 1));
 132: }
 133: 
 134: /*
 135:  * Allocate more memory to the indicated bucket.
 136:  */
 137: static
 138: morecore(bucket)
 139:     register bucket;
 140: {
 141:     register union overhead *op;
 142:     register int rnu;       /* 2^rnu bytes will be requested */
 143:     register int nblks;     /* become nblks blocks of the desired size */
 144:     register int siz;
 145: 
 146:     if (nextf[bucket])
 147:         return;
 148:     /*
 149: 	 * Insure memory is allocated
 150: 	 * on a page boundary.  Should
 151: 	 * make getpageize call?
 152: 	 */
 153:     op = (union overhead *)sbrk(0);
 154:     if ((int)op & 0x3ff)
 155:         sbrk(1024 - ((int)op & 0x3ff));
 156:     /* take 2k unless the block is bigger than that */
 157:     rnu = (bucket <= 8) ? 11 : bucket + 3;
 158:     nblks = 1 << (rnu - (bucket + 3));  /* how many blocks to get */
 159:     if (rnu < bucket)
 160:         rnu = bucket;
 161:     op = (union overhead *)sbrk(1 << rnu);
 162:     /* no more room! */
 163:     if ((int)op == -1)
 164:         return;
 165:     /*
 166: 	 * Round up to minimum allocation size boundary
 167: 	 * and deduct from block count to reflect.
 168: 	 */
 169:     if ((int)op & 7) {
 170:         op = (union overhead *)(((int)op + 8) &~ 7);
 171:         nblks--;
 172:     }
 173:     /*
 174: 	 * Add new memory allocated to that on
 175: 	 * free list for this hash bucket.
 176: 	 */
 177:     nextf[bucket] = op;
 178:     siz = 1 << (bucket + 3);
 179:     while (--nblks > 0) {
 180:         op->ov_next = (union overhead *)((caddr_t)op + siz);
 181:         op = (union overhead *)((caddr_t)op + siz);
 182:     }
 183: }
 184: 
 185: free(cp)
 186:     char *cp;
 187: {
 188:     register int size;
 189:     register union overhead *op;
 190: 
 191:     if (cp == NULL)
 192:         return;
 193:     op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
 194: #ifdef debug
 195:     ASSERT(op->ov_magic == MAGIC);      /* make sure it was in use */
 196: #else
 197:     if (op->ov_magic != MAGIC)
 198:         return;             /* sanity */
 199: #endif
 200: #ifdef RCHECK
 201:     ASSERT(op->ov_rmagic == RMAGIC);
 202:     if (op->ov_index <= 13)
 203:         ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC);
 204: #endif
 205:     ASSERT(op->ov_index < NBUCKETS);
 206:     size = op->ov_index;
 207:     op->ov_next = nextf[size];
 208:     nextf[size] = op;
 209: #ifdef MSTATS
 210:     nmalloc[size]--;
 211: #endif
 212: }
 213: 
 214: /*
 215:  * When a program attempts "storage compaction" as mentioned in the
 216:  * old malloc man page, it realloc's an already freed block.  Usually
 217:  * this is the last block it freed; occasionally it might be farther
 218:  * back.  We have to search all the free lists for the block in order
 219:  * to determine its bucket: 1st we make one pass thru the lists
 220:  * checking only the first block in each; if that fails we search
 221:  * ``realloc_srchlen'' blocks in each list for a match (the variable
 222:  * is extern so the caller can modify it).  If that fails we just copy
 223:  * however many bytes was given to realloc() and hope it's not huge.
 224:  */
 225: int realloc_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
 226: 
 227: char *
 228: realloc(cp, nbytes)
 229:     char *cp;
 230:     unsigned nbytes;
 231: {
 232:     register u_int onb;
 233:     union overhead *op;
 234:     char *res;
 235:     register int i;
 236:     int was_alloced = 0;
 237: 
 238:     if (cp == NULL)
 239:         return (malloc(nbytes));
 240:     op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
 241:     if (op->ov_magic == MAGIC) {
 242:         was_alloced++;
 243:         i = op->ov_index;
 244:     } else {
 245:         /*
 246: 		 * Already free, doing "compaction".
 247: 		 *
 248: 		 * Search for the old block of memory on the
 249: 		 * free list.  First, check the most common
 250: 		 * case (last element free'd), then (this failing)
 251: 		 * the last ``realloc_srchlen'' items free'd.
 252: 		 * If all lookups fail, then assume the size of
 253: 		 * the memory block being realloc'd is the
 254: 		 * smallest possible.
 255: 		 */
 256:         if ((i = findbucket(op, 1)) < 0 &&
 257:             (i = findbucket(op, realloc_srchlen)) < 0)
 258:             i = 0;
 259:     }
 260:     onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
 261:     /* avoid the copy if same size block */
 262:     if (was_alloced &&
 263:         nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP)
 264:         return(cp);
 265:     if ((res = malloc(nbytes)) == NULL)
 266:         return (NULL);
 267:     if (cp != res)          /* common optimization */
 268:         bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
 269:     if (was_alloced)
 270:         free(cp);
 271:     return (res);
 272: }
 273: 
 274: /*
 275:  * Search ``srchlen'' elements of each free list for a block whose
 276:  * header starts at ``freep''.  If srchlen is -1 search the whole list.
 277:  * Return bucket number, or -1 if not found.
 278:  */
 279: static
 280: findbucket(freep, srchlen)
 281:     union overhead *freep;
 282:     int srchlen;
 283: {
 284:     register union overhead *p;
 285:     register int i, j;
 286: 
 287:     for (i = 0; i < NBUCKETS; i++) {
 288:         j = 0;
 289:         for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
 290:             if (p == freep)
 291:                 return (i);
 292:             j++;
 293:         }
 294:     }
 295:     return (-1);
 296: }
 297: 
 298: #ifdef MSTATS
 299: /*
 300:  * mstats - print out statistics about malloc
 301:  *
 302:  * Prints two lines of numbers, one showing the length of the free list
 303:  * for each size category, the second showing the number of mallocs -
 304:  * frees for each size category.
 305:  */
 306: mstats(s)
 307:     char *s;
 308: {
 309:     register int i, j;
 310:     register union overhead *p;
 311:     int totfree = 0,
 312:     totused = 0;
 313: 
 314:     fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
 315:     for (i = 0; i < NBUCKETS; i++) {
 316:         for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
 317:             ;
 318:         fprintf(stderr, " %d", j);
 319:         totfree += j * (1 << (i + 3));
 320:     }
 321:     fprintf(stderr, "\nused:\t");
 322:     for (i = 0; i < NBUCKETS; i++) {
 323:         fprintf(stderr, " %d", nmalloc[i]);
 324:         totused += nmalloc[i] * (1 << (i + 3));
 325:     }
 326:     fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
 327:         totused, totfree);
 328: }
 329: #endif

Defined functions

botch defined in line 74; used 1 times
  • in line 73
findbucket defined in line 279; used 2 times
free defined in line 185; used 1 times
malloc defined in line 86; used 2 times
morecore defined in line 137; used 1 times
mstats defined in line 306; never used
realloc defined in line 227; never used

Defined variables

nextf defined in line 60; used 10 times
realloc_srchlen defined in line 225; used 1 times
sccsid defined in line 2; never used

Defined union's

overhead defined in line 30; used 40 times

Defined macros

ASSERT defined in line 83; used 4 times
MAGIC defined in line 46; used 4 times
NBUCKETS defined in line 59; used 6 times
NULL defined in line 19; used 7 times
RMAGIC defined in line 47; used 4 times
RSLOP defined in line 51; used 5 times
ov_index defined in line 41; used 5 times
ov_magic defined in line 40; used 4 times
ov_rmagic defined in line 43; used 2 times
ov_size defined in line 42; used 2 times
Last modified: 1985-08-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1570
Valid CSS Valid XHTML 1.0 Strict